You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
vibed/quotesdb/docs/plans/dreamy-marinating-corbato.md

17 KiB

quotesdb Implementation Dispatch Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Commit all pending triage work, advance ec118c to in_progress, then dispatch parallel domain orchestrators to implement all 69 open implementation tickets.

Architecture: A sequential foundation agent resolves shared-file conflicts first (Cargo.toml touched by both API and UI setup tickets). Then 3 parallel domain orchestrators — API+QA, UI, Infra — each pick up tickets via nbd ready --json, create per-ticket git worktrees, dispatch domain-expert sub-agents, validate, merge, and loop.

Tech Stack: Rust/Axum/Tokio (API), Yew/Trunk/Wasm (UI), OpenTofu/Cloudflare (Infra), reqwest/tokio-test (QA), nbd (ticket tracking), git worktrees (agent isolation)

Critical files:

  • quotesdb/Cargo.toml — single crate, shared by API + UI; modified by foundation tickets only
  • quotesdb/.nbd/tickets/ — per-ticket markdown files; no cross-ticket conflicts
  • quotesdb/docs/ARCHITECTURE.md — already updated with WASM dep versions
  • quotesdb/api/openapi.yaml — OpenAPI spec (source of truth, do not generate)

Task 1: Commit all pending changes

Run from: /run/media/pop/4e1ca4f1-37f1-4bd3-bad2-603166a773db/Projects/src/gitea.elijah.run/vibed/worktrees/quotesdb/ (the worktree git root, one level above quotesdb/)

What is in the working tree:

  • 80 modified/untracked files: mostly nbd ticket updates (triage resolutions, new implementation tickets, XML tag additions from previous session)
  • quotesdb/CLAUDE.md — updated
  • quotesdb/docs/ARCHITECTURE.md — updated with WASM dependency version table
  • flake.lock — updated

Step 1: Stage all changes

git add quotesdb/.nbd/tickets/ \
        quotesdb/CLAUDE.md \
        quotesdb/docs/ARCHITECTURE.md \
        flake.lock

Step 2: Verify staged files look right

git status
git diff --cached --stat

Step 3: Commit

git commit -m "$(cat <<'EOF'
chore(quotesdb): resolve all triage tickets and create implementation tickets

- All 21 TRIAGE decision tickets resolved with chosen approaches documented
- This session: e2bd9b (SPA routing → _redirects), 2ec8b1 (OpenAPI → build.rs),
  0d84fa (HTTP client → reqwest), 0bc655 (auth code → session storage)
- New implementation tickets created: 9ef703, 8892d5, 5379eb
- Downstream tickets updated with resolved approaches and correct dependencies
- ARCHITECTURE.md updated with pinned WASM dependency versions (yew 0.22,
  yew-router 0.19, wasm-bindgen 0.2)
- XML tags added to all tickets for improved LLM guidance

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
EOF
)"

Task 2: Update root ticket ec118c to in_progress

Run from: quotesdb/ directory

Phase 0 (design) and Phase 1 (planning / ticket creation) are both complete. All 21 triages are resolved. Moving to Phase 2 (implementation).

nbd update ec118c --status in_progress --json | jq '{id, status}'

Expected output:

{ "id": "ec118c", "status": "in_progress" }

Task 3: Foundation agent — shared Cargo.toml setup (sequential)

Why sequential: Tickets 1f5bb5, 93515e, and 8892d5 all write to Cargo.toml. Running them in parallel would cause merge conflicts. This one-shot foundation agent does them in order before parallel agents start.

Dispatch a single general-purpose agent with this prompt:

You are a senior Rust engineer setting up the foundation of the quotesdb project — a single Cargo crate with api and ui binaries.

Working directory: quotesdb/ inside the worktree at /run/media/pop/4e1ca4f1-37f1-4bd3-bad2-603166a773db/Projects/src/gitea.elijah.run/vibed/worktrees/quotesdb/

Task tracking: Always run nbd from quotesdb/. Use nbd update <id> --status in_progress --json before starting a ticket, nbd update <id> --status done --json when finished.

Worktree convention (per ticket):

git worktree add .claude/worktrees/quotesdb-shared-<id> -b quotesdb/shared/<id>
# do all work inside quotesdb/ root within the worktree
cargo fmt && cargo check && cargo clippy && cargo test
git checkout quotesdb
git merge quotesdb/shared/<id>
git worktree remove .claude/worktrees/quotesdb-shared-<id>

