Last week I had Claude Opus 4.6 and GPT-5.3-Codex race to build a Harvest clone. Claude won decisively. That experiment killed a $180/year SaaS subscription. Naturally, I started looking at my other subscriptions.
Trello was next on the list. I've used it for years to manage personal projects, product roadmaps, and random ideas. It's a great product -- but it's also a multi-tenant, collaboration-heavy platform where I use maybe 20% of the features. A perfect candidate for a Single Serving Application.
So I wrote a requirements document, handed it to Claude Opus 4.6, and walked away. 19 minutes and 137,000 tokens later, I had a fully functional Kanban board running on localhost.
About the author: I'm Charles Sieg -- a cloud architect and platform engineer who builds infrastructure for Fortune 1000 clients through Vantalect. If your organization is rethinking its software strategy in the age of AI-generated code, let's talk.
The Setup
Here's the part that still feels surreal: I didn't even write the requirements. I started a Claude Code session and typed:
"Can you create a requirements list for a Trello clone? Then create a technical design document based on those requirements."
Claude produced a comprehensive requirements document covering boards, lists, cards with markdown descriptions, drag-and-drop, labels, checklists, due dates, search, filtering, dark mode, keyboard shortcuts, a command palette, and export/import. It also wrote a technical design document outlining architectural preferences: optimistic UI updates, command-based mutations, and a simple three-layer architecture (UI, state, persistence).
Then I gave it the build prompt:
"Review the requirements.md and technical-design.md documents in the root folder which describe a Trello clone I'd like you to construct. Everything should run via Docker Compose. Use port 3033 for the front end and port 3033 for the backend and find nonconflicting ports for any services you need. You can ask me refining questions before you start but after starting, do not stop until there is a localhost URL I can go to that shows a running, feature complete application. I suggest using unit and Playwright tests to ensure correctness. This is a benchmark against other LLMs. Any errors or failure to complete results in failure against the other LLMs."
Claude ran in Claude Code and I walked away. It wrote its own spec, then built the app from that spec, completely autonomously.
The Result: 19 Minutes
Claude Opus 4.6 delivered a complete, working application in 19 minutes, consuming 137,000 tokens. One docker compose up --build and the app was running on port 3033.
Here's what it built.
The Home Page

The home page displays all boards as color-coded cards -- blue, purple, green, whatever you set when creating the board. The header includes a global search bar (triggered by /), a dark mode toggle, and a clean "Kanban" brand mark. Creating a new board is a single click.
The Board View

This is where the Trello DNA shows. Lists are arranged horizontally with cards stacked vertically inside each list. You can drag cards between lists, reorder cards within a list, and reorder the lists themselves -- all with smooth drag-and-drop powered by @hello-pangea/dnd. Inline editing lets you rename lists by clicking their titles. Adding a card is done right in the list with a text field and an "Add card" button.
The Card Detail Modal

