Petunia Architecture Migration Plan
Version: 2.0.0 Last Updated: 2025-12-13 Reference: See ARCHITECTURE.md for ideal state
This document contains the complete migration plan to align the current Petunia codebase with the ideal architecture. Items are prioritized P0 (critical) through P5 (documentation).
✅ Migration Status Summary
| Priority | Total | ✅ Done | 🔄 Partial | ❌ Pending | Progress |
|---|---|---|---|---|---|
| P0 | 12 | 12 | 0 | 0 | 100% |
| P1 | 15 | 12 | 1 | 2 | 87% |
| P2 | 12 | 9 | 1 | 2 | 79% |
| P3 | 12 | 8 | 1 | 3 | 71% |
| P4 | 14 | 3 | 2 | 9 | 29% |
| P5 | 10 | 10 | 0 | 0 | 100% |
| Total | 75 | 54 | 5 | 16 | 79% |
Quick Status Reference
P0 - Critical (12/12 Complete) ✅
| ID | Item | Status | Notes |
|---|---|---|---|
| P0-1 | Client.companyId FK | ✅ Done | FK relation added to schema |
| P0-2 | Fix Orphaned CompanyIds | ✅ Done | cron/orphan-cleanup/route.ts runs hourly |
| P0-3 | Delete Orphaned Records | ✅ Done | Handled by orphan-cleanup cron job |
| P0-4 | Encrypt MFA Secret | ✅ Done | mfa-secret-encryption.ts + tests + migration |
| P0-5 | Encrypt OAuth Tokens | ✅ Done | oauth-token-encryption.ts + middleware |
| P0-6 | Encrypt Integration Tokens | ✅ Done | integration-token-encryption.ts + middleware |
| P0-7 | Fix Billing Race Condition | ✅ Done | credit-wallet-service.ts uses $transaction |
| P0-8 | Portal.clientId Required FK | ✅ Done | Commit cca045791 |
| P0-9 | Portal→Client→Company Chain | ✅ Done | Chain validated via P0-1 + P0-8 |
| P0-10 | Atomic Webhook Processing | ✅ Done | idempotencyKey with @unique in schema |
| P0-11 | Request Signing | ✅ Done | internal-api-auth.ts + request-signing.ts with HMAC-SHA256 |
| P0-12 | Session Token Security | ✅ Done | sessionRotation.ts with privilege change detection |
P1 - High (12/15 Complete)
| ID | Item | Status | Notes |
|---|---|---|---|
| P1-1 | Redis Rate Limiting | ✅ Done | rate-limiter.ts with Upstash Redis, sliding window |
| P1-2 | Product.businessId → companyId | ❌ Pending | Requires schema migration |
| P1-3 | Service.businessId → companyId | ❌ Pending | Requires schema migration |
| P1-4 | Lead Merge Transaction | ✅ Done | leadService.prisma.ts:929 uses $transaction |
| P1-5 | Missing FK Indexes | ✅ Done | 50+ @@index directives in schema |
| P1-6 | PortalAnalyticsSummary clientId | 🔄 Partial | NOT NULL constraint pending |
| P1-7 | Demo Portal Data Chain | ✅ Done | Demo data structure exists |
| P1-8 | Seed KnowledgeBaseEntry | ✅ Done | Knowledge base seeding in place |
| P1-9 | Standardize API Response | ✅ Done | api-response.ts with requestId and pagination |
| P1-10 | VACUUM ANALYZE | ✅ Done | Automated via database maintenance |
| P1-11 | Connection Pool Monitoring | ✅ Done | prometheusMetrics.ts tracks pool stats |
| P1-12 | Graceful Shutdown | ✅ Done | graceful-shutdown.ts with SIGTERM handler |
| P1-13 | Database Query Timeout | ✅ Done | database.ts has statement_timeout configured |
| P1-14 | Circuit Breaker | ✅ Done | api-circuit-breaker.ts + circuit-breaker.ts |
| P1-15 | Structured Error Codes | ✅ Done | error-codes.ts with domain-specific codes |
P2 - Medium (9/12 Complete)
| ID | Item | Status | Notes |
|---|---|---|---|
| P2-1 | Remove Type Safety Bypasses | ❌ Pending | Ongoing improvement |
| P2-2 | Deduplication Algorithm | ✅ Done | deduplication-service.ts with confidence scoring |
| P2-3 | Admin Status Cache TTL | ✅ Done | withAuth.ts has 60-second cache |
| P2-4 | Device Fingerprinting | ✅ Done | device-fingerprint.ts with trust levels |
| P2-5 | Portal→PortalAIConfig 1:1 | ✅ Done | Commit 818039065 |
| P2-6 | Rename Business Model | 🔄 Assessment | Decision needed on naming |
| P2-7 | CommissionTransaction Cleanup | ❌ Pending | Polymorphic design intentional |
| P2-8 | Multi-Tenant Middleware | ✅ Done | multi-tenant-middleware.ts |
| P2-9 | TypeScript Strict Mode | ✅ Done | Strict mode enabled in tsconfig |
| P2-10 | Date/Time Handling | ✅ Done | dates.ts with comprehensive timezone support |
| P2-11 | Zod Validation | ✅ Done | 102+ routes have Zod validation |
| P2-12 | Proper Enum Types | ✅ Done | Prisma enums in schema |
P3 - Standard (8/12 Complete)
| ID | Item | Status | Notes |
|---|---|---|---|
| P3-1 | Clean Unused Indexes | ✅ Done | Index audit completed, unused indexes removed |
| P3-2 | Standardize Pagination | ✅ Done | Standard pagination pattern across APIs |
| P3-3 | Audit Log Retention | ❌ Pending | Retention policy definition needed |
| P3-4 | API Versioning Doc | ✅ Done | API_VERSIONING.md exists |
| P3-5 | Distributed Tracing | 🔄 Partial | Sentry tracing configured |
| P3-6 | SLO/SLA Definitions | ✅ Done | apiSlo.ts defines critical SLOs |
| P3-7 | Test Coverage Report | ❌ Pending | Coverage reporting setup needed |
| P3-8 | Dead Code Audit | ❌ Pending | Needs tooling setup |
| P3-9 | Request ID in Logs | ✅ Done | requestContext.server.ts |
| P3-10 | Log Aggregation | ✅ Done | Centralized logging via Sentry + Vercel |
| P3-11 | Health Check Dependencies | ✅ Done | health-checker.ts with comprehensive checks |
| P3-12 | Runbooks | ✅ Done | Various runbooks created |
P4 - Lower (3/14 Complete)
| ID | Item | Status | Notes |
|---|---|---|---|
| P4-1 | Rename organizationId to portalId | ❌ Pending | Schema migration needed |
| P4-2 | KnowledgeBaseEntry companyId | ❌ Pending | |
| P4-3 | Vector Namespace Restructure | ❌ Pending | |
| P4-4 | Lead.clientId FK | 🔄 Partial | Relation exists, optional |
| P4-5 | Consolidate Subscription Fields | ❌ Pending | |
| P4-6 | Knowledge Tier Architecture | ✅ Done | KNOWLEDGE_ARCHITECTURE.md |
| P4-7 | Input Validation Consistency | 🔄 Partial | Via P2-11 |
| P4-8 | N+1 Query Patterns | ❌ Pending | |
| P4-9 | Soft Delete Models | ❌ Pending | |
| P4-10 | Created/Updated By Fields | ❌ Pending | |
| P4-11 | Phone Number Normalization | ✅ Done | phone.ts with E.164 format support |
| P4-12 | Email Normalization | ✅ Done | email.ts with validation + domain extraction |
| P4-13 | Status Enum Consolidation | ❌ Pending | |
| P4-14 | Optimistic Locking | ❌ Pending |
P5 - Documentation (10/10 Complete)
| ID | Item | Status | Notes |
|---|---|---|---|
| P5-1 | Webhook Documentation | ✅ Done | Merged into API_INTEGRATION_GUIDE.md |
| P5-2 | Integration Monitoring | ✅ Done | INTEGRATION_MONITORING.md |
| P5-3 | Voice AI Setup | ✅ Done | VOICE_AI_SETUP.md |
| P5-4 | Call Recording Storage | ✅ Done | CALL_RECORDINGS.md |
| P5-5 | RLS Policies | ✅ Done | RLS_POLICIES.md |
| P5-6 | Developer Guide | ✅ Done | DEVELOPER_GUIDE.md |
| P5-7 | Background Jobs | ✅ Done | BACKGROUND_JOBS.md |
| P5-8 | API Integration Guide | ✅ Done | API_INTEGRATION_GUIDE.md |
| P5-9 | Database Migrations | ✅ Done | DATABASE_MIGRATIONS.md |
| P5-10 | Security Guide | ✅ Done | SECURITY_GUIDE.md |
Table of Contents
- Priority Overview
- P0: Critical - Data Integrity & Security
- P1: High - Core Infrastructure
- P2: Medium - Type Safety & Model Refinement
- P3: Standard - Cleanup & Observability
- P4: Lower - Schema & Validation
- P5: Documentation
- Dependencies Graph
- Migration Execution Notes
Priority Overview
| Priority | Items | Focus Area | Risk Level | Status |
|---|---|---|---|---|
| P0 | 12 | FK constraints, encryption, race conditions | HIGH - Data loss/security | ✅ 100% |
| P1 | 15 | Rate limiting, model migration, indexes | MEDIUM - Performance/stability | ✅ 87% |
| P2 | 12 | Type safety, model renaming, access control | MEDIUM - Code quality | ✅ 79% |
| P3 | 12 | Cleanup, standardization, observability | LOW - Technical debt | ✅ 71% |
| P4 | 14 | Schema refinement, validation, optimization | LOW - Enhancement | 🔄 29% |
| P5 | 10 | Documentation, runbooks, guides | LOW - Knowledge | ✅ 100% |
Total: 75 migration items | 54 Complete | 5 Partial | 16 Pending (79% overall)
P0: Critical - Data Integrity & Security
These items address data integrity issues, security vulnerabilities, and race conditions that could cause data loss or security breaches.
P0-1: Fix Client.companyId Foreign Key
Problem: Client.companyId is a String @default("default") with no FK constraint. This allows orphaned clients and breaks the entity chain.
Current State:
model Client {
companyId String @default("default") // No FK!
}
Target State:
model Client {
companyId String
Company Company @relation(fields: [companyId], references: [id])
}
Steps:
- Audit all clients with
companyId = "default"(currently 22+) - Create "orphan" company for existing orphans OR assign to correct companies
- Add FK constraint in Prisma schema
- Run migration with
prisma migrate dev - Verify no broken references
Files: /prisma/schema.prisma
Depends On: P0-2 (data migration first)
Effort: Medium
P0-2: Data Migration - Fix Orphaned Client CompanyIds
Problem: 22+ orphaned clients have companyId = "default" which will break when FK is added.
Steps:
- Query all clients with
companyId = "default" - For each, determine correct company via UserCompany or create one
- Update
companyIdto valid company - Verify all clients have valid company references
- Document any clients that couldn't be assigned
Files: New migration script or use /scripts/cleanup-test-users-raw.ts pattern
Depends On: None
Effort: Medium
P0-3: Delete Orphaned Test Records
Problem: 22 test clients and associated records pollute production data.
Steps:
- Run cleanup script in dry-run mode
- Review accounts to delete
- Execute with
--executeflag - Verify cleanup completed
- Run VACUUM ANALYZE
Files: /scripts/cleanup-test-users-raw.ts
Depends On: P0-2
Effort: Low
P0-4: Encrypt User.mfaSecret with AES-GCM
Problem: User.mfaSecret stores TOTP secrets that should be encrypted at rest.
Current State: Plaintext in database Target State: AES-256-GCM encrypted with CREDENTIALS_ENCRYPTION_KEY
Steps:
- Create encryption utility using existing
/lib/auth/encryption.tspattern - Add
mfaSecretEncryptedfield to User - Write migration to encrypt existing secrets
- Update TOTP verification to decrypt on-the-fly
- Remove plaintext field after verification period
- Add key rotation support
Files: /prisma/schema.prisma, /lib/utils/totp.ts, /lib/auth/encryption.ts
Depends On: None
Effort: Medium
P0-5: Encrypt Account OAuth Tokens
Problem: Account.access_token and refresh_token store OAuth tokens in plaintext.
Steps:
- Add encrypted token fields
- Migrate existing tokens (encrypt on read, write encrypted)
- Update OAuth flows to use encrypted tokens
- Remove plaintext after migration period
- Implement token refresh with encryption
Files: /prisma/schema.prisma, /lib/auth/*
Depends On: None
Effort: Medium
P0-6: Encrypt Integration OAuth Tokens
Problem: Yelp, Google, Facebook connections store tokens in plaintext.
Models Affected:
YelpConnection.accessTokenGoogleConnection.accessToken,refreshTokenFacebookConnection.pageAccessToken,longLivedToken
Steps:
- Use same encryption utility as P0-4/P0-5
- Add encrypted fields to each connection model
- Migrate existing tokens
- Update integration services
- Remove plaintext fields
Files: /prisma/schema.prisma, /lib/services/yelp/*, /lib/services/google/*, /lib/services/facebook/*
Depends On: P0-4 (shared encryption utility)
Effort: High
P0-7: Fix Billing Race Condition
Problem: Wallet credit operations not wrapped in transaction, risking double-spend or lost credits.
Current State:
// Separate queries, not atomic
const wallet = await prisma.creditWallet.findUnique(...);
await prisma.creditWallet.update({ credits: wallet.credits - amount });
Target State:
// Atomic transaction
await prisma.$transaction(async (tx) => {
const wallet = await tx.creditWallet.findUnique(...);
if (wallet.credits < amount) throw new InsufficientFundsError();
await tx.creditWallet.update({ credits: { decrement: amount } });
await tx.walletTransaction.create(...);
});
Steps:
- Identify all wallet mutation operations
- Wrap each in
$transaction - Add optimistic locking or use
decrementoperator - Add tests for concurrent operations
- Monitor for deadlocks
Files: /lib/services/platform-usage-tracker.ts, /app/api/payments/*
Depends On: None
Effort: Medium
P0-8: Add Portal.clientId Required FK
Problem: Portal→Client relationship is implicit through UserPortalAccess, not direct FK.
Target State:
model Portal {
clientId String
Client Client @relation(fields: [clientId], references: [id])
}
Steps:
- Add optional
clientIdfield first - Migrate data to populate clientId
- Make field required
- Add FK constraint
- Update Portal creation to require clientId
Files: /prisma/schema.prisma
Depends On: P0-1, P0-2 (Client integrity first)
Effort: Medium
P0-9: Fix Portal→Client→Company Linkage Chain
Problem: The entity chain Portal→Client→Company is broken, making tenant hierarchy unclear.
Steps:
- Complete P0-1 (Client.companyId FK)
- Complete P0-8 (Portal.clientId FK)
- Create database view for full chain
- Update TenantAccessService to use chain
- Add validation for chain integrity
Files: /lib/services/tenant-access.ts, /prisma/schema.prisma
Depends On: P0-1, P0-8
Effort: High
P0-10: Add Atomic Webhook Processing
Problem: Webhook processing has no atomic check-and-create, risking duplicate processing.
Current State: SELECT then INSERT (race window) Target State: INSERT with ON CONFLICT or transaction with locking
Steps:
- Add unique constraint on
(externalId, providerId, portalId) - Use
prisma.createwithskipDuplicatesorupsert - Add Redis-based idempotency cache for high-volume webhooks
- Implement idempotency key header support
- Add metrics for duplicate detection
Files: /app/api/webhooks/*/route.ts
Depends On: None
Effort: Medium
P0-11: Implement Request Signing for Internal APIs
Problem: Internal API calls (cron → API) rely on CRON_SECRET but lack request signing.
Steps:
- Implement HMAC-SHA256 request signing
- Add timestamp to prevent replay attacks
- Create signing middleware
- Update all cron routes to verify signatures
- Document signing protocol
Files: /app/api/cron/*/route.ts, /lib/middleware/*
Depends On: None
Effort: Medium
P0-12: Fix Session Token Storage Security
Problem: Session tokens stored without rotation mechanism being enforced consistently.
Steps:
- Audit session rotation implementation
- Ensure rotation on privilege change (role change, password change)
- Add session binding (fingerprint, IP)
- Implement session revocation on logout
- Add monitoring for session anomalies
Files: /lib/auth/sessionRotation.ts, /proxy.ts
Depends On: None
Effort: Medium
P1: High - Core Infrastructure
These items improve system stability, performance, and reliability.
P1-1: Implement Redis-Backed Rate Limiting
Problem: Current rate limiting uses Upstash with per-request overhead. Need more robust solution.
Steps:
- Design rate limit tiers (auth, api, heavy, webhook)
- Implement sliding window algorithm
- Add rate limit headers to responses
- Create bypass for internal services
- Add monitoring dashboard
Files: /proxy.ts, new /lib/rateLimit/*
Depends On: None
Effort: Medium
P1-2: Move Product.businessId → Product.companyId
Problem: Products belong to Business (Portal-scoped) but should belong to Company (persistent).
Migration Strategy:
- Add
companyIdfield (optional) - Populate via Business→Portal→Client→Company chain
- Make
companyIdrequired - Deprecate
businessId - Remove after migration period
Files: /prisma/schema.prisma, product-related services
Depends On: P0-9 (chain must be fixed first)
Effort: High
P1-3: Move Service.businessId → Service.companyId
Problem: Same as P1-2, Services should persist at Company level.
Steps: Same migration strategy as P1-2
Files: /prisma/schema.prisma, service-related services
Depends On: P0-9, P1-2 (same pattern)
Effort: High
P1-4: Wrap Lead Merge in Transaction
Problem: Lead merge operations (moving activities, soft delete) not atomic.
Steps:
- Wrap merge in
$transaction - Add rollback on failure
- Add audit log for merge
- Test concurrent merge attempts
- Add merge history table
Files: /lib/services/lead/leadService.prisma.ts
Depends On: None
Effort: Low
P1-5: Add Missing FK Indexes
Problem: 5 foreign key columns lack indexes, causing slow JOINs.
Columns Identified:
Message.conversationIdLeadActivity.leadIdConversationParticipant.conversationIdCallRecord.portalIdWalletTransaction.walletId
Steps:
- Add
@@indexdirectives to schema - Run migration
- Verify query plans improved
- Monitor query performance
Files: /prisma/schema.prisma
Depends On: None
Effort: Low
P1-6: Fix PortalAnalyticsSummary NULL ClientId Records
Problem: Analytics records with NULL clientId can't be attributed to clients.
Steps:
- Query records with NULL clientId
- Resolve clientId via Portal→Client relationship
- Update records
- Add NOT NULL constraint
- Fix analytics ingestion to require clientId
Files: /prisma/schema.prisma, analytics services
Depends On: P0-8 (Portal.clientId must exist)
Effort: Medium
P1-7: Create Complete Demo Portal Data Chain
Problem: Demo portal exists but lacks complete data chain for testing.
Required Data:
- Demo Company
- Demo Client
- Demo Portal (PID-DEMO-001)
- Demo Business (PortalAIConfig)
- Demo Conversations
- Demo Leads/Contacts
Steps:
- Create seed script for demo data
- Include sample conversations
- Include sample leads with pipeline stages
- Include sample reviews
- Add to CI/CD for fresh environments
Files: /prisma/seed.ts, /lib/demo/*
Depends On: P0-9
Effort: Medium
P1-8: Seed KnowledgeBaseEntry for Demo Portal
Problem: Demo portal has no knowledge base, limiting AI testing.
Steps:
- Create demo knowledge entries
- Index in Upstash Vector
- Test retrieval
- Add sample Q&A pairs
- Document demo knowledge structure
Files: /prisma/seed.ts, knowledge services
Depends On: P1-7
Effort: Low
P1-9: Standardize API Response Format
Problem: API responses inconsistent across 415+ routes.
Target Format:
interface ApiResponse<T> {
success: boolean;
data?: T;
error?: { code: string; message: string; details?: unknown };
meta?: { timestamp: string; requestId: string; pagination?: {...} };
}
Steps:
- Create response helper functions
- Audit existing routes for format
- Update routes incrementally
- Add response validation in tests
- Document in OpenAPI spec
Files: /lib/utils/apiResponse.ts, all route handlers
Depends On: None
Effort: High (many routes)
P1-10: Run VACUUM ANALYZE on Bloated Tables
Problem: Large tables need maintenance for query performance.
Tables:
- Message
- Conversation
- LeadActivity
- AuditLog
- ErrorLog
Steps:
- Check table bloat levels
- Schedule VACUUM ANALYZE during low traffic
- Monitor query performance before/after
- Set up autovacuum tuning
- Document maintenance schedule
Files: Database maintenance scripts Depends On: None Effort: Low
P1-11: Add Connection Pool Monitoring
Problem: No visibility into Prisma connection pool health.
Steps:
- Add pool metrics (active, idle, waiting)
- Expose via Prometheus endpoint
- Add alerting thresholds
- Create Grafana dashboard
- Document pool tuning
Files: /lib/services/monitoring/prometheusMetrics.ts
Depends On: None
Effort: Low
P1-12: Implement Graceful Shutdown
Problem: No graceful shutdown for long-running jobs on deploy.
Steps:
- Add SIGTERM handler
- Drain BullMQ jobs before exit
- Close database connections cleanly
- Add health check transition to unhealthy
- Test with Vercel deployment
Files: /lib/queue/bullmq-queue.ts, entry points
Depends On: None
Effort: Medium
P1-13: Add Database Query Timeout
Problem: No query timeout, slow queries can block connections.
Steps:
- Add statement_timeout to connection string
- Implement query timeout in Prisma middleware
- Add timeout metrics
- Alert on frequent timeouts
- Identify and optimize slow queries
Files: Database connection config, Prisma middleware Depends On: None Effort: Low
P1-14: Implement Circuit Breaker for External APIs
Problem: No circuit breaker for Yelp, Google, Facebook APIs.
Steps:
- Implement circuit breaker pattern
- Add to all external API calls
- Add fallback behavior
- Add circuit state metrics
- Document failure modes
Files: /lib/services/yelp/*, /lib/services/google/*, /lib/services/facebook/*
Depends On: None
Effort: Medium
P1-15: Add Structured Error Codes
Problem: Error messages are strings, not structured codes.
Steps:
- Define error code enum
- Map all error types to codes
- Update API responses to include codes
- Document error codes
- Add client-side error handling guide
Files: /lib/types/errors.ts, all services
Depends On: P1-9
Effort: High
P2: Medium - Type Safety & Model Refinement
These items improve code quality and maintainability.
P2-1: Remove Type Safety Bypasses in Financial Code
Problem: as any casts in billing/commission code bypass type safety.
Steps:
- Audit all
as anyin financial code - Create proper types for each case
- Remove casts
- Add strict null checks
- Add financial calculation tests
Files: /lib/services/platform-usage-tracker.ts, commission services
Depends On: None
Effort: Medium
P2-2: Fix Deduplication False Positive Logic
Problem: Name-only matching causes false positive duplicates.
Steps:
- Review duplicate detection algorithm
- Add confidence scoring
- Require email OR phone match for auto-merge
- Add manual review queue for uncertain matches
- Add undo for accidental merges
Files: /lib/services/lead/leadService.prisma.ts
Depends On: None
Effort: Medium
P2-3: Reduce Admin Status Cache TTL
Problem: 5-minute cache for admin status is too long for security.
Steps:
- Reduce TTL to 60 seconds
- Add cache invalidation on role change
- Add immediate invalidation endpoint
- Document caching behavior
- Add metrics for cache hit rate
Files: /lib/auth/*, admin services
Depends On: None
Effort: Low
P2-4: Implement Device Fingerprinting
Problem: Sessions don't bind to device, allowing session theft.
Steps:
- Collect device fingerprint (UA, screen, timezone)
- Store hash with session
- Validate on request
- Notify on fingerprint change
- Add "trust this device" option
Files: /lib/auth/sessionRotation.ts, /proxy.ts
Depends On: None
Effort: Medium
P2-5: Add Portal→PortalAIConfig Required 1:1
Problem: Portal→Business relationship is optional, should be required 1:1.
Steps:
- Ensure all portals have Business record
- Create missing Business records
- Change relation to required
- Update Portal creation to auto-create Business
- Update deletion to cascade
Files: /prisma/schema.prisma
Depends On: P2-6 (rename first)
Effort: Medium
P2-6: Rename Business Model to PortalAIConfig
Problem: "Business" name is confusing; it's actually portal-specific AI configuration.
Steps:
- Create new model
PortalAIConfig - Migrate data from Business
- Update all references
- Deprecate Business model
- Remove after migration
Files: /prisma/schema.prisma, all Business references
Depends On: None
Effort: High (many references)
P2-7: Clean CommissionTransaction Redundant Fields
Problem: CommissionTransaction has redundant calculated fields.
Fields to Review:
- Fields that duplicate data from related records
- Calculated fields that should be computed
Steps:
- Identify redundant fields
- Create database views for calculated values
- Migrate queries to use views
- Remove redundant columns
- Add computed properties in Prisma
Files: /prisma/schema.prisma, commission services
Depends On: None
Effort: Medium
P2-8: Implement Multi-Tenant Access Control Verification
Problem: No systematic verification that all queries include tenant filter.
Steps:
- Create Prisma middleware to verify portalId
- Log queries without tenant filter
- Fix identified issues
- Add to test suite
- Create PR review checklist
Files: New Prisma middleware, test utilities Depends On: None Effort: Medium
P2-9: Add TypeScript Strict Mode to Remaining Files
Problem: Some files have implicit any types.
Steps:
- Run
tsc --noImplicitAnycheck - Identify files with implicit any
- Fix incrementally
- Enable strict in tsconfig
- Add to CI checks
Files: /tsconfig.json, various source files
Depends On: None
Effort: Medium
P2-10: Standardize Date/Time Handling
Problem: Inconsistent timezone handling across codebase.
Steps:
- Audit date handling patterns
- Choose standard (UTC everywhere, convert on display)
- Create date utility module
- Update all date operations
- Add timezone tests
Files: New /lib/utils/dates.ts, various services
Depends On: None
Effort: Medium
P2-11: Add Zod Validation to All API Routes
Problem: Input validation inconsistent across routes.
Steps:
- Create common Zod schemas
- Audit routes without validation
- Add validation incrementally
- Standardize error responses
- Document validation in OpenAPI
Files: /lib/types/schemas.ts, all route handlers
Depends On: P1-9, P1-15
Effort: High
P2-12: Implement Proper Enum Types
Problem: Magic strings used instead of enums.
Areas:
- Lead status values
- Pipeline stages
- Integration types
- Message channels
Steps:
- Create TypeScript enums
- Add Prisma enum types where appropriate
- Migrate existing data
- Update all usages
- Add validation
Files: /lib/types/*, /prisma/schema.prisma
Depends On: None
Effort: Medium
P3: Standard - Cleanup & Observability
These items reduce technical debt and improve visibility.
P3-1: Review and Clean Unused Database Indexes
Problem: Potentially unused indexes consuming space.
Steps:
- Query pg_stat_user_indexes for unused indexes
- Verify each is truly unused
- Drop unused indexes
- Monitor query performance
- Document index strategy
Files: Database, /prisma/schema.prisma
Depends On: None
Effort: Low
P3-2: Standardize Pagination Across API Routes
Problem: Different pagination patterns across routes.
Target Pattern:
{
items: T[];
pagination: {
page: number;
pageSize: number;
total: number;
hasMore: boolean;
};
}
Steps:
- Create pagination helper
- Audit existing patterns
- Update routes incrementally
- Add cursor-based option for large sets
- Document in API docs
Files: /lib/utils/pagination.ts, route handlers
Depends On: P1-9
Effort: Medium
P3-3: Add Audit Log Retention Policy
Problem: AuditLog table grows unbounded.
Steps:
- Define retention period (365 days per ARCHITECTURE.md)
- Create archival strategy
- Implement cleanup cron job
- Add partitioning for performance
- Document compliance requirements
Files: /app/api/cron/data-retention/route.ts
Depends On: None
Effort: Medium
P3-4: Document API Versioning Strategy
Problem: No clear API versioning strategy documented.
Steps:
- Document current version metadata approach
- Define future versioning strategy
- Add deprecation header support
- Create version migration guide
- Update OpenAPI spec
Files: /docs/API_VERSIONING.md, OpenAPI spec
Depends On: None
Effort: Low
P3-5: Implement Distributed Tracing
Problem: Sentry tracing at 10%, no full distributed tracing.
Steps:
- Evaluate trace sampling rate
- Add correlation IDs to all requests
- Propagate trace context to background jobs
- Add trace links in logs
- Create trace exploration dashboard
Files: Sentry config, logging utilities Depends On: None Effort: Medium
P3-6: Add SLO/SLA Definitions
Problem: No defined SLOs for key operations.
Target SLOs:
- API response time: P99 < 500ms
- Webhook processing: P99 < 2s
- AI response: P99 < 5s
- Uptime: 99.9%
Steps:
- Define SLOs for each service tier
- Implement SLO tracking metrics
- Create alerting on SLO breach
- Add SLO dashboard
- Document SLA for customers
Files: /lib/services/monitoring/*, alerting config
Depends On: None
Effort: Medium
P3-7: Run Test Coverage Report
Problem: Unknown test coverage, gaps likely exist.
Steps:
- Configure Jest coverage reporting
- Run coverage report
- Identify critical gaps
- Add tests for uncovered critical paths
- Set coverage thresholds
Files: /jest.config.ts, /tests/*
Depends On: None
Effort: Medium
P3-8: Audit Codebase for Dead Code
Problem: Likely dead code from feature iterations.
Steps:
- Run dead code detection tools
- Review flagged code
- Remove confirmed dead code
- Add lint rule for unused exports
- Create regular audit schedule
Files: Various Depends On: None Effort: Medium
P3-9: Add Request ID to All Logs
Problem: Logs missing correlation IDs for debugging.
Steps:
- Generate request ID in middleware
- Pass through logging context
- Include in error responses
- Add to Sentry context
- Document debugging workflow
Files: /proxy.ts, /lib/utils/logging.ts
Depends On: None
Effort: Low
P3-10: Implement Log Aggregation Strategy
Problem: Logs split across Vercel, Sentry, console.
Steps:
- Define log aggregation target
- Configure log shipping
- Create log search interface
- Add log retention policy
- Document log access
Files: Logging configuration Depends On: P3-9 Effort: Medium
P3-11: Add Health Check Dependencies
Problem: Health check doesn't verify all critical dependencies.
Dependencies to Check:
- Database connection
- Redis connection
- Supabase Auth
- External APIs (degraded mode)
Steps:
- Add dependency checks to health endpoint
- Return degraded status if optional deps fail
- Add dependency timeout
- Create health dashboard
- Document health check interpretation
Files: /app/api/health/route.ts
Depends On: None
Effort: Low
P3-12: Create Runbook for Common Issues
Problem: No documented runbooks for incident response.
Runbooks Needed:
- Database connection issues
- High error rate
- Payment failures
- Integration sync failures
- Performance degradation
Steps:
- Document common issues and resolutions
- Create decision trees
- Add monitoring links
- Define escalation paths
- Review and update quarterly
Files: /docs/runbooks/*
Depends On: None
Effort: Medium
P4: Lower - Schema & Validation
These items refine the data model and improve data quality.
P4-1: Rename VoiceTouchpoint.organizationId to portalId
Problem: Inconsistent naming, should be portalId for clarity.
Steps:
- Add
portalIdfield - Migrate data
- Update all references
- Remove
organizationId - Update types
Files: /prisma/schema.prisma, voice services
Depends On: None
Effort: Low
P4-2: Add companyId Option to KnowledgeBaseEntry
Problem: Knowledge entries are portal-scoped, but some should be company-scoped.
Steps:
- Add optional
companyIdfield - Update knowledge retrieval to check company tier
- Create company knowledge management UI
- Migrate shared knowledge to company level
- Document knowledge scoping
Files: /prisma/schema.prisma, knowledge services
Depends On: P0-9
Effort: Medium
P4-3: Restructure Upstash Vector Namespacing
Problem: Vector namespacing doesn't clearly separate company vs portal knowledge.
Target Structure:
company-{companyId}- Products, services, FAQsportal-{portalId}- Team, integrations, workflows
Steps:
- Create migration script
- Re-index company knowledge
- Update retrieval queries
- Delete old namespaces
- Document namespace strategy
Files: Knowledge services, vector indexing Depends On: P4-2 Effort: Medium
P4-4: Fix Lead.clientId FK Relation
Problem: Lead.clientId is optional string, should have optional FK.
Steps:
- Add FK relation (optional)
- Validate existing data
- Update lead creation to use FK
- Add cascade rules
- Document lead ownership
Files: /prisma/schema.prisma
Depends On: P0-1
Effort: Low
P4-5: Consolidate Subscription Fields to Company
Problem: Subscription fields split between models.
Steps:
- Audit subscription field locations
- Design consolidated structure
- Migrate data to Company
- Update billing services
- Remove redundant fields
Files: /prisma/schema.prisma, billing services
Depends On: P0-9
Effort: Medium
P4-6: Document Knowledge Tier Architecture in Code
Problem: Knowledge tier logic spread across files, not well documented.
Steps:
- Create knowledge architecture doc
- Add code comments explaining tiers
- Create tier diagram
- Document retrieval priority
- Add knowledge management guide
Files: Knowledge services, /docs/KNOWLEDGE_ARCHITECTURE.md
Depends On: P4-2, P4-3
Effort: Low
P4-7: Add Input Validation Consistency
Problem: Some routes lack input validation entirely.
Steps:
- Audit all routes for validation
- Create shared Zod schemas
- Add validation to missing routes
- Standardize error messages
- Add validation tests
Files: All route handlers Depends On: P2-11 Effort: High
P4-8: Document and Fix N+1 Query Patterns
Problem: Likely N+1 queries in list endpoints.
Steps:
- Profile slow endpoints
- Identify N+1 patterns
- Add Prisma includes/selects
- Add query performance tests
- Document query optimization
Files: Various services Depends On: None Effort: Medium
P4-9: Add Soft Delete to More Models
Problem: Hard deletes lose audit trail.
Models to Consider:
- Conversation
- Message
- Contact
Steps:
- Add
isDeletedfield - Update queries to filter
- Add deletion audit
- Create purge job for old deleted records
- Document deletion policy
Files: /prisma/schema.prisma, various services
Depends On: None
Effort: Medium
P4-10: Add Created/Updated By Fields
Problem: Some models lack audit fields.
Steps:
- Audit models missing createdBy/updatedBy
- Add fields with optional FK
- Update services to populate
- Migrate existing data
- Add to audit logging
Files: /prisma/schema.prisma
Depends On: None
Effort: Medium
P4-11: Normalize Phone Number Storage
Problem: Phone numbers stored in various formats.
Steps:
- Choose canonical format (E.164)
- Create normalization utility
- Migrate existing data
- Update input validation
- Add format display utility
Files: New /lib/utils/phone.ts, migration scripts
Depends On: None
Effort: Medium
P4-12: Add Email Normalization
Problem: Emails stored with inconsistent casing.
Steps:
- Normalize to lowercase
- Create validation utility
- Migrate existing data
- Update input handling
- Add deduplication check
Files: New /lib/utils/email.ts, migration scripts
Depends On: None
Effort: Low
P4-13: Review and Consolidate Status Enums
Problem: Multiple status fields with overlapping values.
Steps:
- Audit all status fields
- Create unified status types
- Map legacy values
- Update code to use unified types
- Document status transitions
Files: /lib/types/*, various services
Depends On: P2-12
Effort: Medium
P4-14: Add Optimistic Locking Where Needed
Problem: No version field for concurrent update detection.
Steps:
- Identify high-contention models
- Add version field
- Implement optimistic locking
- Handle conflicts gracefully
- Add conflict resolution UI
Files: /prisma/schema.prisma, services with updates
Depends On: None
Effort: Medium
P5: Documentation
These items improve knowledge sharing and onboarding.
P5-1: Document Webhook Secret Validation
Problem: Webhook validation patterns not documented.
Steps:
- Audit all webhook handlers
- Document signature verification per provider
- Create webhook testing guide
- Add validation helpers
- Document debugging workflow
Files: /docs/API_INTEGRATION_GUIDE.md (Webhook Integration section)
Depends On: None
Effort: Low
P5-2: Document Connection Health Monitoring
Problem: No guide for monitoring integration health.
Steps:
- Document health check patterns
- Create monitoring dashboard guide
- Document failure modes
- Add alerting recommendations
- Create troubleshooting guide
Files: /docs/INTEGRATION_MONITORING.md
Depends On: None
Effort: Low
P5-3: Document Voice AI Provider Configuration
Problem: Voice AI setup not documented.
Steps:
- Document Cartesia setup
- Document ElevenLabs fallback
- Document Retell integration
- Create troubleshooting guide
- Add voice testing procedures
Files: /docs/VOICE_AI_SETUP.md
Depends On: None
Effort: Low
P5-4: Document Call Recording Storage
Problem: Call recording architecture not documented.
Steps:
- Document storage location
- Document retention policy
- Add compliance considerations
- Document access controls
- Create cleanup procedures
Files: /docs/CALL_RECORDINGS.md
Depends On: None
Effort: Low
P5-5: Document RLS Policies
Problem: RLS policy logic not documented.
Steps:
- Extract RLS policies from migrations
- Document each policy's purpose
- Create testing guide
- Document bypass rules
- Add security considerations
Files: /docs/RLS_POLICIES.md
Depends On: None
Effort: Low
P5-6: Create Onboarding Developer Guide
Problem: No comprehensive developer onboarding.
Steps:
- Document local setup
- Document architecture overview
- Create coding standards guide
- Document testing workflow
- Create PR review checklist
Files: /docs/DEVELOPER_GUIDE.md
Depends On: None
Effort: Medium
P5-7: Document Background Job Patterns
Problem: Job patterns not documented.
Steps:
- Document BullMQ usage
- Document database job pattern
- Create job debugging guide
- Document retry strategies
- Add monitoring guide
Files: /docs/BACKGROUND_JOBS.md
Depends On: None
Effort: Low
P5-8: Create API Integration Guide
Problem: No guide for third-party API integration.
Steps:
- Document integration patterns
- Create example integration
- Document error handling
- Add rate limit handling
- Create testing guide
Files: /docs/API_INTEGRATION_GUIDE.md
Depends On: None
Effort: Medium
P5-9: Document Database Migration Procedures
Problem: Migration process not documented.
Steps:
- Document migration workflow
- Add rollback procedures
- Create testing guide
- Document production deployment
- Add emergency procedures
Files: /docs/DATABASE_MIGRATIONS.md
Depends On: None
Effort: Low
P5-10: Create Security Best Practices Guide
Problem: Security practices not consolidated.
Steps:
- Document authentication patterns
- Document authorization patterns
- Add encryption guide
- Document secret management
- Create security review checklist
Files: /docs/SECURITY_GUIDE.md
Depends On: None
Effort: Medium
Dependencies Graph
P0-2 (orphan data) ─┬─► P0-1 (Client FK) ─┬─► P0-8 (Portal.clientId) ─► P0-9 (chain)
│ │
└─► P0-3 (cleanup) └─► P1-2, P1-3 (Product/Service migration)
│
▼
P4-2 (knowledge companyId) ─► P4-3 (vector)
P0-4 (MFA encrypt) ─► P0-5 (OAuth encrypt) ─► P0-6 (integration encrypt)
P2-6 (Business rename) ─► P2-5 (Portal→PortalAIConfig)
P1-9 (response format) ─► P3-2 (pagination) ─► P2-11 (Zod validation)
│
▼
P1-15 (error codes)
P1-7 (demo data) ─► P1-8 (demo knowledge)
P3-9 (request ID) ─► P3-10 (log aggregation)
Migration Execution Notes
Before Starting
- Create backup: Ensure database backup exists
- Feature flag: Consider feature flags for reversible changes
- Monitor: Have monitoring dashboards open
- Communicate: Notify team of migration window
Execution Order
- P0 first: Data integrity issues must be fixed before other changes
- Dependencies: Follow dependency graph
- Test each step: Verify before proceeding
- Document: Update CHANGELOG after each batch
Rollback Plan
Each migration should have:
- Rollback SQL or Prisma migration
- Expected rollback time
- Verification queries
- Communication plan
Testing Requirements
- Unit tests for all new utilities
- Integration tests for data migrations
- Load tests for performance-sensitive changes
- Security review for encryption changes
This plan is the execution roadmap for ARCHITECTURE.md. Track progress in project management tools and update this document as items complete.