Knowledge baseCase BreakdownsThis article

Building Traction: CRM in a Day

Traction is a mini CRM with contacts, deals, a pipeline kanban view, and data that persists across sessions. No backend. No login. Just a working tool, built in a day.

CRMs are one of those tools everyone thinks they need but nobody wants to build. The feature surface is deceptively large: contacts, companies, deals, statuses, filtering, sorting, multiple views, data import and export. Most agencies would scope this at 2 to 3 weeks. We wanted to see what a single day could produce.

The brief

A contact management tool that replaces a shared spreadsheet. Add, edit, and delete contacts. Track them through a sales pipeline. See them in a list or a kanban board. Search and filter. Export to CSV. Persist everything in localStorage so it survives page refreshes without needing a server.

The spec defined the data model explicitly: each contact has a name, company, email, phone, status (lead, prospect, active, closed, or lost), last contact date, and a next step field. Ten seed contacts were specified with realistic names and companies so the demo feels populated from the first click.

Two views, one state

The core design challenge was the dual-view interface: a sortable table view and a pipeline kanban board, both operating on the same data. Change a contact's status in the list and the kanban board updates instantly. Drag a card between pipeline columns and the list reflects it.

The agent handled this correctly on the first pass. The shared state pattern (contacts stored in a single React state, both views reading from it) is a well-understood architecture. The spec made the requirement explicit: “Moving a contact's status in one view updates the other instantly.” No ambiguity, no correction needed.

The slide-out panel

Add and edit forms use an animated slide-out panel from the right side of the screen. This was a deliberate choice over a modal: panels keep the context visible underneath, which matters when you are editing a contact and want to see where it sits in the pipeline.

The animation was the one area that required iteration. The agent's first implementation used a simple opacity transition. We specified a slide + fade combination with a 150ms duration and the panel felt immediately more polished. Small details like transition timing and easing curves are where the human still adds the most value per minute of review time.

localStorage as a feature

The decision to use localStorage instead of a backend was not a shortcut. It was a product decision. For a demo, the user experience is better: no signup, no loading spinner, no server to maintain. You add a contact, close the browser, come back tomorrow, and your data is there.

It also demonstrates a real architectural pattern. Many internal tools start as localStorage-backed prototypes and graduate to a server when they need multi-user access. The data model and the UI are the same either way. Swapping the storage layer is a one-day migration, not a rewrite.

Search, filter, export

The search bar filters contacts by name and company in real time. A status dropdown filters to a specific pipeline stage. These work together: search for “AB” with the status set to “Active” and you get only active contacts whose name or company contains “AB.”

CSV export downloads the current filtered view. If you have filtered to just active contacts, that is what you get in the CSV. The agent implemented this correctly without specific instruction, which is a good sign: the behavior is obvious enough from the interface that a well-specified agent infers it.

Timeline

Spec writing: 25 minutes. Agent execution: about 4.5 hours across two sessions. Human review, corrections, and deployment: about 1 hour. Total: roughly 6 hours from nothing to a deployed, working CRM.

The final output: approximately 1,800 lines of TypeScript across 10 files. Three human interventions: the panel animation timing, a tweak to the kanban column widths on mobile, and adjusting the seed data to include a better mix of Swedish and international names.

What we learned

CRUD applications are the sweet spot for AI-native development. The spec-to-implementation mapping is nearly 1:1. You describe the data model, the operations, and the views, and the agent produces working code with minimal aesthetic judgment required. The three corrections we made were all about feel (animation, responsive layout, name variety), not function.

The biggest lesson: the scope decision matters more than the implementation speed. We could have added drag-and-drop reordering, activity logs, email integration, and a dozen other features that real CRMs have. Cutting to the core (contacts, statuses, two views, persistence) is what made the one-day timeline possible. The features we left out can each be added in a half-day sprint if a client needs them.

The live demo is at /demos/crm. Add a contact, switch to pipeline view, close the browser, come back. It works.

Read next