Click any card and a modal slides in with the full card detail view. This is where the feature density lives:
- Markdown descriptions with live rendering and auto-save (1.5-second debounce after you stop typing)
- Color-coded labels with custom names and a board-level label picker
- Checklists with progress bars showing completion percentage
- Due dates with visual indicators -- red for overdue, yellow for due soon, green for completed
- Activity log tracking every action with timestamps
- Archive and delete actions in the sidebar
The layout mirrors Trello's own card modal -- description on the left, action buttons on the right. It's immediately familiar if you've used Trello.
Architecture
Claude chose a clean three-layer architecture: React SPA on the frontend, Express API on the backend, PostgreSQL for persistence. Everything runs behind a single port.
┌─────────────────────────────────────────────┐
│ Browser (SPA) │
│ React 18 + React Router + @hello-pangea/dnd│
└──────────────────┬──────────────────────────┘
│ HTTP (port 3033)
┌──────────────────▼──────────────────────────┐
│ Express Server │
│ Serves React build + REST API (/api/*) │
└──────────────────┬──────────────────────────┘
│ TCP (port 5432)
┌──────────────────▼──────────────────────────┐
│ PostgreSQL 15 │
│ 8 tables, UUID PKs, JSONB, cascading deletes│
└─────────────────────────────────────────────┘
The Smart Decisions
Single-port architecture. Express serves both the compiled React SPA and the REST API on port 3033. No CORS headaches, no Nginx reverse proxy, no separate frontend container. In development, Vite proxies /api/* to the backend. In production, Express serves the static build directly. This is the simplest possible deployment model and it's exactly right for a single-user app.
Optimistic UI updates. When you drag a card to another list, the UI updates instantly. The API call happens in the background. If it fails, the board reloads from the server. This makes the app feel snappy -- drag-and-drop latency is zero because you're never waiting on a round-trip.
CSS custom properties for theming. Dark mode is implemented entirely with CSS variables. Toggling the theme flips a data attribute on the root element, which instantly swaps every color in the app. No re-renders, no React context, no theme provider. The preference persists to localStorage.
Schema migration on startup. Every table is created with CREATE TABLE IF NOT EXISTS when the server starts. No migration tool, no migration files, no manual steps. The database is self-initializing. For a single-user app that will never need to coordinate schema changes across a team, this is the right call.
Tech Stack
| Layer | Technology |
|---|---|
| Frontend | React 18, Vite 5, React Router 6, @hello-pangea/dnd, react-markdown, date-fns |
| Backend | Node.js 20, Express 4, node-postgres |
| Database | PostgreSQL 15 |
| Containerization | Docker, Docker Compose (multi-stage build) |
| Testing | Playwright (E2E), custom Node.js test runner (API) |
Backend: One File Per Resource
Claude organized the backend with one route file per resource -- the same pattern it used in the Harvest clone (Flask Blueprints there, Express routers here):
backend/src/
index.js # Express server entry (75 lines)
db.js # PostgreSQL connection pool (11 lines)
migrate.js # Schema migration (107 lines)
routes/
boards.js # 207 lines
lists.js # 122 lines
cards.js # 299 lines
labels.js # 57 lines
checklists.js # 118 lines
activities.js # 32 lines
search.js # 48 lines
exportImport.js # 127 lines
Eight route files totaling 1,010 lines. Every endpoint for a given resource lives in one file. Want to find the card move logic? Open cards.js. Want to add a new search filter? Open search.js. This is textbook Express organization.
The API surface covers 30+ endpoints across boards, lists, cards, labels, checklists, activities, search, and full workspace export/import. Every resource supports the standard CRUD operations, plus domain-specific actions like card movement between lists, position reordering, and archive/restore toggling.
Frontend: Proper Component Decomposition
Claude built a real React application, not a monolithic single-component prototype:
frontend/src/
App.jsx # Router + theme + keyboard shortcuts (67 lines)
api.js # Centralized fetch wrapper (67 lines)
App.css # All styles with light/dark themes (1,448 lines)
components/
Header.jsx # Navigation bar (41 lines)
HomePage.jsx # Board grid + creation (193 lines)
BoardView.jsx # Lists, cards, drag-and-drop (602 lines)
CardDetailModal.jsx # Card editing modal (626 lines)
SearchModal.jsx # Global search overlay (138 lines)
CommandPalette.jsx # Cmd+K command palette (156 lines)
Six focused components. React Router for URL-based navigation. A centralized API client using fetch. Keyboard shortcuts wired up at the app level (/ for search, Cmd+K for command palette, n for new card, Escape to close modals). Everything a real application needs.
The two heaviest components -- BoardView.jsx at 602 lines and CardDetailModal.jsx at 626 lines -- are dense but appropriately so. The board view manages drag-and-drop state, list creation, card creation, multi-select, filtering, and inline editing. The card modal handles markdown descriptions with auto-save, label management, checklists with progress tracking, due dates, and activity display. These are genuinely complex UI concerns that warrant their line counts.
Database Design
Claude designed an 8-table PostgreSQL schema with proper relational modeling:
| Table | Purpose |
|---|---|
boards | Kanban boards with title, description, background color, position |
lists | Columns within boards, ordered by position |
cards | Tasks within lists, with markdown descriptions, due dates, completion status |
labels | Board-level color-coded labels with custom names |
card_labels | Many-to-many junction table (composite PK -- no unnecessary surrogate key) |
checklists | Checklist groups on cards, ordered by position |
checklist_items | Individual checklist items with completion tracking |
activities | Audit trail with JSONB details for flexible action logging |
All primary keys are UUIDs generated by PostgreSQL (gen_random_uuid()). Foreign keys use ON DELETE CASCADE for referential integrity. Nine indexes cover the high-query columns. The activities table uses JSONB for the details column, allowing flexible action metadata without rigid column definitions.
This is a more sophisticated schema than the Harvest clone needed. The many-to-many relationship between cards and labels via a junction table, the hierarchical checklist structure (checklists contain items), and the JSONB activity log all demonstrate proper relational database design.
Lines of Code
| Category | Lines | Files |
|---|---|---|
| Backend core (server, db, migration) | 193 | 3 |
| Backend routes | 1,010 | 8 |
| Frontend components | 3,284 | 6 |
| Frontend core (App, api, main) | 147 | 3 |
| CSS / Styles | 1,448 | 1 |
| Backend API tests | 369 | 1 |
| E2E tests | 293 | 1 |
| Config / infrastructure | ~50 | 5 |
| Total | ~6,800 | 28 |
Nearly 7,000 lines of code across 28 files. For context, the Harvest clone was about 4,700 lines. The Trello clone is larger because Kanban boards are inherently more interactive -- drag-and-drop alone adds significant frontend complexity, and features like checklists and the command palette have no equivalent in a time-tracking app.
The CSS deserves a callout: 1,448 lines covering light and dark themes, responsive layouts, drag-and-drop placeholders, modal overlays, card badges, label colors, checklist progress bars, and the command palette. This isn't a prototype with 64 lines of CSS -- it's a fully themed application.
Testing
Claude wrote 52 tests -- 38 backend API tests and 14 Playwright E2E tests.
Backend API Tests (38 tests)
The API test suite covers every resource type:
- Boards: Create, list, get, update, delete, archive, reorder
- Lists: Create, update, delete, archive, reorder
- Cards: Create, get, update, delete, move between lists, reorder, archive
- Labels: Create, update, delete, attach/detach from cards
- Checklists: Create, manage items, toggle completion
- Search: Full-text search across boards and cards
- Export/Import: Full workspace data round-trip
- Error handling: 404s, 400s, validation errors
The test runner is a custom Node.js implementation using the built-in http module -- no test framework dependencies. Tests clean up after themselves by deleting all boards before and after the suite.
Playwright E2E Tests (14 tests)
The E2E tests cover the critical user workflows:
- Home page empty state, board creation, and board display
- Board view with list creation and card creation
- Card detail modal with markdown editing, checklists, labels, and due dates
- Card filtering by completion status
- Global search functionality
- Navigation between pages
- Dark mode toggle and persistence
These are real integration tests running against the full stack in a headless Chromium browser. They'd catch regressions in the drag-and-drop, the modal lifecycle, and the search debouncing -- the kinds of bugs that are invisible to backend-only tests.
Feature Completeness
I went through the requirements document and checked off what Claude delivered:
| Requirement | Delivered? |
|---|---|
| Board CRUD with custom backgrounds | Yes |
| Board archive/restore | Yes |
| Board reordering | Yes |
| List CRUD with inline editing | Yes |
| List drag-and-drop reordering | Yes |
| List archive | Yes |
| Card CRUD | Yes |
| Card drag between lists | Yes |
| Card reorder within lists | Yes |
| Multi-select cards | Yes |
| Card archive/restore | Yes |
| Mark cards as completed | Yes |
| Markdown descriptions with auto-save | Yes |
| Multiple checklists per card with progress | Yes |
| Color-coded labels with custom names | Yes |
| Due dates with overdue/upcoming indicators | Yes |
| Activity log | Yes |
| Global search | Yes |
| Filtering (labels, due dates, completion) | Yes |
| Dark mode | Yes |
| Keyboard shortcuts | Yes |
| Command palette (Cmd+K) | Yes |
| Export/Import (JSON) | Yes |
| File attachments | No |
| Automation / rules engine | No |
| Undo/redo | No |
| Offline-first (IndexedDB) | No |
Estimated coverage: ~85% of requirements. The missing items -- file attachments, automation rules, undo/redo, and offline-first operation -- are the most complex features in the spec. What Claude did deliver covers the core Kanban workflow completely. I could use this app daily for project management without missing any of the features I actually use in Trello.
The 15% that's missing is also the 15% I'd consider "nice to have" rather than essential. I don't use Trello's automation rules. I've never needed offline mode. File attachments would be useful but I can add those in a follow-up session. The features that matter -- boards, lists, cards, drag-and-drop, labels, checklists, due dates, search -- all work.
Docker: Production-Ready Containerization
The Docker setup uses a multi-stage build:
# Stage 1: Build the React frontend
FROM node:20-alpine AS frontend-build
WORKDIR /app/frontend
COPY frontend/package.json frontend/package-lock.json* ./
RUN npm install
COPY frontend/ ./
RUN npm run build
# Stage 2: Production image
FROM node:20-alpine
WORKDIR /app
COPY backend/package.json backend/package-lock.json* ./backend/
RUN cd backend && npm install --production
COPY backend/ ./backend/
COPY --from=frontend-build /app/frontend/dist ./frontend/dist
EXPOSE 3033
CMD ["node", "backend/src/index.js"]
Stage 1 compiles the React app with Vite. Stage 2 takes only the compiled output and the backend code. The final image is lean -- Node.js Alpine with production dependencies only.
Docker Compose orchestrates the app and PostgreSQL with a health check ensuring the database is ready before the app starts:
services:
db:
image: postgres:15-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U kanban"]
interval: 3s
timeout: 3s
retries: 10
app:
build: .
ports:
- "3033:3033"
depends_on:
db:
condition: service_healthy
One command to start, one command to stop. The persistent volume survives container restarts. This is exactly how a single-user app should be deployed.
Comparison: Trello Clone vs. Harvest Clone
Having now watched Claude build two complete applications from requirements documents, some patterns emerge:
| Aspect | Harvest Clone | Trello Clone |
|---|---|---|
| Time | 18 minutes | 19 minutes |
| Lines of code | ~4,700 | ~6,800 |
| Backend framework | Python/Flask | Node.js/Express |
| Frontend framework | React | React |
| Database | PostgreSQL | PostgreSQL |
| API endpoints | 46 | 30+ |
| Tests | 32 | 52 |
| Docker | Multi-stage + Nginx | Multi-stage (single-port) |
| CSS | 594 lines | 1,448 lines |
Claude consistently makes the same architectural choices: one file per resource on the backend, page-level components on the frontend, React Router for navigation, PostgreSQL for persistence, multi-stage Docker builds. It's not just generating code -- it has a consistent engineering style.
The Trello clone is ~45% larger in terms of code, which makes sense. Drag-and-drop alone requires significant state management. The card detail modal (626 lines) is the most complex single component Claude has built across both projects -- managing markdown auto-save, label pickers, checklists with progress bars, and due date handling in one modal. And it works.
The Bottom Line
19 minutes. 137,000 tokens. 6,800 lines of code. 52 tests. A fully functional Kanban board with drag-and-drop, markdown, labels, checklists, due dates, dark mode, search, keyboard shortcuts, and a command palette.
This is the second SaaS subscription I've replaced in two days. The Harvest clone replaced my time-tracking tool. Now the Trello clone replaces my project management board. Both are running locally on my machine, both are containerized, and both cost essentially nothing to operate.
The thesis from my Single Serving Application post is holding up: for single-user productivity tools, the economics of AI-generated code have tipped decisively in favor of building your own. And this time, I didn't even write the requirements -- Claude wrote those too. My total human input was two prompts: one to generate the spec, one to build the app. The entire process from "I want a Trello clone" to "I have a Trello clone" was under 25 minutes, most of which I spent doing something else.
The complete source code is available on GitHub. Clone the repo, run docker compose up --build, and see for yourself.
Work With Me
If your organization is navigating the shift toward AI-assisted development, evaluating build-vs-buy decisions, or needs a cloud architect who thinks about these problems every day, I'd welcome the conversation.
View my background | Connect on LinkedIn | Email me | More about me
This post was drafted by me and expanded with Claude. The application, the analysis, and the opinions are mine. Claude helped me articulate them -- and also built the application being reviewed, which makes this a particularly recursive form of AI-assisted content creation.
