Internal Document Space Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Stand up a brand-styled, access-controlled internal document space at board.cloudbase.foundation (gated) and public.cloudbase.foundation (open), backed by the documents repo (Eleventy + PagesCMS) plus a Google Shared Drive for living files.

Architecture: One documents repo is the single source of truth. Eleventy builds it twice — the full site to board.* (gated by Cloudflare Access → board@ group) and the public/ subtree to public.* (ungated). Routine docs are Markdown rendered through one shared brand theme (lifted from the existing embedded CSS); showcase docs stay bespoke standalone HTML (passed through verbatim). Living/financial files live in a Google Shared Drive that internal index pages link to — no API integration.

Tech Stack: Eleventy (11ty) v3, Liquid layout (Markdown templating disabled for content), PagesCMS (.pages.yml), Cloudflare Pages (two projects), Cloudflare Access (Google Workspace IdP), Google Shared Drive.

Global Constraints


Task 1: Scaffold the Eleventy project

Files:

Interfaces:

{
  "name": "cbf-documents",
  "private": true,
  "scripts": {
    "build": "eleventy --config=eleventy.config.js",
    "build:public": "eleventy --config=eleventy.public.config.js",
    "serve": "eleventy --config=eleventy.config.js --serve"
  },
  "devDependencies": {
    "@11ty/eleventy": "^3.0.0"
  }
}
cd ~/cbf/documents && mkdir -p _includes public/files && touch _includes/.gitkeep public/files/.gitkeep
// Tier-safe Eleventy setup shared by BOTH builds. Nothing internal-only here —
// internal-only passthroughs belong in eleventy.config.js so they can't leak to public.
module.exports = function (eleventyConfig) {
  // Public uploads (PagesCMS media) — safe on both tiers.
  eleventyConfig.addPassthroughCopy("public/files");
  // The shared brand layout is enabled in Task 2 (base.liquid must exist first):
  // eleventyConfig.addGlobalData("layout", "base.liquid");
};
const shared = require("./eleventy.shared.js");

module.exports = function (eleventyConfig) {
  shared(eleventyConfig);
  // Showcase HTML docs carry their own <head>/<style> — copied verbatim. Internal ONLY.
  eleventyConfig.addPassthroughCopy("tech");

  return {
    dir: { input: ".", includes: "_includes", output: "_site" },
    markdownTemplateEngine: false, // content is pure Markdown; no brace landmines
    templateFormats: ["md"],
  };
};
node_modules
_site
_site-public
README.md
resumes
.temp

Append to the existing .gitignore:

# Node / Eleventy build
node_modules/
_site/
_site-public/
---
title: CBF Internal Documents
---

# Cloudbase Foundation — Internal Documents

Smoke-test page. Replaced by the real index in Task 5.

Run: cd ~/cbf/documents && npm install && npm run build Expected: install completes; build prints Wrote N files and exits 0.

Run: test -f _site/index.html && echo OK Expected: OK

Run: head -1 _site/tech/domain-map.html Expected: <!DOCTYPE html> (original doc at the same .html path, not pretty-URL'd or wrapped).

git add package.json package-lock.json eleventy.shared.js eleventy.config.js .eleventyignore .gitignore _includes/.gitkeep public/files/.gitkeep index.md
git commit -m "build: scaffold Eleventy site (internal build + tier-safe shared config)"

Task 2: Extract the brand theme into a shared layout

Files:

Interfaces:

The <style> body is lines 12–483 (excludes the <style>/</style> tags):

cd ~/cbf/documents
sed -n '12,483p' tech/domain-map.html > _includes/theme.css

Run: grep -c -- '--navy\|--gold\|--paper' _includes/theme.css Expected: a non-zero count.

Append to _includes/theme.css:

/* Doc-space additions — reuse existing brand tokens */
.callout {
  border-left: 4px solid var(--gold);
  background: var(--paper-soft);
  padding: 0.75rem 1rem;
  margin: 1.25rem 0;
  border-radius: 4px;
}
.callout strong { color: var(--navy); display: block; margin-bottom: 0.25rem; }
.doc-main { max-width: 60rem; margin: 0 auto; padding: 2.5rem 1.5rem; }
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ title }} — CBF</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@300;400;500;600;700&family=Newsreader:ital,opsz,wght@0,6..72,300;0,6..72,400;0,6..72,500;0,6..72,600;1,6..72,400&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
<style>{% include "theme.css" %}</style>
</head>
<body>
<main class="doc-main">
{{ content }}
</main>
</body>
</html>

Replace the commented line in eleventy.shared.js with the live line:

  eleventyConfig.addGlobalData("layout", "base.liquid");

(Front-matter layout: on any doc still overrides this.)

Run: npm run build && grep -c 'doc-main\|--navy' _site/index.html Expected: non-zero (the layout + inlined theme are present in the rendered Markdown page).

git add _includes/theme.css _includes/base.liquid eleventy.shared.js
git commit -m "feat: shared brand theme layout for Markdown docs"

