From 48f4b70556ef89574e3a63f44b087f0eea177cdc Mon Sep 17 00:00:00 2001 From: Tyler Stapler Date: Sat, 18 Apr 2026 13:31:49 -0700 Subject: [PATCH 1/8] docs: Add feature plan for stelekit-site Adds the implementation plan for the GitHub Pages site (Astro + Starlight), two-job CI pipeline, landing page content, demo page with graceful fallback, user docs, and developer docs. Includes three ADRs for site framework, CI architecture, and GitHub Pages deployment decisions. Co-Authored-By: Claude Sonnet 4.6 --- docs/tasks/TODO.md | 2 + docs/tasks/stelekit-site.md | 806 ++++++++++++++++++ .../decisions/ADR-001-astro-starlight.md | 52 ++ .../decisions/ADR-002-monorepo-two-job-ci.md | 48 ++ .../ADR-003-github-pages-nojekyll-coi.md | 47 + 5 files changed, 955 insertions(+) create mode 100644 docs/tasks/stelekit-site.md create mode 100644 project_plans/stelekit-documentation-and-branding/decisions/ADR-001-astro-starlight.md create mode 100644 project_plans/stelekit-documentation-and-branding/decisions/ADR-002-monorepo-two-job-ci.md create mode 100644 project_plans/stelekit-documentation-and-branding/decisions/ADR-003-github-pages-nojekyll-coi.md diff --git a/docs/tasks/TODO.md b/docs/tasks/TODO.md index cf7e81d2e..ab43d7f00 100644 --- a/docs/tasks/TODO.md +++ b/docs/tasks/TODO.md @@ -1,5 +1,7 @@ # Tasks +- [ ] SteleKit Site — Astro + Starlight GitHub Pages site with CI/CD pipeline, landing page, user docs, developer docs, and demo page; depends on browser-wasm-demo.md for demo embed (docs/tasks/stelekit-site.md) +- [ ] Browser Wasm Demo — migrate `js(IR)` to `wasmJs` + `CanvasBasedWindow`, rendering the real Compose UI in-browser via Skia canvas; switch SQLDelight to IN_MEMORY backend for demo (docs/tasks/browser-wasm-demo.md) - [ ] Recent Pages — per-graph visit history in left sidebar showing last 10 visited pages, persists across sessions (docs/tasks/recent-pages.md) - [ ] Copy / Cut / Paste Blocks — Ctrl+C/X/V block-tree clipboard with undo, external Markdown paste, and Ctrl+Shift+V block reference paste (docs/tasks/copy-cut-paste-blocks.md) - [ ] All Pages View — sortable table of every page with backlink counts, name filter, journal/page toggle, and multi-select bulk delete (docs/tasks/all-pages-view.md) diff --git a/docs/tasks/stelekit-site.md b/docs/tasks/stelekit-site.md new file mode 100644 index 000000000..807caf6ac --- /dev/null +++ b/docs/tasks/stelekit-site.md @@ -0,0 +1,806 @@ +# SteleKit Site + +**Status**: Planned +**Depends on**: `docs/tasks/browser-wasm-demo.md` (wasmJs migration must be complete before Story 4 — demo page — can be fully implemented; all other stories are independent) + +--- + +## Problem + +SteleKit has no public web presence. Developers who discover the repository see a bare directory listing. Potential users cannot try the app without cloning and building it locally. The project competes with Logseq for mindshare but is invisible on the web. + +This plan covers the GitHub Pages site, CI/CD pipeline, landing page, documentation, and demo page integration — everything except the wasmJs migration itself (planned in `docs/tasks/browser-wasm-demo.md`). + +--- + +## Architecture Summary + +``` +stelekit/ + kmp/ ← Kotlin source (unchanged) + site/ ← NEW: Astro + Starlight + src/ + pages/ + index.astro ← Landing page + demo.astro ← Demo wrapper (iframe) + content/ + docs/ + user/ ← User guide (5–6 pages) + developer/ ← Developer docs (3–4 pages) + public/ + .nojekyll ← Committed static file; never generated in CI + astro.config.mjs ← base: '/stelekit/' + package.json + .github/workflows/ + pages.yml ← NEW: two-job deploy workflow +``` + +**CI pipeline (pages.yml)**: +``` +push to main + └── build-demo (Gradle wasmJsBrowserDistribution, ~15–20 min) + └── build-site (npm ci + astro build, ~2 min) + └── deploy (actions/deploy-pages) +``` + +Site-only changes (`site/**`) skip `build-demo` via `paths` filters and reuse the last successful demo artifact. + +**Key decisions** (see ADRs in `project_plans/stelekit-documentation-and-branding/decisions/`): +- ADR-001: Astro + Starlight over Docusaurus/VitePress/MkDocs +- ADR-002: Monorepo two-job CI over separate site repo +- ADR-003: GitHub Pages + `.nojekyll` + `coi-serviceworker` + +--- + +## Dependency Visualization + +``` +Story 1: Site Scaffolding (Astro + Starlight) + | + +── Story 2: CI/CD Pipeline (pages.yml) + | | + | +── Story 3: Landing Page Content + | | + | +── Story 5: User Documentation + | | + | +── Story 6: Developer Documentation + | + +── Story 4: Demo Page + | + depends on: browser-wasm-demo.md (Phase A complete) + degrades gracefully if artifact not yet available +``` + +Stories 1–2 are the critical path. Stories 3, 5, 6 can proceed in parallel once Story 1 is complete. Story 4 can be scaffolded in Story 1 and filled in after `browser-wasm-demo.md` ships. + +--- + +## Story 1: Site Scaffolding + +**Goal**: A runnable Astro + Starlight project in `site/` with correct base path configuration, `.nojekyll`, and a placeholder home page. + +### Task 1.1 — Bootstrap Astro + Starlight in `site/` + +**Objective**: Create the `site/` directory with a working Astro + Starlight install. + +**Context boundary**: Files created or modified are entirely within `site/`. No Kotlin or Gradle files are touched. + +**Prerequisites**: Node 20+, npm. + +**Implementation approach**: + +```bash +cd /path/to/stelekit +npm create astro@latest site -- --template starlight --no-install +cd site && npm install +``` + +The Starlight template creates: +``` +site/ + src/ + content/ + docs/ + index.mdx ← replace with our landing page stub + astro.config.mjs + package.json + tsconfig.json +``` + +Starlight's default layout uses `src/content/docs/` for all documentation pages. The marketing landing page (`index.astro`) lives in `src/pages/` and overrides the default docs index route. + +**Validation strategy**: +- `npm run dev` in `site/` serves the project at `localhost:4321` +- Landing page loads at `/` during dev (will be `/stelekit/` in production) +- No build errors in `npm run build` + +**INVEST check**: Self-contained; no Kotlin knowledge required; deliverable is a committed `site/` directory. + +--- + +### Task 1.2 — Configure `astro.config.mjs` for GitHub Pages subpath + +**Objective**: Set `base: '/stelekit/'` and `site: 'https://tstapler.github.io'` so all asset references resolve correctly on GitHub Pages. + +**Context boundary**: `site/astro.config.mjs` only. + +**Prerequisites**: Task 1.1 complete. + +**Implementation approach**: + +```js +// site/astro.config.mjs +import { defineConfig } from 'astro/config'; +import starlight from '@astrojs/starlight'; + +export default defineConfig({ + site: 'https://tstapler.github.io', + base: '/stelekit', + integrations: [ + starlight({ + title: 'SteleKit', + description: 'A local-first outliner for Desktop and Android. Reads your Logseq markdown.', + social: { + github: 'https://github.com/tstapler/stelekit', + }, + sidebar: [ + { + label: 'User Guide', + items: [ + { label: 'Getting Started', slug: 'user/getting-started' }, + { label: 'Outliner', slug: 'user/outliner' }, + { label: 'Journals', slug: 'user/journals' }, + { label: 'Backlinks', slug: 'user/backlinks' }, + { label: 'Search', slug: 'user/search' }, + ], + }, + { + label: 'Developer', + items: [ + { label: 'Architecture', slug: 'developer/architecture' }, + { label: 'Build', slug: 'developer/build' }, + { label: 'Contributing', slug: 'developer/contributing' }, + { label: 'Module Structure', slug: 'developer/module-structure' }, + ], + }, + ], + }), + ], +}); +``` + +Note: Astro `base` must not have a trailing slash in the config; Astro adds the slash when generating URLs. + +**Validation strategy**: +- `npm run build` in `site/` produces `dist/` with all paths prefixed `/stelekit/` +- `grep -r "href=\"/" site/dist/ | grep -v "/stelekit/"` returns no results (no unpatched absolute paths) +- Serve locally with `npx serve -p 3000 site/dist` and verify `http://localhost:3000/stelekit/` loads + +**INVEST check**: Single file change; independently reviewable. + +--- + +### Task 1.3 — Add `site/public/.nojekyll` + +**Objective**: Commit `.nojekyll` as a static file so Jekyll is never run on the GitHub Pages deployment. + +**Context boundary**: Create `site/public/.nojekyll` as an empty file. + +**Prerequisites**: `site/` directory exists (Task 1.1). + +**Implementation approach**: Create the file: + +```bash +touch site/public/.nojekyll +``` + +Commit it. The file has no content. Astro copies all `public/` files verbatim to `dist/`, so `.nojekyll` will always be present at the root of every deployed artifact. + +**Why committed, not generated**: If this file were created in a CI step (`touch site/public/.nojekyll`), it could be omitted in a manual deploy or a tooling change. Committing it makes it structurally impossible to forget. + +**Validation strategy**: After `npm run build`, confirm `ls site/dist/.nojekyll` exists. + +**INVEST check**: Trivial; wrong approach (CI-generated) has a documented failure mode that makes committed approach clearly superior. + +--- + +### Task 1.4 — Add placeholder `src/pages/index.astro` + +**Objective**: Replace the default Starlight index page with a custom `.astro` landing page stub so the marketing page route is established. + +**Context boundary**: `site/src/pages/index.astro`. + +**Prerequisites**: Tasks 1.1–1.2 complete. + +**Implementation approach**: + +```astro +--- +// site/src/pages/index.astro +import BaseHead from '../components/BaseHead.astro'; +--- + + + + + + +

