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/.beans/quotesdb-32yd--quotesdb.md

234 lines
8.5 KiB
Markdown

---
# quotesdb-32yd
title: quotesdb
status: todo
type: epic
priority: critical
created_at: 2026-03-10T23:32:11Z
updated_at: 2026-03-10T23:32:19Z
blocked_by:
- quotesdb-ryhx
- quotesdb-pqdw
- quotesdb-ndjj
- quotesdb-xi3i
---
<skills>
REQUIRED: Use `superpowers:executing-plans` to implement this plan task-by-task.
SUGGESTED: Use `superpowers:dispatching-parallel-agents` for parallel agent dispatch.
SUGGESTED: Use `superpowers:subagent-driven-development` for agent dispatch within a session.
SUGGESTED: Use `superpowers:verification-before-completion` before marking any phase complete.
SUGGESTED: Use `superpowers:finishing-a-development-branch` when ready to merge.
SUGGESTED: Use `superpowers:using-git-worktrees` for parallel work in isolated branches.
SUGGESTED: Use `superpowers:test-driven-development` during development.
</skills>
<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.
All four sub-project tickets (`f3dc74` api, `c3503b` ui, `ce1e4f` qa, `25c413` infra) must be completed and closed before this ticket can close.
</goal>
<context>
A new `quotesdb` service is being added to the vibed mono-repo. The design was finalized in Phase 0. This plan covers three phases:
1. **Phase 0 (done):** Design finalized — see `docs/plans/2026-02-27-quotesdb-design.md`
2. **Phase 1:** Dispatch 4 parallel planning agents (each in a git worktree) to create nbd tickets per domain
3. **Phase 2:** Dispatch 4 parallel implementation orchestrators per domain
**Tech Stack:** Rust, Axum, Tokio, workers-rs, SQLx, Turso (local) / Cloudflare D1 (prod), Yew, Trunk, OpenTofu, Cloudflare Workers + Pages
</context>
<design>
### 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 |
</design>
<phases>
## 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:
1. Read the design doc at `docs/plans/2026-02-27-quotesdb-design.md`
2. Plan their domain thoroughly
3. Create nbd tickets for every piece of work (using `nbd create --ftype md --json`)
4. Commit their tickets on their branch
### Agent 1: api-planner
**Branch:** `quotesdb/api` | **Directory:** `src/bin/api/`
> You are a senior Rust backend engineer. Plan and ticket all backend API work for `quotesdb`.
>
> The backend is Rust + Axum + Tokio targeting Cloudflare Workers (workers-rs), with SQLx/Turso for dev and Cloudflare D1 in production. An auto-generated OpenAPI spec is required.
>
> Create one ticket per: Cargo.toml setup, database migrations, each endpoint handler, auth code generator, NanoID generator, pagination logic, tag filtering, OpenAPI spec generation, unit tests, and documentation files.
### Agent 2: ui-planner
**Branch:** `quotesdb/ui` | **Directory:** `src/bin/ui/`
> You are a senior Rust frontend engineer. Plan and ticket all frontend UI work for `quotesdb`.
>
> The frontend is Rust + Yew compiled to wasm32-unknown-unknown, built by Trunk, hosted on Cloudflare Pages.
>
> Create one ticket per: Cargo.toml + Trunk.toml setup, Yew app shell + routing, each page component (Home, Browse, Quote Detail, Author, Submit), API client module, auth code modal, pagination component, and documentation files.
### Agent 3: qa-planner
**Branch:** `quotesdb/qa` | **Directory:** `tests/`
> You are a senior QA engineer. Plan and ticket all integration test work for `quotesdb`.
>
> Tests live in `tests/` as Cargo integration tests, using a real HTTP client against a locally-spawned API server with a temporary SQLite database.
>
> Create one ticket per: dev-dependencies setup, test server harness, and one test suite per endpoint (list, get, random, create, update, delete, tags, router ordering).
### Agent 4: infra-planner
**Branch:** `quotesdb/infra` | **Directory:** `infra/`
> You are a Terraform/OpenTofu expert. Plan and ticket all infrastructure work for `quotesdb`.
>
> Resources needed: Cloudflare Worker (API), Cloudflare D1 database, Cloudflare Pages project, custom domain `quotes.elijah.run`. Use OpenTofu with the Cloudflare provider.
>
> Create one ticket per: OpenTofu project init, Workers script resource, D1 database resource, Pages project, custom domain, secrets docs, migration workflow docs, and infra README.
---
## Phase 2 — Parallel Implementation Orchestrators
> **Required skill:** Use `superpowers:dispatching-parallel-agents` before dispatching.
After all planning branches are merged, dispatch 4 orchestrator agents IN PARALLEL. Each orchestrator:
1. Lists all tickets for their domain (`nbd ready --json`)
2. Dispatches a sub-agent per ticket (one at a time — complete one before starting the next)
3. Reviews the sub-agent's work after each ticket (validate: `cargo fmt && cargo check && cargo clippy && cargo test`)
4. Continues to the next ticket
**Domain orchestrators:**
- **api-orchestrator** — works in `src/bin/api/`, dispatches 1 sub-agent per api ticket
- **ui-orchestrator** — works in `src/bin/ui/`, dispatches 1 sub-agent per ui ticket
- **qa-orchestrator** — works in `tests/`, dispatches 1 sub-agent per qa ticket
- **infra-orchestrator** — works in `infra/`, dispatches 1 sub-agent per infra ticket
Each sub-agent receives: design doc context, the specific ticket body, validation commands, and the conventional commit scope (`feat(quotesdb): ...`).
</phases>
<verification>
After Phase 2 completes, verify the full stack:
```sh
# From quotesdb/
cargo fmt && cargo check && cargo clippy && cargo test
# Start API server locally
cargo run
# Build UI to Wasm
trunk build
# Dry-run infra (from infra/)
tofu plan
```
Manual smoke test:
```sh
# 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
```
</verification>