Task 3: Branded inline components + reference doc

Components are inline HTML using the theme's existing classes (no Liquid shortcodes — see Global Constraints). markdown-it renders raw HTML by default, so editors drop a snippet straight into a doc.

Files:

Interfaces:

Run: grep -c 'class="pill"\|\.pill\b' _includes/theme.css && grep -c '\.callout' _includes/theme.css Expected: both non-zero (.pill from the extracted CSS, .callout from Task 2 Step 3).

---
title: Brand components for docs
---

# Brand components

Drop these snippets straight into any Markdown doc — they use the shared theme.

Status pill: <span class="pill live">Live</span> <span class="pill future">Planned</span>

Panel:

<div class="panel">A boxed, on-brand panel of content.</div>

Callout:

<div class="callout"><strong>Heads up</strong>An emphasized note.</div>

Run: npm run build && grep -o 'class="pill live"' _site/it/components/index.html Expected: class="pill live"

Run: grep -o 'class="callout"' _site/it/components/index.html Expected: class="callout"

git add it/components.md
git commit -m "docs: brand component reference (inline HTML snippets)"

Task 4: Create the public/ subtree and the public build

Files:

Interfaces:

cd ~/cbf/documents
mv foundational/toc.md public/theory-of-change.md

Then make the first lines of public/theory-of-change.md this front matter (board-approved 2026-06-25; ships public immediately):

---
title: Theory of Change
date: 2026-06-25
---
---
title: Cloudbase Foundation — Public Documents
---

# Cloudbase Foundation

Public documents for The Cloudbase Foundation, a 501(c)(3) nonprofit (EIN 27-1359927).

- [Theory of Change](/theory-of-change/)
- 501(c)(3) determination letter (coming soon)
const shared = require("./eleventy.shared.js");

module.exports = function (eleventyConfig) {
  shared(eleventyConfig); // tier-safe setup; deliberately NOT the internal config

  // Internal content dirs are excluded from the PUBLIC build.
  ["agendas", "it", "tech", "research", "projects", "resumes", "foundational"]
    .forEach((dir) => eleventyConfig.ignores.add(`${dir}/**`));
  eleventyConfig.ignores.add("index.md"); // the internal landing page

  return {
    dir: { input: ".", includes: "_includes", output: "_site-public" },
    markdownTemplateEngine: false,
    templateFormats: ["md"],
  };
};

Run: npm run build:public Expected: build exits 0, writes to _site-public/.

Run: test -f _site-public/theory-of-change/index.html && test -f _site-public/index.html && echo OK Expected: OK

Run: for d in it agendas tech research projects resumes foundational; do test -e _site-public/$d && echo "LEAK: $d"; done; echo "leak-check done" Expected: leak-check done with NO LEAK: lines.

git add public eleventy.public.config.js
git commit -m "feat: public/ subtree + public-only build (theory of change)"

Task 5: Wire existing content + internal index

Files:

Interfaces:

---
title: CBF Internal Documents
---

# Cloudbase Foundation — Internal Documents

Access-controlled to the `board@cloudbase.foundation` group.

## Reference
- [Domain & Subdomain Map](/tech/domain-map.html)
- [Roadmap](/tech/roadmap.html)
- [Brand components for docs](/it/components/)

## IT & operations
- [Internal Doc Space — Design](/it/2026-06-25-internal-doc-space-design/)
- [Internal Doc Space — Plan](/it/2026-06-25-internal-doc-space-plan/)
- [CRM rebrand finish plan](/it/2026-06-25-cloudbase-foundation-email-finish-plan/)
- [Finances & Filings](/it/finances/) — budgets & board packets (Google Drive)