Do these 4 tickets in order — do not start the next until the previous is merged:

  1. 7a0d9f — Implement generate_id() in src/lib.rs (UUID v4, WASM-compatible). Read the ticket first: nbd read 7a0d9f --json. Validation: cargo check. Branch: quotesdb/shared/7a0d9f.

  2. 1f5bb5 — Set up Cargo.toml with all crate dependencies (axum, tokio, workers-rs, rusqlite, uuid, rand, serde, getrandom, plus [build-dependencies] serde_json + serde_yaml). Read: nbd read 1f5bb5 --json. Validation: cargo check. Branch: quotesdb/shared/1f5bb5.

  3. 93515e — Add Yew/Wasm UI dependencies to Cargo.toml (yew 0.22, yew-router 0.19, wasm-bindgen, gloo, web-sys). Read: nbd read 93515e --json. Validation: cargo check. Branch: quotesdb/shared/93515e.

  4. 8892d5 — Create build.rs that converts api/openapi.yaml to JSON at compile time (writes to $OUT_DIR/openapi.json). Read: nbd read 8892d5 --json. Validation: cargo check (confirms build.rs runs). Branch: quotesdb/shared/8892d5.

After all 4 are merged, run cargo fmt && cargo check && cargo clippy && cargo test from quotesdb/ to confirm the foundation is clean.

Return: which tickets were completed, the final cargo check output, and any issues encountered.

Proceed to Task 4 only after this agent returns successfully.


Task 4: Dispatch 3 parallel domain orchestrators

Invoke all 3 agents in a single message (parallel). Each orchestrator runs nbd ready --json, filters to its domain, picks the highest-priority unblocked ticket, works it in a worktree, merges, and loops until its domain's sub-project ticket can be closed.


Orchestrator A: API + QA

Domain: src/bin/api/, src/lib.rs (non-Cargo parts), tests/ Sub-project ticket: f3dc74 (quotesdb/api), ce1e4f (quotesdb/qa) Worktree prefix: quotesdb/api/<id> and quotesdb/qa/<id>

Ready tickets to start with (priority order):

  • 00aff0 — QuoteRepository trait + cfg-split D1/rusqlite implementations
  • 5f5ba0 — Add integration test dev-dependencies (reqwest, tokio, tempfile, serde_json)
  • a5049d — DB connection module + SQLx migrations (after 00aff0)
  • 9c9546.env.example documenting DATABASE_URL
  • af56a7docs/LOCAL_DEV.md quickstart guide
  • 6e829e — API server main.rs (router setup, Axum app)
  • 28e7d9 — GET /api/ handler (serves compiled openapi.json)
  • a6bce1 — GET /api/quotes (list, pagination, filters)
  • 1a274d — GET /api/quotes/random
  • b20b5a — GET /api/quotes/:id
  • 05f8ae — PUT /api/quotes (create)
  • 2c5a57 — Auth middleware (X-Auth-Code header validation)
  • 5f1112 — POST /api/quotes/:id (update)
  • 5cdbd9 — DELETE /api/quotes/:id
  • Then QA tickets: 9b581f, 789d0f, aa0eab, 93f1b6, f9f448, 4a4c26, fae330, 8c87db, 893eba, e8f5cf

Agent prompt:

You are a senior Rust backend engineer implementing the quotesdb API (Axum + Tokio) and its integration test suite.

Working directory: Always work from quotesdb/ at /run/media/pop/4e1ca4f1-37f1-4bd3-bad2-603166a773db/Projects/src/gitea.elijah.run/vibed/worktrees/quotesdb/quotesdb/

Your domains: src/bin/api/, src/lib.rs (non-Cargo parts), tests/

Ticket tracking: nbd commands always from quotesdb/. Mark in_progress before starting, done after merging.

Worktree loop (repeat until f3dc74 and ce1e4f can close):

  1. nbd ready --json | jq '[.[] | select(.title | test("api|lib|test|DB|QuoteRepo|router|handler|migration|local|env|auth|GET|PUT|POST|DELETE|random|list|quotes|Test suite|integration"; "i"))]'
  2. Pick highest priority unblocked ticket. Read it: nbd read <id> --json
  3. Create worktree: git worktree add .claude/worktrees/quotesdb-api-<id> -b quotesdb/api/<id>
  4. Dispatch a Bash sub-agent to implement the ticket inside quotesdb/ within the worktree
  5. Validate: cargo fmt && cargo check && cargo clippy && cargo test
  6. Merge: git checkout quotesdb && git merge quotesdb/api/<id>
  7. Remove: git worktree remove .claude/worktrees/quotesdb-api-<id>
  8. Mark ticket done: nbd update <id> --status done --json
  9. Loop

