Level: advanced Estimated time: 60–90 min Objective: build a real fullstack web application with SQLite persistence, practice the complete OpenSpec workflow (SPEC.md → AGENTS.md → sub-agents), and learn to work with multiple layers at once (frontend, API, database).
The classic Todo List, but built the way a professional team would: REST API backend, SQLite database, decoupled frontend, and a minimum of care for security and tests. It's the perfect challenge to show how OpenCode shines in multi-layer projects.
The challenge covers:
- Client-server architecture in a simple monorepo.
- REST endpoints with input validation.
- Persistence in SQLite (a single
data.dbfile). - Live AGENTS.md: rules that the agent respects between iterations.
- Division of work into sub-agents (explore, security, reviewer).
- Basic automated tests.
mkdir todolist-pro
cd todolist-pro
opencodeRecommended: Mimo 2.5 Pro or Qwen 3.6 for execution via OpenCode Zen, planning with GPT-5.5 high if you have ChatGPT Plus connected. The challenge benefits greatly from a good planner.
Copy and paste this prompt into OpenCode, ideally starting in Plan mode:
Build a fullstack Todo List application with SQLite persistence.
Folder structure:
- /server → Node.js backend + SQLite (no Express if possible, use native http or minimal dependency like Hono)
- /web → vanilla frontend (HTML + CSS + JS, no frameworks)
- /db → data.db file and SQL migrations
- AGENTS.md → project rules
- SPEC.md → live specification
- README.md → how to start and test
Backend:
- Runtime: Node.js 24 or Bun (agent chooses and documents in AGENTS.md)
- REST API at /api with the following endpoints:
- GET /api/notes → paginated list (?page=1&limit=20)
- POST /api/notes → creates a note
- GET /api/notes/:id → detail
- PATCH /api/notes/:id → updates title, content, or status (done)
- DELETE /api/notes/:id → logical delete (soft delete, deleted_at column)
- Input validation: required title 1-120 chars; optional content max 5000 chars
- Consistent JSON responses: { ok: true, data } or { ok: false, error: { code, message } }
- Error handling with correct status codes (400, 404, 409, 500)
- CORS open to localhost in development
Database:
- SQLite (better-sqlite3 or bun:sqlite driver)
- File at /db/data.db
- Initial migration at /db/migrations/001_init.sql with the notes table:
id INTEGER PRIMARY KEY AUTOINCREMENT
title TEXT NOT NULL
content TEXT
done INTEGER NOT NULL DEFAULT 0
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
deleted_at DATETIME
- Migrations apply automatically when starting the server
Frontend:
- index.html with:
- List of notes, filterable by status (all / pending / completed)
- Inline form to create new note (title + content)
- Inline editing when clicking title or content
- Button to mark as done (accessible checkbox)
- Delete button with discreet confirmation
- Friendly empty state when there are no notes
- styles.css with the soft sage palette from the workshop:
cream background #F5F1E8, sage accents #84B59F, slate #50808E, text #2E3A42
- app.js with fetch to /api, error handling, and visual feedback
- No frameworks or libraries; one template helper allowed (template literals)
Tests (minimal):
- API tests with node:test or bun:test
- Coverage: create, list paginated, update, delete, error validations
- Single command: `bun test` or `npm test`
Quality:
- Consistent code style (Prettier defaults)
- README with: requirements, start (single command), endpoints, curl examples
- AGENTS.md with all decisions (runtime, SQLite driver, no framework, no frontend framework)
- SPEC.md with objectives, entities, endpoints, and acceptance criteria
Steps before starting to program:
1. Give me a numbered plan of 7 to 10 steps without touching files.
2. List the decisions I need to confirm (runtime, driver, single startup command).
3. Wait for me to say "go" before starting to write code.
- Plan and decisions. Review the plan and confirm key decisions (runtime, driver). This avoids rewrites.
- Build with sub-agents. When implementation starts, divide the work:
In parallel: @explore map what files you'll create and in what order @general assess API security risks (SQL injection, CORS, validation) - Build by layers. Explicitly suggest to the agent to go layer by layer:
- Migration and data access module.
- Endpoints one by one with their tests.
- Minimal frontend connected to backend.
- Visual polish and empty states.
- Iterate with curl examples. When the backend is ready, test in Shell Mode:
!curl -s http://localhost:3000/api/notes | jq !curl -s -X POST http://localhost:3000/api/notes -H 'Content-Type: application/json' -d '{"title":"First note","content":"hello"}' - Save tokens. For spot fixes, use
@server/routes/notes.jsor other specific files in the input. - Close with a clean commit:
Or manually:
/supercommit feat: todo list MVP fullstack!git init && git add . && git commit -m "feat: todo list MVP fullstack"
-
bun dev(ornpm run dev) starts backend and frontend with a single command. - All 5 REST endpoints work with consistent JSON responses.
- Database persists after restarting the server.
- Delete is logical (note isn't lost from database).
- Frontend shows empty states and errors in a friendly way.
- Tests pass (
bun testornpm test). - Repository includes
SPEC.md,AGENTS.md, andREADME.md. - No obvious vulnerabilities (SQL injection, XSS when rendering content).
- Tags: add a tag system per note and a tag filter in the frontend.
- Search:
GET /api/notes?q=textendpoint with full-text search using SQLite's FTS5 extension. - Basic auth: middleware with Bearer token and single user configurable by
.env. - Export / Import: endpoints to download and upload JSON backups.
- PWA: convert the frontend into an installable PWA with manifest and offline-first service worker.
- DESIGN.md: document the design system used and ask the AI to respect those tokens in future iterations.