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.

464 lines
14 KiB
Markdown

+++
title = "quotesdb"
priority = 8
status = "todo"
ticket_type = "project"
dependencies = ["f3dc74", "c3503b", "ce1e4f", "25c413"]
+++
# QuotesDB Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
> **For Claude:** SUGGESTED SUB-SKILL: Use agent-development for agent dispatch
> **For Claude:** SUGGESTED SUB-SKILL: Use dispatching-parallel-agents for agent dispatch
> **For Claude:** SUGGESTED SUB-SKILL: Use subagent-driven-development for agent dispatch
> **For Claude:** SUGGESTED SUB-SKILL: Use verification-before-completion for verification
> **For Claude:** SUGGESTED SUB-SKILL: Use finishing-a-development-branch for verification
> **For Claude:** SUGGESTED SUB-SKILL: Use using-git-worktrees for parallel work
> **For Claude:** SUGGESTED SUB-SKILL: Use test-driven-development for development workflow
**Goal:** Bootstrap the `quotesdb` service (Rust/Axum backend on Cloudflare Workers + Yew frontend on Cloudflare Pages), then orchestrate parallel agents to plan and implement the work.
**Architecture:** Three-phase delivery: (0) design ✓, (1) 4 parallel planning agents ticket work in git worktrees, (2) 4 parallel implementation orchestrators dispatch sub-agents per ticket. Each subdomain (api, ui, tests, infra) lives in its own directory under `quotesdb/` as an independent Rust crate.
**Tech Stack:** Rust, Axum, Tokio, workers-rs, SQLx, Turso (local) / Cloudflare D1 (prod), Yew, Trunk, OpenTofu, Cloudflare Workers + Pages
---
## Context
A new `quotesdb` service is being added to the vibed mono-repo. The design was finalized in Phase 0. This plan covers:
0. **Task 0:** Create nbd project ticket `quotesdb` (stop after this — user will trigger the rest)
1. **Task 1:** Bootstrap directory structure and design doc
2. **Task 2:** Phase 1 — dispatch 4 parallel planning agents (each in a git worktree) to create nbd tickets
3. **Task 3:** Merge planning branches
4. **Task 4:** Phase 2 — dispatch 4 parallel implementation orchestrators
---
## Finalized Design (Phase 0 Output)
### Database Schema
```sql
CREATE TABLE quotes (
id TEXT PRIMARY KEY, -- NanoID (~21 chars)
text TEXT NOT NULL,
author TEXT NOT NULL,
source TEXT, -- optional: book, speech, etc.
date TEXT, -- optional: ISO date YYYY-MM-DD
auth_code TEXT NOT NULL, -- 4-word passphrase e.g. ocean-table-purple-storm
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE quote_tags (
quote_id TEXT NOT NULL REFERENCES quotes(id) ON DELETE CASCADE,
tag TEXT NOT NULL,
PRIMARY KEY (quote_id, tag)
);
```
### API Endpoints
| Method | Path | Description | Auth |
|--------|------|-------------|------|
| GET | `/api/` | OpenAPI spec (JSON) | None |
| GET | `/api/quotes` | List quotes, 10/page. Query: `?page=N&author=X&tag=Y` | None |
| GET | `/api/quotes/random` | Random quote | None |
| GET | `/api/quotes/:id` | Get quote by NanoID | None |
| PUT | `/api/quotes` | Create a quote | None (auth_code optional in body) |
| POST | `/api/quotes/:id` | Update a quote | `X-Auth-Code` header |
| DELETE | `/api/quotes/:id` | Delete a quote | `X-Auth-Code` header |
**Note:** `GET /api/quotes/random` must be registered BEFORE `GET /api/quotes/:id` in the router.
### Request/Response Shapes
**PUT /api/quotes** — Create
```json
// Request body (auth_code optional — generated if omitted)
{
"text": "...",
"author": "...",
"source": "Stanford Commencement 2005",
"tags": ["motivation"],
"date": "2005-06-12",
"auth_code": "ocean-table-purple-storm"
}
// Response 201
{
"quote": { "id": "V1StG...", "text": "...", "author": "...", ... },
"auth_code": "ocean-table-purple-storm"
}
```
**GET /api/quotes** — List
```json
{
"quotes": [...],
"page": 1,
"total_pages": 4,
"total_count": 38
}
```
**Error responses:** `{ "error": "message" }` with appropriate HTTP status.
### Auth
- No user accounts. Each quote has an `auth_code` (4-word passphrase).
- Auth codes are stored **plaintext**.
- Provided via `X-Auth-Code` header for update/delete.
- On mismatch: `403 Forbidden`.
- Auth code is always returned in the create response.
### Frontend Pages (Yew)
| Route | Page |
|-------|------|
| `/` | Home — random quote + "Browse all" link |
| `/browse` | Paginated list with author/tag filter controls |
| `/quotes/:id` | Single quote — view, edit (auth prompt), delete (auth prompt) |
| `/author/:name` | All quotes by an author |
| `/submit` | New quote form |
---
## Task 1: Bootstrap Project Structure
**Step 1: Create the quotesdb branch**
```bash
git checkout -b quotesdb
```
**Step 2: Create directory skeleton**
```
quotesdb/
├── api/
│ ├── Cargo.toml
│ ├── src/
│ │ ├── main.rs
│ │ └── tests.rs
│ ├── tests/
│ ├── docs/
│ │ ├── PLANNING.md
│ │ └── ARCHITECTURE.md
│ ├── flake.nix
│ └── README.md
├── ui/
│ ├── Cargo.toml
│ ├── src/
│ │ ├── main.rs
│ │ └── tests.rs
│ ├── index.html
│ ├── Trunk.toml
│ ├── docs/
│ │ ├── PLANNING.md
│ │ └── ARCHITECTURE.md
│ ├── flake.nix
│ └── README.md
├── tests/
│ ├── Cargo.toml
│ ├── tests/
│ ├── docs/
│ │ └── PLANNING.md
│ └── README.md
├── infra/
│ └── main.tf
└── docs/
├── PLANNING.md
├── ARCHITECTURE.md
└── plans/
└── 2026-02-27-quotesdb-design.md
```
**Step 3: Write design doc**
Write the finalized design (from this plan's "Finalized Design" section) to `quotesdb/docs/plans/2026-02-27-quotesdb-design.md`.
**Step 4: Stub Cargo.toml files**
`quotesdb/api/Cargo.toml`:
```toml
[package]
name = "quotesdb-api"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
[dependencies]
common = { path = "../../common" }
[profile.release]
opt-level = "z"
lto = true
strip = true
codegen-units = 1
```
`quotesdb/ui/Cargo.toml`:
```toml
[package]
name = "quotesdb-ui"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
[dependencies]
common = { path = "../../common" }
[profile.release]
opt-level = "z"
lto = true
strip = true
codegen-units = 1
```
`quotesdb/tests/Cargo.toml`:
```toml
[package]
name = "quotesdb-tests"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
```
**Step 5: Commit skeleton**
```bash
git add quotesdb/
git commit -m "chore(quotesdb): bootstrap project skeleton and design doc"
```
---
## Task 2: Phase 1 — Parallel Planning Agents
> **Required skill:** Use `superpowers:dispatching-parallel-agents` before dispatching.
Dispatch 4 agents IN PARALLEL (single message, 4 Task tool calls). Each works in a dedicated git worktree on its own branch. Each agent's job is to:
1. Explore the design doc at `quotesdb/docs/plans/2026-02-27-quotesdb-design.md`
2. Plan their domain thoroughly
3. Create nbd tickets for every piece of work in their domain
4. Commit their tickets on their branch
The nbd tool is available in the devshell. Tickets live in `.nbd/tickets/`. Use `nbd` to create and manage tickets.
### Agent 1: api-planner
**Branch:** `quotesdb/api`
**Directory:** `quotesdb/api/`
**Prompt:**
> You are a senior Rust backend engineer. Your job is to plan and ticket all backend API work for the `quotesdb` project.
>
> Read the design doc at `quotesdb/docs/plans/2026-02-27-quotesdb-design.md` for full context.
>
> The backend is:
> - Rust, Axum, Tokio
> - Target: Cloudflare Workers (workers-rs crate)
> - Database: SQLx with Turso (local file-based SQLite) for dev, Cloudflare D1 in production
> - Auto-generated OpenAPI spec required
>
> Create one nbd ticket per logical work item. Typical tickets include:
> - Set up Cargo.toml with all dependencies
> - Implement database migrations (schema creation)
> - Implement each API endpoint (list, get, random, create, update, delete)
> - Implement auth code generation (4-word passphrase)
> - Implement NanoID generation for quote IDs
> - Implement pagination logic
> - Implement tag filtering (join with quote_tags)
> - Implement OpenAPI spec generation
> - Write unit tests for each handler
> - Write README.md, PLANNING.md, ARCHITECTURE.md
>
> Work on branch `quotesdb/api` (use git worktrees). Each ticket should have enough detail for a developer to implement it independently.
### Agent 2: ui-planner
**Branch:** `quotesdb/ui`
**Directory:** `quotesdb/ui/`
**Prompt:**
> You are a senior Rust frontend engineer with strong design sensibilities. Your job is to plan and ticket all frontend UI work for the `quotesdb` project.
>
> Read the design doc at `quotesdb/docs/plans/2026-02-27-quotesdb-design.md` for full context.
>
> The frontend is:
> - Rust + Yew compiled to Wasm (wasm32-unknown-unknown)
> - Build tool: Trunk (`trunk serve` for dev)
> - Hosted on Cloudflare Pages
>
> Pages to build:
> - `/` — Home: random quote of the day + "Browse all" link
> - `/browse` — Paginated quote list with author/tag filter controls
> - `/quotes/:id` — Single quote view + edit/delete forms (auth code prompt)
> - `/author/:name` — All quotes by an author
> - `/submit` — New quote submission form
>
> Create one nbd ticket per logical work item. Typical tickets include:
> - Set up Cargo.toml and Trunk.toml with all dependencies
> - Set up Yew app shell and routing
> - Implement each page component
> - Implement API client (fetch calls to backend)
> - Implement auth code prompt/modal
> - Implement pagination component
> - Write README.md, PLANNING.md, ARCHITECTURE.md
>
> Work on branch `quotesdb/ui` (use git worktrees). Each ticket should have enough detail for a developer to implement it independently.
### Agent 3: qa-planner
**Branch:** `quotesdb/qa`
**Directory:** `quotesdb/tests/`
**Prompt:**
> You are a senior QA engineer specializing in Rust integration testing. Your job is to plan and ticket all integration test work for the `quotesdb` project.
>
> Read the design doc at `quotesdb/docs/plans/2026-02-27-quotesdb-design.md` for full context.
>
> Integration tests live in `quotesdb/tests/` as a separate Rust crate. Tests should:
> - Spin up the API server with an in-memory SQLite database
> - Make real HTTP requests to test each endpoint
> - Verify correct behavior for happy paths and error cases
>
> Create one nbd ticket per logical test suite. Typical tickets include:
> - Set up test harness (test server, in-memory DB)
> - Test quote creation (valid body, auth code generation, auth code provided by user)
> - Test quote retrieval (by ID, not found)
> - Test quote listing (pagination, author filter, tag filter)
> - Test random quote endpoint
> - Test quote update (valid auth, wrong auth, not found)
> - Test quote deletion (valid auth, wrong auth, not found)
> - Test OpenAPI spec endpoint
> - Write README.md
>
> Work on branch `quotesdb/qa` (use git worktrees). Each ticket should have enough detail for a developer to implement it independently.
### Agent 4: infra-planner
**Branch:** `quotesdb/infra`
**Directory:** `quotesdb/infra/`
**Prompt:**
> You are a Terraform/OpenTofu expert. Your job is to plan and ticket all infrastructure work for the `quotesdb` project.
>
> Read the design doc at `quotesdb/docs/plans/2026-02-27-quotesdb-design.md` for full context.
>
> Infrastructure uses OpenTofu with the Cloudflare provider. Resources needed:
> - Cloudflare Worker for the backend API
> - Cloudflare D1 database (bound to the worker)
> - Cloudflare Pages project for the frontend
> - Custom domain: `quotes.elijah.run` for the frontend
>
> Create one nbd ticket per logical work item. Typical tickets include:
> - Set up OpenTofu project (providers, state backend)
> - Define Cloudflare Worker resource and build config
> - Define Cloudflare D1 database resource and binding
> - Define Cloudflare Pages project with custom domain
> - Write README.md for infra setup instructions
>
> Work on branch `quotesdb/infra` (use git worktrees). Each ticket should have enough detail for a developer to implement it independently.
---
## Task 3: Merge Planning Branches
After all 4 Phase 1 agents complete:
**Step 1: Review tickets from each branch**
```bash
git log quotesdb/api --oneline
git log quotesdb/ui --oneline
git log quotesdb/qa --oneline
git log quotesdb/infra --oneline
```
**Step 2: Merge all planning branches into `quotesdb`**
```bash
git checkout quotesdb
git merge quotesdb/api
git merge quotesdb/ui
git merge quotesdb/qa
git merge quotesdb/infra
```
**Step 3: Resolve any conflicts, commit**
---
## Task 4: Phase 2 — Parallel Implementation Orchestrators
> **Required skill:** Use `superpowers:dispatching-parallel-agents` before dispatching.
Dispatch 4 orchestrator agents IN PARALLEL. Each orchestrator:
1. Lists all tickets for their domain
2. Dispatches a fresh sub-agent per ticket (one at a time — complete one before starting the next)
3. Reviews the sub-agent's work after each ticket
4. Continues to the next ticket
### Implementation agent instructions (for each domain):
Each orchestrator should prompt its sub-agents with:
- Full design context from `quotesdb/docs/plans/2026-02-27-quotesdb-design.md`
- The specific ticket to implement
- Validation commands to run: `cargo fmt && cargo check && cargo clippy && cargo test`
- Conventional commit format: `feat(quotesdb-api): ...`
### Domain orchestrators:
**api-orchestrator** — works in `quotesdb/api/`, dispatches 1 sub-agent per api ticket
**ui-orchestrator** — works in `quotesdb/ui/`, dispatches 1 sub-agent per ui ticket
**qa-orchestrator** — works in `quotesdb/tests/`, dispatches 1 sub-agent per qa ticket
**infra-orchestrator** — works in `quotesdb/infra/`, dispatches 1 sub-agent per infra ticket
> **Note:** api and tests must share an API contract. If the api-orchestrator makes endpoint changes, update the design doc and notify the qa-orchestrator.
---
## Verification
After Phase 2 completes:
**Backend:**
```bash
cd quotesdb/api
cargo fmt && cargo check && cargo clippy && cargo test
cargo run # starts local server
```
**Frontend:**
```bash
cd quotesdb/ui
trunk serve # starts dev server at localhost:8080
```
**Integration tests:**
```bash
cd quotesdb/tests
cargo test
```
**Infrastructure:**
```bash
cd quotesdb/infra
tofu plan # dry-run Cloudflare infra
```
**Manual smoke test:**
```bash
# Create a quote
curl -X PUT http://localhost:8787/api/quotes \
-H "Content-Type: application/json" \
-d '{"text":"Hello world","author":"Test"}'
# List quotes
curl http://localhost:8787/api/quotes
# Random quote
curl http://localhost:8787/api/quotes/random
```