Public documents are published at [public.cloudbase.foundation](https://public.cloudbase.foundation/).
---
title: Finances & Filings
---

# Finances & Filings

Living financial files are kept in the **CBF Internal** Google Shared Drive
(shared to `board@cloudbase.foundation`), not in this repo.

- Operating budgets (Google Sheets): _Drive link added in Task 11_
- Board meeting packets (PDF): _Drive link added in Task 11_
- Working financial statements: _Drive link added in Task 11_

Final, published filings (e.g. the 501(c)(3) determination letter) live on the
[public document site](https://public.cloudbase.foundation/).

Find Markdown files with no front-matter title (these would render with an empty <title>):

cd ~/cbf/documents
for f in $(find agendas it research projects -name '*.md'); do
  head -5 "$f" | grep -q '^title:' || echo "NEEDS TITLE: $f"
done

For each file printed, prepend a front-matter block using the doc's main heading text:

---
title: <human title>
---

Run: npm run build && grep -c 'Finances & Filings' _site/index.html Expected: non-zero.

Run:

for p in tech/domain-map.html tech/roadmap.html it/components/index.html \
         it/2026-06-25-internal-doc-space-design/index.html \
         it/2026-06-25-internal-doc-space-plan/index.html \
         it/2026-06-25-cloudbase-foundation-email-finish-plan/index.html \
         it/finances/index.html; do
  test -f "_site/$p" || echo "MISSING: $p"
done; echo "link-check done"

Expected: link-check done with NO MISSING: lines.

git add index.md it/finances.md agendas it research projects
git commit -m "content: internal index, finances hub, doc front matter"

Task 6: Rewrite .pages.yml for the real structure

Files:

Interfaces:

media:
  input: public/files
  output: /files

content:
  - name: agendas
    label: Board Agendas
    type: collection
    path: agendas
    filename: '{year}-{month}-{day}-{primary}.md'
    view:
      fields: [title, date]
    fields:
      - { name: title, label: Title, type: string }
      - { name: date, label: Meeting Date, type: date }
      - { name: body, label: Content, type: rich-text }

  - name: it
    label: IT & Operations
    type: collection
    path: it
    view:
      fields: [title, date]
    fields:
      - { name: title, label: Title, type: string }
      - { name: date, label: Date, type: date }
      - { name: body, label: Content, type: rich-text }

  - name: public_docs
    label: Public Documents
    type: collection
    path: public
    view:
      fields: [title, date]
    fields:
      - { name: title, label: Title, type: string }
      - { name: date, label: Date, type: date }
      - { name: body, label: Content, type: rich-text }

Run: cd ~/cbf/documents && python3 -c "import yaml; yaml.safe_load(open('.pages.yml')); print('valid')" Expected: valid

git add .pages.yml
git commit -m "chore: rewrite .pages.yml for the real repo structure"

Sign in to https://app.pagescms.org with GitHub, authorize the Cloudbase-Foundation/documents repo, open it, and confirm the agendas, it, and public_docs collections appear and one existing doc opens in the editor. Expected: collections load; a doc is editable. (No git artifact — visual verification.)


Task 7: Create the board@cloudbase.foundation Google group (Jonathan)

Files: none (Google Admin console).

Google Admin console → Directory → Groups → Create group:

Admin console → Groups → board@cloudbase.foundation → Members shows the expected people. Expected: group present, members listed. (Shared with the rebrand/audit workstreams — create once.)


Task 8: Two Cloudflare Pages projects (Jonathan; Claude verifies)

Files: none (Cloudflare dashboard).

Interfaces:

Cloudflare dashboard → Workers & Pages → Create → Pages → Connect to Git → Cloudbase-Foundation/documents:

Repeat with:

Each project's Deployments tab shows a green production build off main. Expected: both succeed.


Task 9: DNS for the two subdomains (Jonathan; Claude verifies)

Files: none (Cloudflare — the cloudbase.foundation zone).

In each Pages project → Custom domains → Set up a custom domain:

Cloudflare auto-creates the proxied CNAME records (the zone is on Cloudflare).

dig +short board.cloudbase.foundation
dig +short public.cloudbase.foundation

Expected: both return Cloudflare/Pages addresses (proxied), not NXDOMAIN.

Run: curl -sI https://public.cloudbase.foundation/theory-of-change/ | head -1 Expected: HTTP/2 200.


Task 10: Cloudflare Access on board.* (Jonathan; Claude verifies)

Files: none (Cloudflare Zero Trust).

Zero Trust dashboard → Settings → Authentication → Login methods. If Google Workspace isn't listed, add it (requires Workspace admin OAuth consent). Confirm a test login resolves group membership.

Zero Trust → Access → Applications → Add → Self-hosted:

Run: curl -sI https://board.cloudbase.foundation/ | head -1 Expected: a redirect to Access login (HTTP/2 302, location: to *.cloudflareaccess.com), NOT 200.

Run: curl -sI https://public.cloudbase.foundation/ | head -1 Expected: HTTP/2 200.

Open https://board.cloudbase.foundation/ as a board@ member → the internal index loads. As a non-member → access denied. Expected: member in, non-member blocked.


Task 11: Google Shared Drive + wire the finances hub (Jonathan + Claude)

Files:

Google Drive → Shared drives → New → CBF Internal. Subfolders: Budgets, Board Packets, Working Financials.

Shared drive → Manage members → add board@cloudbase.foundation as Content manager. Copy the shared-drive folder URL and the Budgets folder URL.

Swap each _Drive link added in Task 11_ for the real Drive URLs as Markdown links, e.g. [Operating budgets](https://drive.google.com/drive/folders/XXXX).

Run: npm run build && grep -c 'drive.google.com' _site/it/finances/index.html Expected: non-zero.

git add it/finances.md
git commit -m "content: wire finances hub to the CBF Internal shared drive"
curl -sI https://board.cloudbase.foundation/it/finances/ | head -1       # expect 302 (gated)
curl -sI https://public.cloudbase.foundation/theory-of-change/ | head -1 # expect 200

Expected: internal route gated, public route open. Then confirm (browser, as a board@ member) the finances page shows working Drive links.


Notes for the implementer

Self-review result