Key architectural facts:

  • API target is Cloudflare Workers (wasm32) in prod; native Axum/Tokio for local dev and tests
  • DB layer uses QuoteRepository trait with two impls: D1Repository (wasm32) and RusqliteRepository (native)
  • Auth: X-Auth-Code header, stored plaintext in quotes.auth_code, 403 on mismatch
  • IDs: UUID v4 via generate_id() in src/lib.rs (done in foundation phase)
  • Auth codes: 4-word passphrase, generated via rand 0.10 with OsRng
  • Router order: GET /api/quotes/random MUST be registered before GET /api/quotes/:id
  • OpenAPI spec: served via include_str!(concat!(env!("OUT_DIR"), "/openapi.json")) (done in foundation)

Validation before closing any ticket:

cargo fmt && cargo check && cargo clippy && cargo test

Close f3dc74 when all API tickets are done. Close ce1e4f when all QA tickets are done.

Return a summary: tickets completed, any blockers encountered, final test run output.


Orchestrator B: UI

Domain: src/bin/ui/, index.html, Trunk.toml, _redirects Sub-project ticket: c3503b (quotesdb/ui) Worktree prefix: quotesdb/ui/<id>

Ready tickets to start with (priority order):

  • 9ef703 — Create _redirects file + add Trunk copy-file directive to index.html
  • 00d6d7 — Add Trunk proxy [[proxy]] block for /api/*localhost:3000
  • 5379eb — Auth code session storage utility (src/bin/ui/storage.rs) + AuthModal pre-fill
  • dc3d2bTrunk.toml + index.html final setup (depends on 9ef703)
  • 04f865 — Yew app shell, BrowserRouter, route definitions for 5 pages
  • 0fbdd5src/bin/ui/style.css full stylesheet (BEM naming)
  • bb1514 — CSS content implementation
  • Page components: HomPage, BrowsePage, QuotePage, AuthorPage, SubmitPage
  • f850c6 — AuthModal component
  • fc2f51 — Error display component
  • 00d6d7 — Pagination component
  • CI/CD: 5137d7 (deploy-ui workflow)
  • Docs: 372790

Agent prompt:

You are a senior Rust frontend engineer implementing the quotesdb UI (Yew + Wasm compiled by Trunk, hosted on Cloudflare Pages).

Working directory: Always work from quotesdb/ at /run/media/pop/4e1ca4f1-37f1-4bd3-bad2-603166a773db/Projects/src/gitea.elijah.run/vibed/worktrees/quotesdb/quotesdb/

Your domains: src/bin/ui/, index.html, Trunk.toml, _redirects, src/bin/ui/style.css

Ticket tracking: nbd from quotesdb/. Mark in_progress before starting, done after merging.

Worktree loop (repeat until c3503b can close):

  1. nbd ready --json | jq '[.[] | select(.title | test("ui|Trunk|Yew|CSS|style|page|component|modal|redirect|auth|BrowserRouter|browse|submit|author|home|wasm|SPA"; "i"))]'
  2. Pick highest priority. Read: nbd read <id> --json
  3. Create worktree: git worktree add .claude/worktrees/quotesdb-ui-<id> -b quotesdb/ui/<id>
  4. Implement inside quotesdb/ within the worktree
  5. Validate: trunk build (from quotesdb/ root)
  6. Merge + mark done, loop

Key architectural facts:

  • Compile target: wasm32-unknown-unknown. No std::thread, std::fs, or threading primitives.
  • Yew 0.22 + yew-router 0.19 (only correct compatible versions).
  • API calls via gloo::net::http::Request (not reqwest — incompatible with wasm32).
  • Auth code storage: sessionStorage via web_sys::window().session_storage() (NOT localStorage). Key pattern: auth_code_{quote_id}.
  • _redirects file content: /* /index.html 200 — must be at project root, copied to dist/ by Trunk.
  • CSS: plain CSS, BEM naming (quote-card, quote-card__text, page-browse). No Tailwind.
  • Trunk proxy: [[proxy]] rewrite = "/api" backend = "http://localhost:3000" — local dev only.
  • In production, Cloudflare routes /api/* to the Worker before Pages sees the request.

Frontend routes (5 pages):

  • / → Home (random quote + Browse link)
  • /browse → Paginated list + author/tag filters
  • /quotes/:id → View/edit/delete single quote
  • /author/:name → All quotes by author
  • /submit → New quote form

Validation before closing any ticket:

trunk build

Close c3503b when all UI tickets are done.

Return a summary: tickets completed, any blockers, final trunk build output.


Orchestrator C: Infra

Domain: infra/, .gitea/workflows/ Sub-project ticket: 25c413 (quotesdb/infra) Worktree prefix: quotesdb/infra/<id>

Ready tickets to start with (priority order):

  • 2d1371 — Bootstrap OpenTofu project (providers.tf, terraform.tf, infra/.gitignore)
  • Then: D1 database resource, Cloudflare Worker resource, Pages project, domain/routes, variables
  • CI/CD: 57fe5e (deploy-api workflow), 3781c9 (deploy-ui workflow listed under infra)
  • Docs: d5839a (infra README)

Agent prompt:

You are a DevOps/infrastructure engineer provisioning the quotesdb Cloudflare infrastructure with OpenTofu.

Working directory: infra/ at /run/media/pop/4e1ca4f1-37f1-4bd3-bad2-603166a773db/Projects/src/gitea.elijah.run/vibed/worktrees/quotesdb/quotesdb/infra/

Your domains: infra/ (all .tf files), .gitea/workflows/ (CI/CD YAML files)

Ticket tracking: nbd from quotesdb/. Mark in_progress before starting, done after merging.

Worktree loop (repeat until 25c413 can close):

  1. nbd ready --json | jq '[.[] | select(.title | test("infra|OpenTofu|tofu|Cloudflare|Worker|D1|Pages|provider|deploy|workflow|gitea|action|migration|wrangler|domain"; "i"))]'
  2. Pick highest priority. Read: nbd read <id> --json
  3. Create worktree: git worktree add .claude/worktrees/quotesdb-infra-<id> -b quotesdb/infra/<id>
  4. Implement. Validate from infra/: tofu validate && tofu plan
  5. Merge + mark done, loop

Key architectural facts:

  • OpenTofu state backend: local file (terraform.tfstate), gitignored.
  • Resource for the Worker: cloudflare_workers_script (check resolved triage efee79 for the exact resource name in the current provider version).
  • D1 binding: chicken-and-egg resolved in triage 07cafb — create D1 first (tofu apply -target), then bind its ID to the Worker.
  • Pages project: direct upload (no git source block). Deploy via wrangler pages deploy dist/.
  • D1 migrations: separate wrangler d1 execute step, not in OpenTofu (resolved in triage 5c0c64).
  • Every resource and data block must have a comment explaining its purpose.
  • Do NOT commit .terraform/, *.tfstate, *.tfstate.backup, or .terraform.lock.hcl.

Validation before closing any ticket (from infra/):

tofu validate
tofu plan

Close 25c413 when all infra tickets are done.

Return a summary: tickets completed, tofu plan output summary, any blockers.


Execution Notes

Ordering

Task 1 (commit) → Task 2 (ec118c update) → Task 3 (foundation agent)
                                                         ↓
                                          Task 4: 3 parallel orchestrators
                                          (single message, 3 Task tool calls)

Coordination between orchestrators

Concern Resolution
Cargo.toml conflicts Foundation agent handles all Cargo.toml tickets first
.nbd/tickets/ conflicts Each ticket is a separate file — no cross-agent conflicts
src/lib.rs Foundation agent owns this; orchestrators only add to src/bin/
UI calling API UI uses API endpoint paths (not shared code) — no conflict
QA calling API QA tests against a running API server in tests — no shared files

When orchestrators finish

After all 3 return:

  1. Run full validation from quotesdb/: cargo fmt && cargo check && cargo clippy && cargo test
  2. Run trunk build to verify UI
  3. Run nbd list --json | jq '[.[] | select(.status != "done")]' — should be empty or near-empty
  4. Close sub-project tickets: f3dc74, c3503b, 25c413, ce1e4f
  5. Close root ticket: nbd update ec118c --status done --json
  6. Use superpowers:finishing-a-development-branch to merge quotesdb branch into main

Ticket filtering tips for orchestrators

# Find the next unblocked ticket in your domain
nbd ready --json | jq 'sort_by(-.priority) | .[0] | {id, priority, title}'

# Check if a sub-project ticket can now close (all deps done)
nbd read f3dc74 --json | jq '.dependencies'
# Then for each dep: nbd read <id> --json | jq .status