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.

8.3 KiB

+++ title = "quotesdb" priority = 8 status = "todo" ticket_type = "project" dependencies = ["ce1e4f", "f3dc74", "c3503b", "25c413"] +++

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. 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.

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

### Database Schema
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

// 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

{
  "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
## 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): ...).

After Phase 2 completes, verify the full stack:
# 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:

# 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