GoKrasiva CRM
The internal CRM I built for Krasiva Windows & Doors
Problem
Krasiva was running on an older Bubble app. Leads came in from the website, Thumbtack, Angi and the phones, and follow-up depended on someone remembering to call or text. Window and door prices lived in a price sheet, and hiring canvassers meant scheduling interviews and collecting paperwork one applicant at a time.
Approach
Next.js App Router on Supabase Postgres, using row-level security, RPCs, triggers and Realtime. Each user has a primary role plus extra roles, and their permissions merge. UI code can reach the backend only through one client API layer that calls typed route handlers, and every date is in Arizona time. The schema lives in numbered SQL migrations and the app deploys to Vercel. I started it in JavaScript and moved it to TypeScript in May 2026. Since July most of the code has been written with AI coding tools (Cursor and Claude Code) working under rules I wrote: a repo guide, file-size budgets, zero-warning lint, CI, CodeQL and Linear tickets.
Process
15 dated steps, from the project’s history
-
Pricing engine prototype
Before the CRM existed I wrote a framework-free pricing engine for windows and doors: United Inches sizing that always rounds up, allowed product lines, add-on size limits, discounts and PAR pricing, with admin and sales pages ported to Astro. It later became the CRM quote builder and catalog.
-
One test text
A Node script that sent a single SMS through the RingCentral API. It grew into the CRM phone and text layer: click-to-call, a call log, two-way texting with live webhooks and a shared calling queue.
-
Repo and call center on day one
Started the app as "lead-crm-js" on Next.js and Supabase and added the call center the same day.
-
First live deploy, thirteen days in
First live deploy on Vercel, with the New Job flow linking jobs back to their leads.
-
Careers portal: six steps, then three
I turned /careers into a six-step wizard with a progress ring, emoji copy and confetti, then reworked it the same day into three calm steps with a video that stays on screen, plain icons and natural copy. Applicants book their own interviews from the same portal.
-
Cadences and text automation
Delay-based cadences send texts and emails, change statuses and move leads between queues, with every step logged so it never fires twice. Inbound texts run through auto-reply chains.
-
In-house e-sign paperwork
New-hire packets with token-signed links, signed PDFs built with pdf-lib and completion emails. Zoom interview booking with calendar invites followed on March 12.
-
Bubble retired
During the move the CRM answered on a Bubble-compatible /api/1.1 endpoint. Removing it ended the old app's role.
-
Moved to TypeScript
Converted the app from JavaScript and reorganized the layout. Strict-mode passes followed in October, such as taking the quotes components from 311 implicit-any errors to zero.
-
Rules for building with AI tools
CI, CodeQL and Dependabot went in on July 1 and the repo guide and Cursor rules on July 7. Most commits after that carry a Cursor or Claude co-author trailer.
-
Four layouts in one day
The quote item editor went from preview-left with pickers on the right, to a single column, to two columns with a full-width catalog, to an icon toolbar with compact panels.
-
Customers become the parent record
Leads, jobs and services now hang off one customer record, with merging, add-on leads and customer file tabs.
-
Design tokens
Semantic color tokens with light and dark values, the core controls (Button, Input, Select, Textarea, Modal) rebuilt on them with lint rules, and the raw gray values across the app moved onto those tokens.
-
A green CI and a backend audit
Fixed CI, which had been failing since June. An audit of Go against TypeScript for the backend ended with "stay on TypeScript" and indexes on the slow paths.
-
Job photos, built and waiting on setup
A photo service indexes company job photos where they are already stored and links them to CRM jobs. The Photos tab on each job is built; it switches on once its signing secret is configured.
Results
The CRM runs at gokrasiva.com, with a public careers and scheduling portal. It connects to RingCentral, Microsoft Graph mail, SMTP, Resend, Google Calendar, Zoom, Zapier, Thumbtack, Angi and the Meta Conversions API.
Lesson
Building a codebase this size alone only worked once the rules were written down: never undo someone else's change, checkpoint after every session, batch pushes because every Vercel build is billed, keep files under a size budget, and treat a lint warning as a failure. An October audit weighed rewriting the backend in Go against staying on TypeScript. It kept TypeScript and fixed the slow paths instead.