Clearview CRM · Stack: flask-nextjs · Generated: 2026-06-01 09:14 UTC
Clearview CRM is a multi-tenant B2B SaaS application for SMB sales teams. The system provides contact and deal management, pipeline tracking, and activity logging across isolated organisational workspaces. This report is generated directly from the architectural genome and reflects the system as built — not as intended.
graph LR SR[Sales Rep] -->|creates| C[Contact] SR -->|tracks| D[Deal] SM[Sales Manager] -->|reviews| PL[Pipeline] OA[Org Admin] -->|manages| W[Workspace] C -->|associated with| D D -->|belongs to| PL PL -->|owned by| W D -->|has| A[Activity Log]
Diagram rendering requires internet access. Paste the source above into mermaid.live to view it.
graph TB FE[Next.js Frontend] -->|REST| GW[Flask API Gateway] GW --> AUTH[auth_bp.py] GW --> CONTACTS[contacts_bp.py] GW --> DEALS[deals_bp.py] GW --> PIPELINE[pipeline_bp.py] GW --> ACTIVITIES[activities_bp.py] GW --> ORG[organizations_bp.py] AUTH -->|JWT httpOnly cookie| DB[(PostgreSQL)] CONTACTS --> DB DEALS --> DB PIPELINE --> DB ACTIVITIES --> DB ORG --> DB BG[Celery Worker] -->|async jobs| DB BG -->|email| SMTP[SMTP / SendGrid]
Diagram rendering requires internet access. Paste the source above into mermaid.live to view it.
graph LR
subgraph Production
LB[Load Balancer / nginx] --> APP[Flask app · gunicorn]
LB --> FE_STATIC[Next.js · Vercel / CDN]
APP --> PG[(PostgreSQL 15)]
APP --> REDIS[(Redis 7 · cache + job queue)]
APP --> WORKER[Celery worker]
end
subgraph CI/CD
GH[GitHub Actions] -->|docker build| ACR[Azure Container Registry]
ACR -->|docker pull| APP
end
DEV[Developer] -->|git push| GH
Diagram rendering requires internet access. Paste the source above into mermaid.live to view it.
Context: Auth tokens must be stored client-side. Two options: localStorage (simple) or httpOnly cookies (XSS-resistant).
Use httpOnly, Secure, SameSite=Lax cookies exclusively. The JWT is never exposed to JavaScript.
localStorage tokens are readable by any injected script (XSS vector). httpOnly cookies are invisible to JavaScript. Required for SOC 2 CC6.1 (logical access controls).
Context: Initial design used a deal.status enum (lead/qualified/proposal/closed). Sales managers need custom stages per pipeline.
Introduce PipelineStage as a configurable entity owned by a Pipeline, replacing the static enum on Deal.
Enum values require a migration for every new sales process. First-class stages allow org admins to configure their own funnel without engineer involvement. This is the industry-standard CRM data model.
Context: Activity log entries carry varying metadata (email open counts, call duration, meeting attendees). Options: single JSONB column or EAV-style attribute table.
Single metadata JSONB column on Activity. Indexed with GIN for metadata-based queries.
EAV tables require N-joins per activity query. JSONB gives flexible schema with native PostgreSQL indexing. Activity query volume is high; join count matters.
| Control | Framework | Status | Evidence / Gap |
|---|---|---|---|
| CC6.1 — Logical access controls | SOC 2 Type II | MET | httpOnly JWT cookie auth; RBAC on all routes; workspace-scoped DB queries |
| CC6.2 — Authentication mechanisms | SOC 2 Type II | MET | bcrypt password hashing (cost 12); secure token rotation on logout |
| CC6.3 — Role-based access | SOC 2 Type II | MET | requires_role() decorator on all admin endpoints |
| CC7.1 — Audit logging | SOC 2 Type II | PARTIAL | Activity log covers user actions; infrastructure-level audit log (CloudTrail equivalent) not yet wired |
| CC8.1 — Change management | SOC 2 Type II | MET | Alembic migrations with version history; CI gate on every schema change |
| Art. 17 — Right to erasure | GDPR | PARTIAL | DELETE /api/organizations/{id} cascades to contacts/deals; no explicit data-subject erasure endpoint for individual users yet |
| Art. 32 — Security of processing | GDPR | MET | TLS in transit; PostgreSQL encryption at rest via managed PG; no PII in logs |
| Art. 25 — Data protection by design | GDPR | MET | Workspace isolation enforced at query layer; no cross-tenant data accessible via API |
| Deployment frequency | DORA | MET | CI/CD pipeline ships on every merge to main; average deploy time < 8 min |
| Change failure rate | DORA | PARTIAL | Automated tests cover happy paths; integration tests for rollback scenarios not yet complete |
| User story | Entity / module | API routes | Status |
|---|---|---|---|
| As a sales rep, I can create and update contacts | Contact | POST /api/contacts, PUT /api/contacts/{id} |
Generated |
| As a sales rep, I can attach deals to contacts | Deal, Contact | POST /api/deals, GET /api/contacts/{id}/deals |
Generated |
| As a sales manager, I can view the full pipeline | Pipeline, PipelineStage, Deal | GET /api/pipelines, GET /api/pipelines/{id}/deals |
Generated |
| As an org admin, I can invite team members | User, Organization | POST /api/organizations/{id}/invite |
Generated |
| As a sales rep, I can log a call against a deal | Activity, Deal | POST /api/activities |
Generated |
| As an org admin, I can export contacts to CSV | Contact | GET /api/contacts/export |
Stubbed — implement export formatter |
| As a sales manager, I can set win probability on a deal | Deal | PATCH /api/deals/{id} |
Generated |
| Risk | Severity | Likelihood | Mitigation |
|---|---|---|---|
| Contact CSV export endpoint is stubbed — data can be exported but formatter is not production-ready | MEDIUM | High (feature will be exercised in first customer pilot) | Implement CSV formatter in app/services/export_service.py before pilot |
| Infrastructure audit log not wired — SOC 2 CC7.1 partial gap | MEDIUM | Medium (required for SOC 2 Type II audit) | Wire CloudWatch / Datadog log forwarding for infrastructure events; target: before Q3 audit |
| No individual user data-erasure endpoint (GDPR Art. 17) | MEDIUM | Low (no DPA requests anticipated until 10k+ users) | Add DELETE /api/users/me with cascade to workspace user records; schedule for next sprint |
| Celery worker has no dead-letter queue — failed email jobs are silently dropped | LOW | Low | Add Redis-backed dead-letter queue with retry limit 3 before launch |