Early access: these pages are being written and reviewed. Facts in the header boxes come straight from the product.
Changelog
In short. Every release of Pitch2Sale, newest first. Entries tagged with a feature link to that feature’s page.
Unreleased
Section titled “Unreleased”- Unified lead-ingest pipeline — every inbound source (forms, webhooks, Meta) flows through one path: idempotency → dedup/merge → create/update Lead + primary Contact →
lead.createdevent → enrich (scoring) →IngestEventaudit record. - Inbound Webhooks — universal receiver: per-endpoint URL, JSON field mapping (dotted paths), dedup strategy/match-field, idempotency key, optional HMAC-SHA256 signing (
X-Ingest-Signature). Config UI at Settings → Automation → Inbound Webhooks. - Meta Lead Ads — direct Facebook/Instagram Lead Ads connector: verify-token handshake,
X-Hub-Signature-256verification, Graph API lead fetch byleadgen_id, per-connection page token. Config UI at Settings → Automation → Meta Lead Ads. - Google Lead Ads — direct Google Lead Form connector: inline webhook payload (no API fetch), shared-key (
google_key) verification,is_testhandling, idempotent onlead_id. Config UI at Settings → Automation → Google Lead Ads. - Instant Response (speed-to-lead) — auto email/SMS reply on
lead.createdfrom any source, with placeholder tokens, source filtering, and unsubscribe/opt-out guards. Config UI at Settings → Automation → Instant Response. - Two-way Google/Microsoft calendar sync (
ConnectedCalendar), public scheduling pages with booking links, booking routing rules (round-robin / weighted / skill-based), and booking-outcome analytics. - AI voice agents (Retell + Twilio), outbound AI-voice campaigns with pacing/consent, live supervisor (listen/barge), A/B prompt testing, inbound AVA, live translation, and expanded human-dialer tooling.
- Knowledge base + support tickets (categories, routing, CSAT), surveys, goals, projects/timesheets enhancements, client portal, and invoices/payments/expenses (Stripe + Razorpay) hardening.
- AI Copilot, Deal Coach, lead scoring/summary/next-action, inbox summaries, and AI proposal generation improvements.
- A2P 10DLC registration flow, GDPR/consents, and TCPA abandonment controls.
- Proposals can now be sent when a document-only proposal has a confirmed uploaded file.
- Estimates show the linked lead as a clickable link and support an inline lead picker.
- Contracts now actually email the client on send (the email path was missing).
- New documentation-site categories: Lead Capture & Ingestion and Calendar & Scheduling; feature inventory updated to match.
- New Zapier, n8n & Make guide (Integrations) — how to connect automation platforms today via inbound webhooks, outbound webhook subscriptions, and the REST API, ahead of the native partner connectors.
Sprint F10 — 2026-03-21
Section titled “Sprint F10 — 2026-03-21”- Settings layout with 220px left nav, 6 sections (Account, Organization, CRM, Communication, Automation, Developer), active state highlighting
- ProfileSettings: name, timezone, change password (RHF+Zod min 8 chars)
- OrgGeneralSettings: name, timezone, currency, date format, address, tax ID, danger zone delete
- TeamSettings: DataTable with status badges, invite/edit role/deactivate/remove actions
- InviteUserModal: email + role picker
- EditUserRoleModal: role dropdown with warnings
- RolesSettings: two-panel — role list + permission matrix (18 features x 5 capabilities), auto-logic (view_global->view_own), system roles read-only, PlanGate for custom roles
- PipelineSettings: two-panel — list + editor with @dnd-kit sortable stages, color picker, status_type badges, won/lost protection, auto-save
- LeadStatusSettings: @dnd-kit sortable, inline edit, color picker, delete protection, auto-save
- CustomFieldsSettings: 4-tab (Leads/Contacts/Opportunities/Activities), DataTable, AddCustomFieldModal (10 types, choices builder)
- CustomActivitySettings: list with is_active toggle, CustomActivityTypeModal with fields builder
- FormsSettings: list + FormBuilder (drag fields, live preview, settings, embed code tab)
- WebhooksSettings: list with test button, WebhookCreateModal (URL + categorized events + auto-generated secret shown once)
- BillingSettings: plan card with colored badges, usage metrics with progress bars, 4-plan feature comparison table, invoice history
- /f/[token]: public form submission page, dynamic Zod schema from field definitions, 7 field types, success message, no auth
- useSettings, useRoles, useForms, useWebhooks hooks
- All 12 Frontend Laws enforced, all forms RHF+Zod, all modals Radix Dialog, @dnd-kit for all reorder, permission gates throughout
Sprint F7 — 2026-03-21
Section titled “Sprint F7 — 2026-03-21”- InboxList: 4 collapsible groups (Missed Calls, Unread Emails, Overdue Tasks, Mentions) with count badges, clear all, real-time Socket.io refresh
- InboxItemDetail: type-specific detail views (call back, email reply with DOMPurify, task complete/reschedule, mention view)
/inboxpage: two-column layout, URL-based group filtering, mark-as-read on selection- useInbox hook: TanStack Query + Socket.io invalidation + markAsRead/clearGroup mutations
- DateRangePicker: 9 presets + custom range, reusable across app
- MetricTile: formatted numbers/currency, trend arrow, optional sparkline
- OverviewTab: 6 metric tiles + stacked BarChart (daily activity breakdown)
- LeaderboardTab: virtualized DataTable, rank badges, export CSV, admin click-to-filter
- FunnelTab: custom SVG trapezoid funnel, conversion rates, avg days in stage
- SalesVelocityTab: formula card, 4 variable cards, velocity result, LineChart trend
- CallOutcomesTab: PieChart donut, DataTable with progress bars, avg duration tile
- EmailStatsTab: 5 metric tiles + dual-axis LineChart (open/click rates)
- TimesheetsTab: permission-gated, user/project filters, totals row, export CSV
/reportingpage: 7 lazy-loaded tabs, DateRangePicker + user filter, PlanGate- reporting.store.ts: shared date range + user filter across all tabs
- useReporting: 7 TanStack Query hooks reading from store
- All Recharts follow standard (ResponsiveContainer, styled tooltips, CartesianGrid)
- All 12 Frontend Laws enforced
Sprint F6 — 2026-03-21
Section titled “Sprint F6 — 2026-03-21”- FullEmailComposer: 560px Sheet, TipTap rich text editor with toolbar, To/Cc/Bcc contact type-ahead, From account picker, {{variables}} insertion, template picker, Ctrl+Enter send, discard-draft confirmation
- EmailThread: collapsed/expanded thread view, DOMPurify-sanitized HTML rendering (SECURITY), inline reply composer
- EmailTrackingBadge: 5 states (Sent/Opened/Clicked/Bounced/Replied) with tooltips
- TemplateManager: CRUD DataTable + TipTap create/edit dialog
- ConnectedAccountCard: provider badge, sync status, reconnect/disconnect
- Settings/Email page: OAuth popup connect (Gmail/Outlook) with postMessage origin validation, templates, unsubscribes
- useEmailTemplates, useConnectedAccounts hooks
- DialerPanel: floating softphone (z-50), 5 states (idle/connecting/ringing/active/ended), contact search, counting timer, mute/hold buttons, auto-transitions to disposition
- DispositionModal: 8 outcomes, RHF+Zod, optional follow-up task creation, auto-advance in power dialer
- PowerDialerHUD: queue progress bar, skip with reason, pause/resume/stop, auto-advance toggle
- IncomingCallToast: Socket.io call.incoming listener, caller ID matching, accept/decline, 30s auto-dismiss
- dialer.store.ts: full Zustand implementation (NO persist – memory only for token security, LAW 8)
- useCalling: Twilio token fetch + auto-refresh, dial/hangup/mute/hold
- Settings/Calling page: phone numbers, compliance badges (STIR/SHAKEN + A2P 10DLC)
- DialerPanel + IncomingCallToast wired into app layout (visible on all routes)
- All 12 Frontend Laws enforced
- DOMPurify on all email HTML (every
dangerouslySetInnerHTMLguarded) - Twilio token memory-only (no
persistmiddleware, no localStorage) - OAuth postMessage origin validated against
env.NEXT_PUBLIC_API_URL - No
anytypes, noprocess.env, no hardcoded URLs across all F6 files
Sprint 20 — 2026-03-21
Section titled “Sprint 20 — 2026-03-21”- Survey model with configurable questions supporting 6 question types:
text,textarea,rating,choice,multi_choice,nps - Public submission token for unauthenticated survey access
- Target audience and expiry date configuration
- Survey lifecycle management: activate and close with
is_activeflag - SurveyResponse model with per-question answers and extracted NPS score
- NPS score extraction from NPS-type question responses (0–10 scale)
- Full CRUD for survey definitions with org-scoped queries
- Activate/close lifecycle management
- Public submission endpoint with per-question answer validation against question type constraints
- NPS analytics: promoter (9–10) / passive (7–8) / detractor (0–6) breakdown with overall NPS score calculation
- Per-question breakdown showing response distribution for each question
- Goal model with metric configuration:
target,currentvalue, andunit - Goal scope levels:
individual,team,org - Goal period options:
weekly,monthly,quarterly,yearly,custom - Full CRUD for goal definitions with org-scoped queries
- Live progress recomputation from Opportunity and Activity data
- Auto-complete: goals automatically marked complete when current value reaches 100% of target
- Expired goal detection for goals past their
end_datethat have not been completed surveysandgoalsadded toFEATURESandPLAN_FEATURESconstants- Both features gated to Growth+ plans via
requireFeaturemiddleware - 10 endpoints under
/api/v1/surveys:GET /api/v1/surveys— list surveysPOST /api/v1/surveys— create surveyGET /api/v1/surveys/:id— get single surveyPUT /api/v1/surveys/:id— update surveyDELETE /api/v1/surveys/:id— delete surveyPOST /api/v1/surveys/:id/activate— activate surveyPOST /api/v1/surveys/:id/close— close surveyGET /api/v1/surveys/:id/responses— list survey responsesGET /api/v1/surveys/:id/analytics— NPS analytics + per-question breakdownPOST /api/v1/surveys/public/:token/submit— public survey submission (no auth)
- 6 endpoints under
/api/v1/goals:GET /api/v1/goals— list goalsPOST /api/v1/goals— create goalGET /api/v1/goals/:id— get single goalPUT /api/v1/goals/:id— update goalDELETE /api/v1/goals/:id— delete goalPOST /api/v1/goals/:id/refresh— recompute goal progress from live data
Sprint 19 — 2026-03-21
Section titled “Sprint 19 — 2026-03-21”- KnowledgeBaseArticle model with auto-slug generation from title
- Text search index on
titleandbodyfor full-text search - Article status lifecycle:
draft→published→archived - Public flag for controlling client portal visibility
- Denormalized counters:
view_count,helpful_count,not_helpful_count - Full CRUD for knowledge base articles with org-scoped queries
- Slug lookup with atomic view count increment (no race conditions)
- DOMPurify sanitization on article body before storage
- Text search across title and body fields
- Category listing returning distinct categories for the org
- Public listing endpoint for client portal (published + public articles only)
- Helpful / not helpful feedback with atomic counter increments
- Ticket model with auto-numbered tickets per org (TKT-0001, TKT-0002, …)
- Embedded threaded replies on ticket document
- SLA tracking fields:
first_response_at,sla_due_at - Priority-based SLA computation: urgent=1h, high=4h, medium=8h, low=24h
- Full CRUD for support tickets with org-scoped queries
- Reply functionality with SLA tracking — first staff reply captures
first_response_at - Contact reply automatically reopens tickets in
pendingorresolvedstatus - Internal replies hidden from client-facing responses
- SLA due date auto-computed on ticket creation based on priority level
- KB browsing restricted to published + public articles only
- Ticket creation scoped to authenticated client’s lead
- Ticket viewing returns only the client’s own tickets
- Ticket replying with internal replies stripped from portal responses
- 8 endpoints under
/api/v1/knowledge-base:GET /api/v1/knowledge-base— list articlesPOST /api/v1/knowledge-base— create articleGET /api/v1/knowledge-base/:id— get single articlePUT /api/v1/knowledge-base/:id— update articleDELETE /api/v1/knowledge-base/:id— delete articleGET /api/v1/knowledge-base/slug/:slug— get article by slug (increments view count)GET /api/v1/knowledge-base/categories— list distinct categoriesPOST /api/v1/knowledge-base/:id/feedback— submit helpful/not_helpful feedback
- 6 endpoints under
/api/v1/tickets:GET /api/v1/tickets— list ticketsPOST /api/v1/tickets— create ticketGET /api/v1/tickets/:id— get single ticketPUT /api/v1/tickets/:id— update ticketDELETE /api/v1/tickets/:id— delete ticketPOST /api/v1/tickets/:id/reply— add reply to ticket
- 7 portal endpoints:
GET /portal/knowledge-base— browse published + public articlesGET /portal/knowledge-base/slug/:slug— get article by slugGET /portal/knowledge-base/categories— list categoriesPOST /portal/tickets— create ticketGET /portal/tickets— list own ticketsGET /portal/tickets/:id— get single ticket (internal replies stripped)POST /portal/tickets/:id/reply— reply to ticket
Sprint 18 — 2026-03-21
Section titled “Sprint 18 — 2026-03-21”- Form model with configurable fields, dedup strategy (
create_new/update_existing/skip), round-robin assignment, and reCAPTCHA support - Public submission endpoint rate limited to 5 requests/min per IP
- Public (unauthenticated) form submission with field mapping to lead/contact/custom_field targets
- Dedup by email/phone — duplicate submissions handled per configured strategy (create new, update existing, or skip)
- Round-robin assignment distributes new leads across configured assignees
form.submittedevent emission for workflow trigger evaluation- WebhookSubscription model with encrypted secrets (LAW 4)
- SSRF prevention: HTTPS-only URLs, blocked internal/private IP ranges
- HMAC-SHA256 signed payloads with
X-CRM-Signatureheader for verification - BullMQ worker with 3-attempt exponential backoff on delivery failure
- Failure tracking visible in webhook delivery history
- Listens to 22 domain events and auto-delivers to matching subscriptions
- Org-scoped event filtering — subscriptions only receive events they registered for
- OAuthApp model with UUID
client_idand bcrypt-hashedclient_secret(secret shown only on creation, never retrievable again) - OAuthToken model with SHA-256 hashed access and refresh tokens
- Token scoping for granular permission control
- Full OAuth2 flow: register app → authorize (user consent) → authorization code exchange → token issuance → token revocation
- Authorization codes stored in Redis with 10-minute TTL, single-use enforcement
- 6 endpoints under
/api/v1/forms:GET /api/v1/forms— list formsPOST /api/v1/forms— create formGET /api/v1/forms/:id— get single formPUT /api/v1/forms/:id— update formDELETE /api/v1/forms/:id— delete formPOST /api/v1/forms/:id/submit— public form submission (rate limited, no auth)
- 6 endpoints under
/api/v1/webhooks:GET /api/v1/webhooks— list webhook subscriptionsPOST /api/v1/webhooks— create webhook subscriptionGET /api/v1/webhooks/:id— get single webhook subscriptionPUT /api/v1/webhooks/:id— update webhook subscriptionDELETE /api/v1/webhooks/:id— delete webhook subscriptionPOST /api/v1/webhooks/:id/test— send test webhook delivery
- 6 endpoints under
/api/v1/oauth:POST /api/v1/oauth/apps— register OAuth appGET /api/v1/oauth/apps— list OAuth appsDELETE /api/v1/oauth/apps/:id— delete OAuth appPOST /api/v1/oauth/authorize— authorize (user consent, returns authorization code)POST /api/v1/oauth/token— exchange authorization code for tokensPOST /api/v1/oauth/revoke— revoke OAuth token
Sprint 17 — 2026-03-21
Section titled “Sprint 17 — 2026-03-21”- Context preview endpoint showing reps all extracted data: pain points, goals, objections, competitors, and key phrases with source counts and quality rating (high/medium/low)
- Extracts scope of work from demo notes + activity history via gemini-flash (temperature 0.1)
- Displayed as clickable suggestion in rep wizard
- Rewrites selected text within a section based on instruction
- Splices rewritten text back into section content, preserving surrounding content
- Rewrites section or selected text in formal/conversational/confident/concise/detailed tone via PROMPT 9 (gemini-flash, temperature 0.5)
- Fetches accepted ProposalPatterns filtered by industry + deal size range
- Winning patterns now included in AI prompt context for next proposal generation (learning loop criteria #13)
- Sections with
ai_confidence< 0.7 flagged for “review carefully” (frontend rendering, backend provides the score) - Source evidence per section preserved from AI response, linking generated content to originating calls/activities
- 5 new endpoints under
/api/v1/proposal-ai:GET /api/v1/proposal-ai/context-preview— preview all extracted context data with quality ratingPOST /api/v1/proposal-ai/suggest-scope— AI scope suggestion from demo notes + activity historyPOST /api/v1/proposal-ai/sections/:id/rewrite— inline AI rewrite of selected text within a sectionPOST /api/v1/proposal-ai/sections/:id/tone— tone adjustment for section or selected textGET /api/v1/proposal-ai/patterns— fetch winning patterns by industry + deal size range
Sprint 16 — 2026-03-21
Section titled “Sprint 16 — 2026-03-21”- PortalSession model with SHA-256 hashed magic link tokens (24h expiry, single-use)
- Session JWTs with 8h expiry for authenticated portal access
- Email enumeration prevention — always returns 200 regardless of email existence
- Completely separate auth middleware from staff JWT auth
- Verifies portal session tokens independently from staff authentication flow
- Full magic link lifecycle: email → token generation → hash storage → verify → session JWT
- Tokens are single-use and expire after 24 hours
- SHA-256 hashing ensures tokens are never stored in plaintext
- Dashboard overview showing: pending invoices, open proposals, active projects, unsigned contracts
- All data scoped to the authenticated client’s lead
- Invoice list filtered to visible statuses only (sent, partial, paid, overdue — never drafts)
- Pay via Stripe Checkout session creation
- Pay via Razorpay Order creation
- Proposal viewing with accept/decline actions
- Accept triggers ProposalPattern learning loop for org-level winning pattern capture
- Decline records pattern for future avoidance
- Contract viewing for the authenticated client
- E-signature capture and storage on contracts
- Read-only project view with progress percentage and time summary
- Hourly rates never exposed to client portal users
- Triple scope enforcement on all portal queries:
org_id+lead_id+ visible statuses - Clients can never access data belonging to other leads or other orgs
- 15 endpoints under
/portal:- 2 public auth endpoints (no auth required):
POST /portal/auth/request-magic-link— request magic link emailPOST /portal/auth/verify— verify magic link token and receive session JWT- 13 authenticated endpoints (via
portalAuthmiddleware): GET /portal/dashboard— client dashboard overviewGET /portal/invoices— list visible invoicesGET /portal/invoices/:id— get single invoicePOST /portal/invoices/:id/pay/stripe— initiate Stripe CheckoutPOST /portal/invoices/:id/pay/razorpay— initiate Razorpay OrderGET /portal/proposals— list proposalsGET /portal/proposals/:id— get single proposalPOST /portal/proposals/:id/accept— accept proposalPOST /portal/proposals/:id/decline— decline proposalGET /portal/contracts— list contractsGET /portal/contracts/:id— get single contractPOST /portal/contracts/:id/sign— e-sign contractGET /portal/projects— list projects (read-only, no rates)
Sprint 15 — 2026-03-21
Section titled “Sprint 15 — 2026-03-21”- Project model with embedded members (user_id, hourly_rate, role) and milestones (name, due_date, completion tracking, order)
- Project status lifecycle:
not_started→in_progress→on_hold→completed→cancelled - Billing types:
fixed_rate,hourly,task_based - Denormalized hours tracking (
total_logged_hours,billable_hours,non_billable_hours) recomputed on every time entry mutation - Progress percent computed from Task completion ratio
- TimeEntry model with start/stop timer, manual entry, billable tracking, billed status
- Timer control:
startTimerprevents multiple running timers,stopTimerauto-computes duration - Convert time entries to invoice line items (hours × hourly_rate), marks entries as billed
- Own vs global timesheet permissions (
edit_own_timesheets/edit_timesheets_global) - Reporting
timesheetSummaryupgraded from placeholder to real implementation with 5 time tiles + per-project breakdown - 11 endpoints under
/api/v1/projects:GET /api/v1/projects— list projectsPOST /api/v1/projects— create projectGET /api/v1/projects/:id— get single projectPUT /api/v1/projects/:id— update projectDELETE /api/v1/projects/:id— delete projectPOST /api/v1/projects/:id/members— add memberDELETE /api/v1/projects/:id/members/:userId— remove memberPOST /api/v1/projects/:id/milestones— add milestonePUT /api/v1/projects/:id/milestones/:milestoneId— update milestoneDELETE /api/v1/projects/:id/milestones/:milestoneId— delete milestoneGET /api/v1/projects/:id/time-entries— list time entries for project
- 8 endpoints under
/api/v1/time-entries:POST /api/v1/time-entries/start— start timerPOST /api/v1/time-entries/stop— stop timerPOST /api/v1/time-entries/manual— create manual time entryGET /api/v1/time-entries/active— get currently running timerGET /api/v1/time-entries— list time entriesGET /api/v1/time-entries/:id— get single time entryPUT /api/v1/time-entries/:id— update time entryPOST /api/v1/time-entries/convert-to-invoice— convert time entries to invoice line items
Sprint 14 — 2026-03-21
Section titled “Sprint 14 — 2026-03-21”- Invoice model with embedded line items (qty x unit_price x tax - discount), auto-incrementing numbers per org (INV-0001, INV-0002, …)
- Pre-save hook computing line item totals, subtotal, tax, discount, and grand total automatically
- Recurring invoice support with interval options: weekly, monthly, quarterly, yearly
- Invoice status lifecycle:
draft->sent->partial->paid->overdue - Multi-currency support with org currency storage and customer currency display
- Payment model tracking payments against invoices with gateway support: Stripe, Razorpay, manual
- Reference ID storage for gateway transaction tracking (Stripe payment intent ID, Razorpay payment ID)
- Partial and full payment recording with automatic invoice status transitions
- Item model for product/service catalog with unit pricing and tax rates
- Reusable line items for invoices, estimates, and proposals
- Expense model with billable tracking for client-billable expense management
- Category and receipt attachment support
- CreditNote model with auto-numbering per org (CN-0001, CN-0002, …)
- Issue and apply workflow — credit notes can be applied against invoices to reduce
amount_due - Subscription model with interval-based recurring billing (weekly, monthly, quarterly, yearly)
- Subscription lifecycle management:
active,paused,cancelled - Full CRUD for invoices with org-scoped queries
- Send invoice (marks as
sent, triggers email) - Record payment with partial/full status transitions — partial payments set status to
partial, full payment setspaid - Mark overdue — bulk update for past-due invoices
- Create invoice from estimate — converts accepted estimate line items into invoice
- Process recurring — generates new invoices from recurring templates on schedule
- Stripe Checkout Session creation for online payment collection
- Razorpay Order creation for India-based payment collection
- Stripe webhook with signature verification via
stripe.webhooks.constructEvent— raw body middleware preserves signature integrity - Razorpay webhook with HMAC-SHA256 signature verification
- Both webhooks update invoice status and create Payment records automatically on successful payment
- Applying a credit note to an invoice reduces the invoice
amount_dueby the credit amount - Credit note status transitions on application
- 32 endpoints across 6 route groups + 2 webhook routes:
/api/v1/invoices(7 endpoints) — CRUD, send, record payment, mark overdue/api/v1/payments(2 endpoints) — list payments, get single payment/api/v1/items(5 endpoints) — CRUD for product/service catalog/api/v1/expenses(5 endpoints) — CRUD for expenses/api/v1/credit-notes(5 endpoints) — CRUD + apply credit note to invoice/api/v1/subscriptions(6 endpoints) — CRUD + pause/resume/cancelPOST /api/v1/webhooks/stripe— Stripe payment webhook (signature verified)POST /api/v1/webhooks/razorpay— Razorpay payment webhook (HMAC verified)
Sprint 13 — 2026-03-21
Section titled “Sprint 13 — 2026-03-21”- Proposal model with 9 standard sections, AI confidence scores per section (0–1 range), and source evidence linking sections to originating calls/activities
- Version history with restore capability for any prior version
- Public viewing tokens for unauthenticated client access
- E-signature capture and storage
- Proposal status lifecycle:
draft→sent→accepted/declined - Context assembly from 8 sources (in priority order): call transcripts + AI summaries, custom activity fields, pinned notes, email thread highlights, lead/contact custom fields, opportunity data, org knowledge base, won proposal patterns
- 7 programmatic risk flag rules: no decision maker contact, price objection logged, competitor mentioned, no calls logged, distant start date, no pain points identified, high value opportunity with no case studies
- Full proposal generation via PROMPT 1 (claude-opus, temperature 0.4, 8000 tokens)
- Section-level regeneration via PROMPT 2 — only target section replaced, all others preserved
- All PROMPTS.md rules followed (structured JSON output, validation, graceful fallback)
- Accepted proposals automatically create winning
ProposalPatternrecords for the org - Declined proposals create
patterns_to_avoidentries - Past winning patterns included in context for future proposal generation
- Contract model with dual e-signature support (client + org signer)
- Renewal tracking — contract renewal creates new contract linked to original
- Public links for unauthenticated client viewing and signing
- Expiry date tracking with workflow trigger support for 30-day renewal reminders
- Estimate model with line items: quantity × unit_price × tax_rate − discount
- Auto-computed totals (subtotal, tax, discount, total) via Mongoose pre-save hook
- Auto-generated estimate numbers per org (EST-0001, EST-0002, …)
- Convert-to-invoice preparation for Sprint 14 integration
- Proposal accept/decline/sign via public token
- Contract sign via public token
- Estimate accept via public token
- 30 endpoints across 3 route groups:
/api/v1/proposals(11 endpoints) — CRUD, AI generate, section regenerate, public view/accept/decline/sign, version restore/api/v1/contracts(9 endpoints) — CRUD, public view/sign, renew/api/v1/estimates(10 endpoints) — CRUD, public view/accept, convert-to-invoice
Sprint 12 — 2026-03-21
Section titled “Sprint 12 — 2026-03-21”callAI<T>()utility implementing all 7 PROMPTS.md rules — never throws on failure- Strips markdown fences from AI responses before JSON parsing
- Extracts JSON from prose when AI wraps output in explanatory text
- Model routing: gemini-flash (cheap tasks), claude-sonnet (standard tasks), claude-opus (premium tasks)
- Temperature presets per task type (0.0 for enrichment, 0.5 for creative drafts)
truncateMiddleutility for prompt overflow prevention — keeps start and end context- BullMQ worker with concurrency 3, rate limited to 10 jobs/min
- Enriches custom fields flagged with
ai_enrich_enabledvia cheap model (gemini-flash) at temperature 0.0 - Confidence level included in enrichment response
- Triggered automatically after lead creation via event handler
- Gathers lead + contacts + recent activities + opportunities as context
- Returns structured summary with pain points, objections, relationship health, and close probability
- Max 200 words, generated via standard model
- Analyzes call transcripts after recording ready (triggered by calling worker)
- Returns sentiment, action items, confidence score, and call outcome
- Stored on Activity record alongside recording URL
- Generates subject + HTML body + preview text from lead context and knowledge base
- Creative temperature (0.5) for natural-sounding drafts
- NEVER auto-sends — human-in-the-loop rule enforced (draft mode only)
- Converts natural language description to valid workflow JSON definition
- Output validated against workflow schema before use
- AI output sanitized before storage (XSS prevention via DOMPurify)
- All AI responses validated before use — malformed responses trigger graceful fallback
- Graceful error handling: user sees “AI unavailable, please try manually” on failure
- 4 endpoints under
/api/v1/ai:POST /api/v1/ai/lead-summary— generate structured lead summaryPOST /api/v1/ai/lead-enrich— trigger AI enrichment for lead custom fieldsPOST /api/v1/ai/email-draft— generate email draft from lead contextPOST /api/v1/ai/workflow-suggest— convert natural language to workflow JSON
Sprint 11 — 2026-03-21
Section titled “Sprint 11 — 2026-03-21”- Activity count by type with date range and user/type filters
- Drill-through support — clicking a tile shows matching leads
- Per-user rankings for calls, emails, meetings, tasks completed, opportunities won, and revenue
- User name population for display
- Requires
view_globalpermission — non-global users cannot access - Breakdown by status: completed, missed, voicemail, no_answer
- Total and average call duration metrics
- Sent and received counts
- Open, click, reply, and bounce rates
- Per-pipeline stage conversion rates
- Stages ordered by pipeline status sequence
- Formula: (N x W x V) / L — number of deals x win rate x avg deal value / avg cycle length in days
- Win rate, average deal value, and average cycle days computed from opportunity data
- Placeholder structure with 5 tiles (Total, Last Month, This Month, Last Week, This Week)
- Actual implementation deferred to Sprint 15 (Projects + Time Tracking)
- Gated by
view_timesheets_reportpermission view_ownscope enforcement: non-global users restricted to their own data across all reporting endpoints- All reporting queries scoped by
org_id(LAW 3) - All endpoints support
start_dateandend_datequery parameters - Date range filters are inclusive on both boundaries
- 7 GET endpoints under
/api/v1/reporting:GET /api/v1/reporting/activity-summary— activity count tiles by typeGET /api/v1/reporting/leaderboard— per-user performance rankingsGET /api/v1/reporting/call-outcomes— call status breakdown with durationGET /api/v1/reporting/email-stats— email sent/received and engagement ratesGET /api/v1/reporting/opportunity-funnel— per-pipeline stage conversion ratesGET /api/v1/reporting/sales-velocity— sales velocity formula computationGET /api/v1/reporting/timesheet-summary— timesheet tiles (placeholder)
Sprint 10 — 2026-03-21
Section titled “Sprint 10 — 2026-03-21”- SmsTemplate model with merge tag support (
{{CONTACT_FIRST_NAME}},{{LEAD_NAME}}, etc.) - Template CRUD service for managing reusable SMS templates per org
- Opt-out check before every send — opted-out contacts blocked
- A2P 10DLC compliance gate for US numbers — SMS blocked if compliance not approved
- Twilio
messages.createintegration for outbound delivery - Activity creation with correct direction and status on send
- Lead denormalized counter updates (
sms_count,last_activity_date,last_comm_date) - Org resolution from Twilio
Tonumber (never trusts client-suppliedorg_id) - Contact matching by sender phone number
- Activity creation for inbound messages with
sms_direction: "inbound" sms.receivedevent emission for workflow trigger evaluation- Chronological, paginated conversation view between org number and contact
- Messages displayed in thread order with direction indicators
- Merge tag replacement engine substituting
{{CONTACT_FIRST_NAME}},{{LEAD_NAME}}, and other tags with live entity data - Inbound SMS webhook with
verifyTwilioWebhookmiddleware (LAW 5) - 2 SMS endpoints:
POST /api/v1/sms/send— send outbound SMSGET /api/v1/sms/conversation— get threaded SMS conversation
- 5 SMS template endpoints:
GET /api/v1/sms-templates— list SMS templatesPOST /api/v1/sms-templates— create SMS templateGET /api/v1/sms-templates/:id— get single SMS templatePUT /api/v1/sms-templates/:id— update SMS templateDELETE /api/v1/sms-templates/:id— delete SMS template
Sprint 9 — 2026-03-21
Section titled “Sprint 9 — 2026-03-21”verifyTwilioWebhookmiddleware enforcing LAW 5 on all Twilio webhook routes- Unsigned/tampered webhook requests rejected with 403
- PhoneNumber model (E.164 format, Twilio SID, capabilities, user/menu/group assignment)
- PhoneMenu model (IVR: greeting TwiML, digit options, timeout, max retries, fallback actions)
- PhoneGroup model (ring groups:
simultaneous,round_robin,sequentialstrategies) - DialerSession model (Power Dialer state tracking with lead queue and progress)
- ComplianceBundle model (STIR/SHAKEN verification + A2P 10DLC registration status)
- Twilio capability token generation for WebRTC softphone connections
- Outbound dial with call activity creation (
call_direction: "outbound") - Voice webhook handler generating TwiML for call routing
- Status callback webhook updating call duration, status, and recording URL on activity
- Recording webhook storing recording URL and triggering AI summary worker
- Hangup endpoint for active call termination
- Voicemail drop for pre-recorded audio playback
- Start dialer session from Smart View with 500 lead cap
- Next lead auto-dial after hang-up with session state management
- Stop/pause dialer session
- Session progress tracking (dialed count, connected count, voicemail count)
- TwiML generation for phone menus with greeting and digit option routing
- Digit routing to: user extension, ring group, sub-menu, external number, voicemail
- Timeout and max-retry handling with configurable fallback actions
- Nested menu support for multi-level IVR trees
- 5 Twilio webhook endpoints (ALL with
verifyTwilioWebhook— LAW 5):POST /api/v1/calling/webhooks/voice— voice webhookPOST /api/v1/calling/webhooks/status— status callbackPOST /api/v1/calling/webhooks/recording— recording readyPOST /api/v1/calling/webhooks/gather— IVR digit gatherPOST /api/v1/calling/webhooks/fallback— error fallback
- 7 calling endpoints:
POST /api/v1/calling/token— get Twilio capability tokenPOST /api/v1/calling/dial— initiate outbound callPOST /api/v1/calling/hangup— terminate active callPOST /api/v1/calling/voicemail-drop— drop voicemailPOST /api/v1/calling/power-dialer/start— start power dialer sessionPOST /api/v1/calling/power-dialer/next— dial next lead in sessionPOST /api/v1/calling/power-dialer/stop— stop power dialer session
- Phone menu CRUD:
GET/POST/PUT/DELETE /api/v1/phone-menus - Phone group CRUD:
GET/POST/PUT/DELETE /api/v1/phone-groups - Compliance routes:
GET /api/v1/compliance/status— STIR/SHAKEN + A2P 10DLC statusPOST /api/v1/compliance/submit— submit compliance bundle
requireFeature('calling')gate on all calling routes
Sprint 8 — 2026-03-21
Section titled “Sprint 8 — 2026-03-21”- ConnectedAccount model with AES-256-GCM encrypted OAuth tokens (LAW 4)
toJSONtransform strips encrypted token fields from API responses (LAW 8)- UnsubscribedEmail model for opt-out tracking per org
- EmailTemplate model with merge tag support and DOMPurify sanitization
- Full CRUD with encrypted token storage
- Internal-only decryption — tokens never exposed via API
- OAuth token refresh handling
- Unsubscribe check before every send — unsubscribed contacts silently skipped with log
- Redis-based rate limiting (100/hr, 500/day per account)
- SMTP via nodemailer with OAuth2 transport (Gmail/Outlook)
- Open tracking pixel injection into outbound emails
- Click tracking link wrapping for all outbound links
- UUID-based tracking IDs stored in Redis with 90-day TTL
- Open/click status updates on Activity records
- All tracking queries scoped by
org_id - Zod-validated Postmark webhook for inbound email ingestion
- Org resolution from recipient address (never trusts client-supplied
org_id) - Contact matching by sender email address
- Thread detection via
In-Reply-To/Referencesheaders - Lead auto-creation for unknown senders
- HMAC-signed state parameter for OAuth callback forgery prevention
- Open redirect prevention on click tracking (http/https-only validation)
- Public unsubscribe endpoint with base64url token decoding
- 3 new route groups with 17 endpoints total:
/api/v1/email(9 endpoints) — send, connected accounts CRUD, OAuth callbacks, tracking/api/v1/email-templates(5 endpoints) — template CRUD/api/v1/unsubscribes(3 endpoints) — unsubscribe managementGET /api/v1/unsubscribe/:token— public unsubscribe endpoint (no auth required)
Sprint 7 — 2026-03-21
Section titled “Sprint 7 — 2026-03-21”- Workflow model with trigger definitions supporting 11 trigger types:
lead_status_change,custom_activity_created,opportunity_stage_changed,form_submitted,manual,lead_created,contact_created,email_received,call_completed,task_completed,tag_added - Step definitions supporting 9 step types:
email,sms,task,call_task,update_lead,create_opportunity,wait,webhook,condition - Goal definitions for automatic run completion on desired outcomes
- Communication windows with timezone-aware scheduling enforcement
- Blackout date configuration to suppress step execution on specified dates
- WorkflowRun model tracking execution state (
running,completed,failed,goal_met,cancelled) - Step logs with timestamps recording each step’s execution result
- Enrollment metadata capturing trigger context and lead/contact references
workflow-triggersqueue for evaluating domain events against active workflowsworkflow-stepsqueue for executing individual workflow steps- Typed job data interfaces for both queues
- EventEmitter2 to BullMQ bridge mapping 9 domain events to workflow trigger types
- Automatic enqueuing of trigger evaluation jobs when domain events fire
- Matches incoming domain events to active workflows by trigger type
- Evaluates trigger conditions (e.g., only fire if status = “qualified”)
- Respects
run_mode:onceprevents duplicate enrollment,multipleallows re-enrollment after completion - Creates WorkflowRun and enqueues first step on successful match
- Executes 8 step types:
task,call_task,update_lead,create_opportunity,wait,email,sms,webhook - Communication window enforcement with timezone-aware scheduling via
Intl.DateTimeFormat - Blackout date respect — steps delayed past blackout dates to next valid window
- Step logging with execution timestamps and result metadata
- 3-retry with exponential backoff on step failures
isWithinWindow— checks if current time falls within configured send windowgetNextValidSlot— calculates next valid execution time respecting window + blackout datesisBlackoutDate— checks if a date falls on a configured blackout date- All functions timezone-aware via
Intl.DateTimeFormat - Listens for
reply_received,call_completed,meeting_booked,opportunity_wonevents - Marks matching workflow runs as
goal_met - Cancels pending BullMQ jobs for completed runs
- Full CRUD for workflow definitions with activation/deactivation toggle
- Manual enrollment endpoint for enrolling leads into workflows from lead profile
- Run listing with filtering by workflow and status
- Workflow stats endpoint returning enrollment count, completion rate, goal met percentage
requireFeature('workflows')gate on all routes — Growth+ plans onlyGET /api/v1/workflows— list workflows for orgPOST /api/v1/workflows— create workflowGET /api/v1/workflows/:id— get single workflowPUT /api/v1/workflows/:id— update workflowDELETE /api/v1/workflows/:id— delete workflowPOST /api/v1/workflows/:id/activate— activate workflowPOST /api/v1/workflows/:id/deactivate— deactivate workflowPOST /api/v1/workflows/:id/enroll— manually enroll a leadGET /api/v1/workflows/:id/runs— list runs for workflowGET /api/v1/workflows/:id/stats— get workflow statistics
Sprint 6 — 2026-03-21
Section titled “Sprint 6 — 2026-03-21”- CustomActivityType model with embedded field definitions supporting 10 field types:
text,number,date,boolean,choice,multi_choice,rich_text,url,email,phone - Fields support required/optional flag, choices arrays (for choice types), display order, and AI enrich prompts
field_keyauto-generated from field label for programmatic access- Full CRUD for custom activity type definitions with field validation
- Choice-type fields require a non-empty
choicesarray — rejected at validation otherwise - Field immutability protection — cannot remove fields that are already used in existing activity instances
- Instance creation via
POST /api/v1/custom-activity-types/:id/instances— validates all field values against type definitions - Required fields enforced on instance creation — missing required fields return 400
- Date fields converted to
Dateobjects (never stored as strings) - Rich text fields sanitized with DOMPurify before storage
- Single-write instance creation —
custom_activity_type_idpassed in initial Activity create (no two-step process) - Integrates with existing Activity model (
type='custom',custom_activity_type_idlinkage) custom_activity.createdevent emission for workflow trigger evaluationrequireFeature('custom_activities')gate on all routes — Solo plan excludedGET /api/v1/custom-activity-types— list custom activity types for orgPOST /api/v1/custom-activity-types— create custom activity typeGET /api/v1/custom-activity-types/:id— get single custom activity typePUT /api/v1/custom-activity-types/:id— update custom activity typeDELETE /api/v1/custom-activity-types/:id— delete custom activity typePOST /api/v1/custom-activity-types/:id/instances— create activity instance of this type
Sprint 5 — 2026-03-21
Section titled “Sprint 5 — 2026-03-21”- Polymorphic Activity model supporting 13 types:
call,email,email_thread,sms,whatsapp,meeting,note,task_completed,lead_status_change,opportunity_status_change,lead_merge,form_submission,custom - Activity CRUD with type-specific creation endpoints:
/note,/call,/email,/sms,/meeting,/custom - Activity pinning — pinned items sort to top of feed
- Activity filter by type on feed endpoint
- Lead denormalized counter updates (
call_count,email_count,sms_count,last_activity_date,last_comm_date) recomputed via recount on activity create/delete (not increment/decrement) - Task model with assignment, due dates, priorities (
low,normal,high,urgent), and completion tracking - Task completion creates a
task_completedActivity automatically on the linked lead has_future_taskrecomputation on all task mutations (create, update, complete, delete)- Workflow-created tasks support
workflow_run_idlinkage - Comment model with DOMPurify-sanitized rich text content
- Validated
@mentionsscoped to org members only - Comment CRUD on leads:
GET/POST /api/v1/leads/:id/comments,PUT/DELETE /api/v1/leads/:id/comments/:commentId - File model for S3 attachment metadata storage
- Presigned URL generation for uploads and time-limited downloads
- Unified Inbox endpoint aggregating missed calls, inbound emails/messages, and due/overdue tasks
- Tab filtering: Primary, Calls, Emails, Messages, Tasks
- Socket.io server with JWT-based authentication
- Room architecture: org-level, user-level, and lead-level rooms
- Cross-tenant
join:leadvalidation — users can only join rooms for leads in their org - Real-time activity feed updates, task assignment notifications, and inbox sync across tabs
GET /api/v1/activity— list activities (filterable by lead, type, pinned)POST /api/v1/activity/note— create note activityPOST /api/v1/activity/call— create call activityPOST /api/v1/activity/email— create email activityPOST /api/v1/activity/sms— create sms activityPOST /api/v1/activity/meeting— create meeting activityPOST /api/v1/activity/custom— create custom activityGET /api/v1/activity/:id— get single activityPUT /api/v1/activity/:id— update activityDELETE /api/v1/activity/:id— delete activityPOST /api/v1/activity/:id/pin— pin/unpin activityGET /api/v1/tasks— list tasks (filterable by assignee, status, due date)POST /api/v1/tasks— create taskGET /api/v1/tasks/:id— get single taskPUT /api/v1/tasks/:id— update taskPOST /api/v1/tasks/:id/complete— complete taskDELETE /api/v1/tasks/:id— delete taskGET /api/v1/leads/:id/comments— list comments on leadPOST /api/v1/leads/:id/comments— create comment on leadPUT /api/v1/leads/:id/comments/:commentId— update commentDELETE /api/v1/leads/:id/comments/:commentId— delete commentGET /api/v1/inbox— unified inbox with tab filtering
Sprint 4 — 2026-03-21
Section titled “Sprint 4 — 2026-03-21”- Pipeline model with embedded statuses supporting three types:
active,won, andlost - Default pipeline seeded automatically on org creation
- Pipeline CRUD with default promotion — deleting the default pipeline promotes another to default
- Deletion guards: cannot delete a pipeline that has linked opportunities or is the only pipeline
multiple_pipelinesfeature gate — Solo plan limited to 1 pipeline, Essentials+ can create multiple- Opportunity model linked to Lead and Pipeline with
status_typedenormalization - Opportunity CRUD with status transition tracking:
won_at,lost_at,lost_reasoncaptured on status changes Lead.open_opportunity_countautomatically recomputed on opportunity create, update, and deleteclose_daterange filtering on opportunity list endpointview_ownscope enforcement on all opportunity endpointsGET /api/v1/pipelines— list all pipelines for orgPOST /api/v1/pipelines— create pipeline (feature-gated for multiple)GET /api/v1/pipelines/:id— get single pipeline with embedded statusesPUT /api/v1/pipelines/:id— update pipelineDELETE /api/v1/pipelines/:id— delete pipeline (with guards)GET /api/v1/opportunities— list opportunities (filterable by pipeline, status, close_date range)POST /api/v1/opportunities— create opportunityGET /api/v1/opportunities/:id— get single opportunityPUT /api/v1/opportunities/:id— update opportunity (with status transition tracking)DELETE /api/v1/opportunities/:id— delete opportunity
Sprint 3 — 2026-03-21
Section titled “Sprint 3 — 2026-03-21”- Filter DSL engine that compiles user-defined filter JSON into MongoDB aggregation pipelines
- 12 filter operators:
eq,neq,gt,lt,gte,lte,in,nin,exists,not_exists,contains,activity_exists/activity_not_exists - Relative date resolution:
now,now-3d,now-1w,now-1m,now+7d $current_userplaceholder resolution to authenticated user’s_id$lookupfor activities (200 limit), tasks, and opportunities withorg_idenforcement in sub-pipelines- AND/OR logic composition for combining filter conditions
- Custom field filtering via
custom_fieldsMap - Regex injection prevention via
escapeRegex - Safe-character validation on
activity_typeandactivity_field view_ownscope enforcement injected into aggregation pipeline- SmartView model with visibility levels:
private,team,org - Pin/unpin support for sidebar display
- Configurable display columns per view
- Smart view execution always live — re-executed on each request, no stale cache
- “Bucket behavior” — leads automatically move in/out of views as underlying data changes
GET /api/v1/smart-views— list smart views visible to current userPOST /api/v1/smart-views— create smart viewGET /api/v1/smart-views/:id— get single smart viewPUT /api/v1/smart-views/:id— update smart viewDELETE /api/v1/smart-views/:id— delete smart viewGET /api/v1/smart-views/:id/results— execute smart view and return paginated resultsPOST /api/v1/smart-views/:id/pin— pin smart view to sidebarPOST /api/v1/smart-views/:id/unpin— unpin smart view from sidebarPOST /api/v1/smart-views/preview— preview filter results without saving
Sprint 2 — 2026-03-21
Section titled “Sprint 2 — 2026-03-21”- Lead CRUD with
org_idscoping — org_id always set fromreq.org._id, never from request body - Pagination, text search, and sort whitelist on lead list endpoint
- Cross-org lead access returns 404 (not 403) to prevent existence leakage
- Lead status management configurable per org with 4 default statuses seeded on org creation
- Lead status change creates
lead_status_changeactivity automatically - Bulk status change operations — all selected leads updated with one activity per lead
view_ownscope enforcement on leads (list, detail, edit, delete)- Orphan cleanup: deleting a lead removes all associated contacts
- Lead import from CSV with field mapping and duplicate skip by email
- Contact CRUD linked to leads with
lead_idvalidated against same org - Multiple contacts per lead returned in lead detail response
- Primary contact flag enforced — only one primary contact per lead
- Email format validated via Zod before storage
- Custom field definitions supporting 10 types: text, number, date, boolean, choice, multi_choice, rich_text, url, email, phone
- Custom field CRUD for lead, contact, opportunity, and activity entity types
- Type checking and required field validation — missing required custom field returns 400
- Choice validation — only defined choices accepted as values
- DOMPurify sanitization for
rich_texttype fields before storage - Shared custom fields appearing on both lead and contact profiles
- Field display order respected in API responses
- Custom fields stored as Map on parent documents with correct type retrieval
GET/POST /api/v1/leads— list (paginated, searchable, sortable) and createGET/PUT/DELETE /api/v1/leads/:id— get, update, delete single leadPOST /api/v1/leads/bulk— bulk status changeGET/POST /api/v1/contacts— list and create contactsGET/PUT/DELETE /api/v1/contacts/:id— get, update, delete single contactGET/POST /api/v1/custom-fields— list and create custom field definitionsGET/PUT/DELETE /api/v1/custom-fields/:id— get, update, delete custom field definitionsGET/POST /api/v1/lead-statuses— list and create lead statusesGET/PUT/DELETE /api/v1/lead-statuses/:id— get, update, delete lead statuses
Sprint 1 — 2026-03-20
Section titled “Sprint 1 — 2026-03-20”- JWT-based auth with 15-minute access tokens and httpOnly refresh token cookies
- Refresh token rotation with SHA-256 hashing stored in Redis (not MongoDB)
- Login, logout, register, forgot-password, and reset-password endpoints
- Tampered/expired token detection returning 401
- Org creation with automatic seeding of 4 system roles: Admin, Super User, Employee, Restricted
- Secret email address generation per org (
orgslug-hash@leads.domain.com) - Onboarding checklist defaults applied on creation
- Org settings (timezone, currency, plan) loaded into
req.orgvialoadOrgmiddleware - User invite flow with 48-hour token expiry and password-set step
- Invited users receive unguessable placeholder password (not empty string)
- Self-role-change and self-permission-change blocked to prevent privilege escalation
- User CRUD scoped by
staff.view_own/staff.view_globalpermissions - Full RBAC with per-user overrides on top of role defaults
- Permission resolution order: system admin > per-user override > role default > 403
_resolved_permissionscache on User document, rebuilt on role or override changerequirePermissionmiddleware enforcing capability checks on every routeapplyScopeFilterfor own-vs-global record visibilityrequireFeaturemiddleware returning 402plan_upgrade_requiredfor ungated featuresrole_based_accessadded as Scale-only feature for custom role creation- Feature flag GraphQL query returning boolean map for current org plan
auth.service.ts— login, register, token refresh, password resetorg.service.ts— org creation with role seedinguser.service.ts— invite, CRUD, role assignment, permission overridesrole.service.ts— role CRUD, system role protectionpermission.service.ts— resolution, caching, override managementeventLog.service.ts— immutable audit trail logging- Apollo Server 4 setup at
/api/graphql - Schema with
CurrentUserQueryandFeatureFlagsQuery - Auth-aware context with DataLoader-ready structure
POST /api/v1/auth/login— authenticate and receive tokensPOST /api/v1/auth/register— create org + admin userPOST /api/v1/auth/refresh— rotate refresh tokenPOST /api/v1/auth/logout— clear refresh token cookiePOST /api/v1/auth/forgot-password— initiate password resetPOST /api/v1/auth/reset-password— complete password resetGET/POST/PUT/DELETE /api/v1/users— user managementGET/POST/PUT/DELETE /api/v1/roles— role managementGET/PUT /api/v1/org— org settingsGET /health— unauthenticated health check
Sprint 0 — 2026-03-20
Section titled “Sprint 0 — 2026-03-20”- Node.js 22 + TypeScript 5.x strict mode (
tsconfig.json) - Express 4.x HTTP server with helmet, CORS, and rate limiting
package.jsonwith all locked dependencies per tech stacksrc/config/env.ts— Zod-validated environment variables; server crashes on missing varssrc/config/db.ts— MongoDB connection via Mongoose 8.xsrc/config/redis.ts— Redis connection via ioredis 5.xsrc/config/constants.ts— centralized auth constants (token expiry, bcrypt rounds, etc.)docker-compose.yml— MongoDB + Redis local dev environment.env.example— all required environment variables documented.gitignore— excludes.env,node_modules/,dist/, secretsauth.ts— JWT verification, setsreq.userloadOrg.ts— loads org from user’sorg_id, setsreq.orgrequirePermission.ts— RBAC capability checkrequireFeature.ts— plan-based feature gatingvalidate.ts— Zod schema validation for request bodiessrc/lib/crypto.ts— AES-256-GCM encrypt/decrypt for sensitive data at restsrc/lib/logger.ts— structured logging (no sensitive data)src/lib/errors.ts— typed error classes (AppError, NotFoundError, ForbiddenError, etc.)src/lib/eventLog.ts— event log helpersrc/events/emitter.ts— EventEmitter2 event bus for internal pub/subsrc/types/express.d.ts— Express request augmentation (req.user,req.org)src/types/permission.ts— permission system type definitions