SteleKit

+

Your knowledge, carved in stone.

+

Try in Browser | Documentation

+ + +``` + +This is a stub. Full landing page content is in Story 3. + +**Validation strategy**: `npm run build` succeeds; `site/dist/index.html` exists and contains "SteleKit". + +**INVEST check**: Isolated; does not touch documentation content. + +--- + +## Story 2: CI/CD Pipeline + +**Goal**: A working `pages.yml` workflow that builds the demo (Gradle) and site (Astro) and deploys to GitHub Pages on push to `main`. + +### Task 2.1 — Create `.github/workflows/pages.yml` + +**Objective**: Implement the two-job CI pipeline with path-filtered triggers, Gradle caching, Node caching, and `actions/deploy-pages`. + +**Context boundary**: `.github/workflows/pages.yml` (new file). + +**Prerequisites**: Story 1 complete; wasmJs Gradle target exists (from `browser-wasm-demo.md`). If the wasmJs target is not yet available, use a placeholder `build-demo` job that creates an empty `site/public/demo/` directory so the site pipeline can be validated independently. + +**Implementation approach**: + +```yaml +name: Deploy to GitHub Pages + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build-demo: + runs-on: ubuntu-latest + # Only rebuild Wasm when app code changes; site-only edits skip this job + if: | + github.event_name == 'workflow_dispatch' || + contains(toJSON(github.event.head_commit.modified), 'kmp/') || + contains(toJSON(github.event.head_commit.added), 'kmp/') + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + - uses: gradle/actions/setup-gradle@v4 + with: + cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + - name: Build wasmJs demo + run: ./gradlew :kmp:wasmJsBrowserDistribution --no-daemon --build-cache -PenableJs=true + - name: Assert expected output exists + run: test -d kmp/build/dist/wasmJs/productionExecutable/ + - name: Assert no single file exceeds 90 MB + run: | + find kmp/build/dist/wasmJs/productionExecutable -type f -size +90M \ + -exec echo "FILE TOO LARGE: {}" \; | grep . && exit 1 || true + - uses: actions/upload-artifact@v4 + with: + name: demo-dist + path: kmp/build/dist/wasmJs/productionExecutable/ + retention-days: 7 + + build-site: + runs-on: ubuntu-latest + needs: build-demo + if: always() && (needs.build-demo.result == 'success' || needs.build-demo.result == 'skipped') + steps: + - uses: actions/checkout@v4 + - name: Download demo artifact (if available) + uses: actions/download-artifact@v4 + continue-on-error: true + with: + name: demo-dist + path: site/public/demo/ + - uses: actions/configure-pages@v5 + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: npm + cache-dependency-path: site/package-lock.json + - run: npm ci + working-directory: site + - run: npm run build + working-directory: site + env: + # Expose demo availability to Astro build for conditional rendering + DEMO_AVAILABLE: ${{ steps.download-demo.outcome == 'success' }} + - uses: actions/upload-pages-artifact@v3 + with: + path: site/dist/ + + deploy: + runs-on: ubuntu-latest + needs: build-site + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 +``` + +Key decisions in this implementation: +- `build-demo` only runs when `kmp/` files changed or on manual dispatch; this prevents the 15–20 min Gradle build from running on every docs edit. +- `build-site` uses `if: always() && ...needs.build-demo.result == 'skipped'` so site-only changes still deploy. +- `continue-on-error: true` on the artifact download lets the site build proceed even when no demo artifact was produced (before `browser-wasm-demo.md` ships); the demo page degrades gracefully. +- `DEMO_AVAILABLE` environment variable allows the Astro build to render a fallback screenshot on the demo page when no artifact is present. +- `concurrency: group: pages` prevents concurrent Pages deploys. + +**Validation strategy**: +- Push a change to `kmp/` — verify `build-demo` runs and uploads artifact. +- Push a change to `site/src/` only — verify `build-demo` is skipped but `build-site` + `deploy` run. +- Verify deployment URL is `https://tstapler.github.io/stelekit/`. +- Verify `_astro/` assets are served (`.nojekyll` working). + +**INVEST check**: Can be implemented before demo is ready; path filter strategy is testable independently of Gradle. + +--- + +### Task 2.2 — Enable GitHub Pages in repository settings + +**Objective**: Configure the `stelekit` GitHub repository to use GitHub Actions as the Pages source. + +**Context boundary**: Repository settings (manual step; not automated). + +**Prerequisites**: Task 2.1 committed and pushed. + +**Implementation approach** (manual, one-time): +1. Navigate to `https://github.com/tstapler/stelekit/settings/pages`. +2. Under "Source", select **GitHub Actions**. +3. Do not configure a custom domain (use `tstapler.github.io/stelekit/` for now). +4. Create the `github-pages` deployment environment if it does not exist (`Settings > Environments > New environment`). + +**Validation strategy**: After the first successful `pages.yml` run, `https://tstapler.github.io/stelekit/` responds with `200 OK` and serves the landing page. + +**INVEST check**: One-time operation; no code changes. + +--- + +## Story 3: Landing Page Content + +**Goal**: A complete, publication-ready landing page at `site/src/pages/index.astro` that addresses all three audiences within two clicks. + +### Task 3.1 — Implement landing page sections + +**Objective**: Build the full landing page: hero, platform matrix, feature cards, Logseq comparison table, quick start, dual audience links. + +**Context boundary**: `site/src/pages/index.astro` and any extracted component files in `site/src/components/landing/`. + +**Prerequisites**: Task 1.2 (base path), Task 1.4 (placeholder page exists). + +**Implementation approach**: + +The landing page is a single `.astro` page. Sections in order: + +**Section 1 — Hero** + +``` +Your knowledge, carved in stone. + +A local-first outliner for Desktop and Android. +Reads your existing Logseq markdown. No install required to try. + +[Try in Browser] [Download] +``` + +- "Try in Browser" links to `/stelekit/demo/` +- "Download" links to the GitHub Releases page + +**Section 2 — Platform matrix** + +| Platform | Status | +|---|---| +| Desktop (macOS, Linux, Windows) | Working | +| Android | Working | +| Web (Browser Demo) | Demo available | +| iOS | Planned | + +**Section 3 — Feature cards** (5 cards with icon + headline + 1-sentence description): +1. Outliner — Hierarchical block editing with keyboard-driven nesting +2. Journals — Daily notes auto-created at app startup +3. Bidirectional links — `[[page]]` links indexed in real time; backlinks panel always visible +4. Search — Full-text search across all pages and blocks +5. Local-first — Your files stay on your machine; plain Markdown, always + +**Section 4 — Logseq comparison table** + +| | SteleKit | Logseq | +|---|---|---| +| File format | Markdown (Logseq-compatible) | Markdown | +| Browser demo | Yes — no install | Server-required | +| Desktop | Yes | Yes | +| Android | Yes | Yes | +| iOS | Planned | Yes | +| Open source | Yes (Elastic 2.0) | Yes (AGPL) | +| KMP architecture | Yes | No | + +**Section 5 — Quick start** + +```bash +git clone https://github.com/tstapler/stelekit +./gradlew run +``` + +**Section 6 — Audience links** (row of three cards) +- "User Guide" → `/stelekit/docs/user/getting-started/` +- "Developer Docs" → `/stelekit/docs/developer/architecture/` +- "Contribute" → `/stelekit/docs/developer/contributing/` + +**Voice rules** (from branding-readme.md): +- No adverbs ("seamlessly", "effortlessly", "simply") +- No marketing filler ("powerful", "robust", "cutting-edge") +- Sentences under 15 words +- Active voice + +**Validation strategy**: +- Page loads at `http://localhost:3000/stelekit/` in local serve +- All six sections visible on desktop and mobile viewport +- "Try in Browser" and "Download" links resolve correctly +- No broken links in the audience row + +**INVEST check**: Content-only; no Wasm or CI dependency; can be written and reviewed as a standalone change. + +--- + +## Story 4: Demo Page + +**Goal**: A demo page at `/demo/` that embeds the Compose Wasm canvas, degrades gracefully when the artifact is not available, and guides users on what to try. + +**Depends on**: `browser-wasm-demo.md` Phase A complete (wasmJs + `CanvasBasedWindow` + demo graph seeded). Can be scaffolded before this dependency ships. + +### Task 4.1 — Scaffold demo page with graceful fallback + +**Objective**: Create `site/src/pages/demo.astro` that renders the demo canvas when the artifact is present and shows a screenshot gallery when it is not. + +**Context boundary**: `site/src/pages/demo.astro`. + +**Prerequisites**: Story 1 (site scaffolding), Task 2.1 (`DEMO_AVAILABLE` env var plumbing). + +**Implementation approach**: + +```astro +--- +// site/src/pages/demo.astro +const demoAvailable = import.meta.env.DEMO_AVAILABLE === 'true'; +--- + + + + + SteleKit — Try in Browser + + + +
+

SteleKit in Your Browser

+
+

What to try

+
    +
  • Open the journal entry and edit a block — click to focus, Enter to add below, Tab to indent
  • +
  • Type [[Getting Started]] to create a wiki link
  • +
  • Navigate to Getting Started and look for the Backlinks panel
  • +
  • Press Cmd/Ctrl+K to open search
  • +
+

The demo runs entirely in your browser. No data leaves your device.

+

Requires Chrome 119+, Firefox 120+, or Safari 18.2+.

+
+ {demoAvailable ? ( +