data-model-gap-analysis.md
CODITECT Multi-Tenant SaaS Platform - Data Model Gap Analysis
Generated: 2025-12-30 Purpose: Identify missing models for pilot launch domains Severity Levels: CRITICAL (blocks pilot), HIGH (needed for MVP), MEDIUM (post-launch), LOW (future enhancement)
Executive Summary
Current State: 40 models across 10 apps (1 app has no models) Gaps Identified: 35 missing models across 6 domains Criticality Breakdown:
- CRITICAL (blocks pilot): 8 models
- HIGH (MVP required): 15 models
- MEDIUM (post-launch): 9 models
- LOW (future): 3 models
Recommendation: Implement all CRITICAL and HIGH priority models before pilot launch (December 24, 2025 - 2 days remaining).
Table of Contents
- Domain 1: Project Management
- Domain 2: Document Management System (DMS)
- Domain 3: Workflow Analysis
- Domain 4: Audit Teams
- Domain 5: Billing/Invoicing/Payment
- Domain 6: Contact Management
- Implementation Priority Matrix
- Field-Level Gaps in Existing Models
- Multi-Tenant Compliance Issues
- Recommendations
Domain 1: Project Management
Current Coverage: Partial (Project model exists, but incomplete)
Existing Models
- ✅
Project(organizations app) - Basic project container
Missing Models
1.1 Task / Issue
Priority: CRITICAL Reason: Core PM functionality - cannot manage projects without tasks
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique task identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
project | TenantForeignKey(Project) | CASCADE | Parent project |
title | CharField(500) | Task title | |
description | TextField | Task description | |
task_type | CharField(20) | 'task', 'bug', 'feature', 'epic' | |
status | CharField(20) | 'backlog', 'todo', 'in_progress', 'in_review', 'done', 'cancelled' | |
priority | CharField(20) | 'low', 'medium', 'high', 'urgent' | |
assignee | TenantForeignKey(User) | SET_NULL, nullable | Assigned user |
reporter | TenantForeignKey(User) | SET_NULL, nullable | User who created task |
sprint | TenantForeignKey(Sprint) | SET_NULL, nullable | Linked sprint |
milestone | TenantForeignKey(Milestone) | SET_NULL, nullable | Linked milestone |
parent_task | ForeignKey(self) | SET_NULL, nullable | Parent task (subtasks) |
story_points | IntegerField | Nullable | Estimation points |
due_date | DateTimeField | Nullable | Due date |
started_at | DateTimeField | Nullable | When work started |
completed_at | DateTimeField | Nullable | When task completed |
tags | JSONField | default=list | List of tags |
custom_fields | JSONField | default=dict | Custom field values |
created_at | DateTimeField | auto_now_add | Creation timestamp |
updated_at | DateTimeField | auto_now | Last update timestamp |
deleted_at | DateTimeField | Nullable | Soft delete |
Indexes: (tenant, project, status), assignee, sprint, due_date
Constraints: None critical
1.2 Sprint
Priority: HIGH Reason: Agile workflow requires sprint management
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique sprint identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
project | TenantForeignKey(Project) | CASCADE | Parent project |
name | CharField(255) | Sprint name (e.g., "Sprint 12") | |
goal | TextField | Sprint goal description | |
status | CharField(20) | 'planned', 'active', 'completed', 'cancelled' | |
start_date | DateField | Sprint start date | |
end_date | DateField | Sprint end date | |
created_at | DateTimeField | auto_now_add | Creation timestamp |
updated_at | DateTimeField | auto_now | Last update timestamp |
completed_at | DateTimeField | Nullable | When sprint completed |
Indexes: (tenant, project, status), (start_date, end_date)
Constraints: (tenant, project, name) unique
1.3 Milestone
Priority: MEDIUM Reason: Release planning and goal tracking
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique milestone identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
project | TenantForeignKey(Project) | CASCADE | Parent project |
title | CharField(255) | Milestone title | |
description | TextField | Milestone description | |
status | CharField(20) | 'open', 'in_progress', 'completed', 'cancelled' | |
due_date | DateField | Nullable | Target completion date |
progress_percent | IntegerField | default=0 | Calculated progress (0-100) |
created_at | DateTimeField | auto_now_add | Creation timestamp |
updated_at | DateTimeField | auto_now | Last update timestamp |
completed_at | DateTimeField | Nullable | When milestone completed |
Indexes: (tenant, project, status), due_date
Constraints: (tenant, project, title) unique
1.4 TaskComment
Priority: HIGH Reason: Collaboration requires commenting
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique comment identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
task | TenantForeignKey(Task) | CASCADE | Parent task |
author | TenantForeignKey(User) | SET_NULL, nullable | Comment author |
content | TextField | Comment content (Markdown supported) | |
created_at | DateTimeField | auto_now_add | Creation timestamp |
updated_at | DateTimeField | auto_now | Last update timestamp |
deleted_at | DateTimeField | Nullable | Soft delete |
Indexes: (task, -created_at)
Constraints: None
1.5 TaskAttachment
Priority: MEDIUM Reason: Task context requires file attachments
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique attachment identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
task | TenantForeignKey(Task) | CASCADE | Parent task |
uploader | TenantForeignKey(User) | SET_NULL, nullable | User who uploaded |
filename | CharField(255) | Original filename | |
file_path | CharField(500) | GCS path | |
file_size_bytes | BigIntegerField | File size | |
mime_type | CharField(100) | MIME type | |
created_at | DateTimeField | auto_now_add | Upload timestamp |
Indexes: (task, -created_at)
Constraints: None
1.6 TaskActivity / ActivityLog
Priority: MEDIUM Reason: Audit trail for task changes
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique activity identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
task | TenantForeignKey(Task) | CASCADE | Task |
user | TenantForeignKey(User) | SET_NULL, nullable | User who made change |
action | CharField(50) | 'created', 'updated', 'commented', 'status_changed', 'assigned', etc. | |
field_changed | CharField(100) | Nullable | Field name changed |
old_value | TextField | Nullable | Previous value (JSON) |
new_value | TextField | Nullable | New value (JSON) |
created_at | DateTimeField | auto_now_add | Activity timestamp |
Indexes: (task, -created_at), (tenant, user, -created_at)
Constraints: None
1.7 Board / KanbanBoard
Priority: LOW Reason: Visual management (can use default project view initially)
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique board identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
project | TenantForeignKey(Project) | CASCADE | Parent project |
name | CharField(255) | Board name | |
board_type | CharField(20) | 'kanban', 'scrum', 'custom' | |
columns | JSONField | List of {id, name, status_mapping, position} | |
created_at | DateTimeField | auto_now_add | Creation timestamp |
updated_at | DateTimeField | auto_now | Last update timestamp |
Gap Summary - Project Management
| Model | Priority | Status | Recommended App |
|---|---|---|---|
| Task/Issue | CRITICAL | Missing | organizations or new pm app |
| Sprint | HIGH | Missing | organizations or new pm app |
| Milestone | MEDIUM | Missing | organizations or new pm app |
| TaskComment | HIGH | Missing | organizations or new pm app |
| TaskAttachment | MEDIUM | Missing | organizations or new pm app |
| TaskActivity | MEDIUM | Missing | organizations or new pm app |
| Board/KanbanBoard | LOW | Missing | organizations or new pm app |
TOTAL: 7 missing models (1 CRITICAL, 2 HIGH, 3 MEDIUM, 1 LOW)
Domain 2: Document Management System (DMS)
Current Coverage: None (0 models)
Missing Models
2.1 Document
Priority: CRITICAL Reason: Core DMS functionality - addon product requires document storage
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique document identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
project | TenantForeignKey(Project) | SET_NULL, nullable | Linked project |
folder | TenantForeignKey(Folder) | SET_NULL, nullable | Parent folder |
title | CharField(500) | Document title | |
description | TextField | Document description | |
file_path | CharField(1000) | GCS storage path | |
file_name | CharField(255) | Original filename | |
file_size_bytes | BigIntegerField | File size | |
mime_type | CharField(100) | MIME type | |
checksum | CharField(64) | SHA256 checksum (deduplication) | |
version | IntegerField | default=1 | Current version number |
status | CharField(20) | 'draft', 'published', 'archived', 'deleted' | |
owner | TenantForeignKey(User) | SET_NULL, nullable | Document owner |
created_by | TenantForeignKey(User) | SET_NULL, nullable | Creator |
updated_by | TenantForeignKey(User) | SET_NULL, nullable | Last editor |
tags | JSONField | default=list | List of tags |
metadata | JSONField | default=dict | Custom metadata |
created_at | DateTimeField | auto_now_add | Creation timestamp |
updated_at | DateTimeField | auto_now | Last update timestamp |
deleted_at | DateTimeField | Nullable | Soft delete |
Indexes: (tenant, folder), (tenant, owner), checksum, (tenant, status, -updated_at)
Constraints: None
2.2 DocumentVersion
Priority: CRITICAL Reason: Version control is core DMS feature
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique version identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
document | TenantForeignKey(Document) | CASCADE | Parent document |
version_number | IntegerField | Version number (1, 2, 3, ...) | |
file_path | CharField(1000) | GCS storage path for this version | |
file_size_bytes | BigIntegerField | File size | |
checksum | CharField(64) | SHA256 checksum | |
change_summary | TextField | What changed in this version | |
created_by | TenantForeignKey(User) | SET_NULL, nullable | User who created version |
created_at | DateTimeField | auto_now_add | Version creation timestamp |
Indexes: (document, -version_number)
Constraints: (document, version_number) unique
2.3 Folder
Priority: HIGH Reason: Hierarchical organization of documents
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique folder identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
project | TenantForeignKey(Project) | SET_NULL, nullable | Linked project |
parent | TenantForeignKey(self) | SET_NULL, nullable | Parent folder (tree) |
name | CharField(255) | Folder name | |
description | TextField | Folder description | |
path | CharField(2000) | Full folder path (/folder1/folder2/...) | |
created_by | TenantForeignKey(User) | SET_NULL, nullable | Creator |
created_at | DateTimeField | auto_now_add | Creation timestamp |
updated_at | DateTimeField | auto_now | Last update timestamp |
deleted_at | DateTimeField | Nullable | Soft delete |
Indexes: (tenant, parent), path
Constraints: (tenant, parent, name) unique where deleted_at IS NULL
2.4 DocumentPermission
Priority: HIGH Reason: Access control for sensitive documents
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique permission identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
document | TenantForeignKey(Document) | SET_NULL, nullable | Specific document |
folder | TenantForeignKey(Folder) | SET_NULL, nullable | Folder (inherits to children) |
user | TenantForeignKey(User) | SET_NULL, nullable | Specific user |
team | TenantForeignKey(Team) | SET_NULL, nullable | Team access |
permission_level | CharField(20) | 'view', 'edit', 'delete', 'admin' | |
granted_by | TenantForeignKey(User) | SET_NULL, nullable | Who granted permission |
created_at | DateTimeField | auto_now_add | Grant timestamp |
expires_at | DateTimeField | Nullable | Permission expiration |
Indexes: (document, user), (folder, team)
Constraints: (document, user) unique OR (folder, team) unique
2.5 DocumentActivity
Priority: MEDIUM Reason: Audit trail for document access and changes
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique activity identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
document | TenantForeignKey(Document) | CASCADE | Document |
user | TenantForeignKey(User) | SET_NULL, nullable | User who performed action |
action | CharField(50) | 'viewed', 'downloaded', 'uploaded', 'edited', 'deleted', 'restored', 'shared' | |
ip_address | GenericIPAddressField | Nullable | Client IP |
user_agent | CharField(500) | Browser user agent | |
created_at | DateTimeField | auto_now_add | Activity timestamp |
Indexes: (document, -created_at), (tenant, user, -created_at)
Constraints: None
2.6 DocumentShare
Priority: MEDIUM Reason: External sharing with time-limited links
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique share identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
document | TenantForeignKey(Document) | CASCADE | Document being shared |
share_token | CharField(64) | Unique | Public share token (UUID) |
created_by | TenantForeignKey(User) | SET_NULL, nullable | User who created share |
permission_level | CharField(20) | 'view', 'download' | |
expires_at | DateTimeField | Nullable | Share expiration |
password_hash | CharField(255) | Nullable | Optional password protection |
access_count | IntegerField | default=0 | Number of times accessed |
last_accessed_at | DateTimeField | Nullable | Last access timestamp |
created_at | DateTimeField | auto_now_add | Share creation timestamp |
is_active | BooleanField | default=True | Share active status |
Indexes: share_token, (document, is_active)
Constraints: None
Gap Summary - Document Management System
| Model | Priority | Status | Recommended App |
|---|---|---|---|
| Document | CRITICAL | Missing | New dms app |
| DocumentVersion | CRITICAL | Missing | New dms app |
| Folder | HIGH | Missing | New dms app |
| DocumentPermission | HIGH | Missing | New dms app |
| DocumentActivity | MEDIUM | Missing | New dms app |
| DocumentShare | MEDIUM | Missing | New dms app |
TOTAL: 6 missing models (2 CRITICAL, 2 HIGH, 2 MEDIUM)
Domain 3: Workflow Analysis
Current Coverage: None (0 models)
Missing Models
3.1 Workflow
Priority: CRITICAL Reason: Core feature for Workflow Analyzer addon product
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique workflow identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
project | TenantForeignKey(Project) | SET_NULL, nullable | Linked project |
name | CharField(255) | Workflow name | |
description | TextField | Workflow description | |
workflow_type | CharField(50) | 'approval', 'automation', 'review', 'deployment', 'custom' | |
version | IntegerField | default=1 | Workflow version |
status | CharField(20) | 'draft', 'active', 'paused', 'archived' | |
definition | JSONField | Workflow state machine definition (nodes, edges, conditions) | |
triggers | JSONField | default=list | List of trigger conditions |
created_by | TenantForeignKey(User) | SET_NULL, nullable | Creator |
created_at | DateTimeField | auto_now_add | Creation timestamp |
updated_at | DateTimeField | auto_now | Last update timestamp |
published_at | DateTimeField | Nullable | When workflow was published |
Indexes: (tenant, status), (tenant, workflow_type)
Constraints: None
3.2 WorkflowExecution
Priority: CRITICAL Reason: Track workflow run history
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique execution identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
workflow | TenantForeignKey(Workflow) | CASCADE | Workflow being executed |
triggered_by | TenantForeignKey(User) | SET_NULL, nullable | User who triggered (or 'system') |
trigger_type | CharField(50) | 'manual', 'scheduled', 'webhook', 'event' | |
status | CharField(20) | 'pending', 'running', 'paused', 'completed', 'failed', 'cancelled' | |
current_step | CharField(100) | Nullable | Current step ID |
started_at | DateTimeField | auto_now_add | Execution start timestamp |
completed_at | DateTimeField | Nullable | Execution completion timestamp |
error_message | TextField | Nullable | Error details if failed |
context_data | JSONField | default=dict | Execution context/variables |
created_at | DateTimeField | auto_now_add | Creation timestamp |
Indexes: (workflow, -started_at), (tenant, status)
Constraints: None
3.3 WorkflowStep
Priority: HIGH Reason: Detailed step execution tracking
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique step identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
execution | TenantForeignKey(WorkflowExecution) | CASCADE | Parent execution |
step_id | CharField(100) | Step identifier from workflow definition | |
step_name | CharField(255) | Step name | |
step_type | CharField(50) | 'approval', 'action', 'condition', 'notification', etc. | |
status | CharField(20) | 'pending', 'running', 'completed', 'failed', 'skipped' | |
started_at | DateTimeField | Nullable | Step start timestamp |
completed_at | DateTimeField | Nullable | Step completion timestamp |
input_data | JSONField | default=dict | Step inputs |
output_data | JSONField | default=dict | Step outputs |
error_message | TextField | Nullable | Error details |
created_at | DateTimeField | auto_now_add | Creation timestamp |
Indexes: (execution, -started_at)
Constraints: None
3.4 WorkflowApproval
Priority: MEDIUM Reason: Approval step tracking
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique approval identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
step | TenantForeignKey(WorkflowStep) | CASCADE | Approval step |
approver | TenantForeignKey(User) | SET_NULL, nullable | User who must approve |
status | CharField(20) | 'pending', 'approved', 'rejected', 'expired' | |
comment | TextField | Approval/rejection comment | |
approved_at | DateTimeField | Nullable | Approval timestamp |
expires_at | DateTimeField | Nullable | Approval deadline |
created_at | DateTimeField | auto_now_add | Creation timestamp |
Indexes: (approver, status), (step, status)
Constraints: None
Gap Summary - Workflow Analysis
| Model | Priority | Status | Recommended App |
|---|---|---|---|
| Workflow | CRITICAL | Missing | New workflows app |
| WorkflowExecution | CRITICAL | Missing | New workflows app |
| WorkflowStep | HIGH | Missing | New workflows app |
| WorkflowApproval | MEDIUM | Missing | New workflows app |
TOTAL: 4 missing models (2 CRITICAL, 1 HIGH, 1 MEDIUM)
Domain 4: Audit Teams
Current Coverage: Partial (Permission model exists for RBAC, but no audit logging)
Existing Models
- ✅
Permission(permissions app) - RBAC definitions - ✅
TaskActivity,DocumentActivity(if implemented from PM/DMS domains)
Missing Models
4.1 AuditLog
Priority: HIGH Reason: Compliance and security audit trail (critical for enterprise customers)
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique audit log identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
user | ForeignKey(User) | SET_NULL, nullable | User who performed action |
action | CharField(100) | Action performed (e.g., 'user.login', 'document.delete', 'permission.grant') | |
resource_type | CharField(100) | Resource type affected (e.g., 'User', 'Document', 'Project') | |
resource_id | CharField(255) | Nullable | Resource UUID |
ip_address | GenericIPAddressField | Nullable | Client IP address |
user_agent | CharField(500) | Browser user agent | |
request_method | CharField(10) | HTTP method (GET, POST, etc.) | |
request_path | CharField(1000) | Request URL path | |
changes | JSONField | default=dict | Before/after values for updates |
metadata | JSONField | default=dict | Additional context |
severity | CharField(20) | 'info', 'warning', 'error', 'critical' | |
created_at | DateTimeField | auto_now_add | Audit timestamp |
Indexes: (tenant, -created_at), (user, -created_at), (resource_type, resource_id), action, severity
Constraints: None
Business Rules:
- Immutable (no updates or deletes)
- Retention policy: 1 year minimum for compliance
- Indexed for fast queries (dashboard analytics)
4.2 AuditReview
Priority: MEDIUM Reason: Track manual audit reviews for compliance
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique review identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
reviewer | TenantForeignKey(User) | SET_NULL, nullable | User conducting review |
review_type | CharField(50) | 'security', 'compliance', 'access', 'data' | |
scope_start_date | DateField | Review period start | |
scope_end_date | DateField | Review period end | |
status | CharField(20) | 'in_progress', 'completed', 'cancelled' | |
findings | TextField | Review findings | |
recommendations | TextField | Recommendations | |
created_at | DateTimeField | auto_now_add | Review start timestamp |
completed_at | DateTimeField | Nullable | Review completion timestamp |
Indexes: (tenant, -created_at), (reviewer, status)
Constraints: None
4.3 ComplianceReport
Priority: LOW Reason: Automated compliance reporting (post-MVP)
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique report identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
report_type | CharField(50) | 'gdpr', 'hipaa', 'soc2', 'iso27001' | |
period_start | DateField | Reporting period start | |
period_end | DateField | Reporting period end | |
status | CharField(20) | 'generating', 'completed', 'failed' | |
report_data | JSONField | default=dict | Report metrics and findings |
file_path | CharField(500) | Nullable | Generated PDF report path |
generated_by | TenantForeignKey(User) | SET_NULL, nullable | User who requested report |
created_at | DateTimeField | auto_now_add | Report generation timestamp |
Indexes: (tenant, -created_at), report_type
Constraints: None
Gap Summary - Audit Teams
| Model | Priority | Status | Recommended App |
|---|---|---|---|
| AuditLog | HIGH | Missing | New audit app |
| AuditReview | MEDIUM | Missing | New audit app |
| ComplianceReport | LOW | Missing | New audit app |
TOTAL: 3 missing models (0 CRITICAL, 1 HIGH, 2 MEDIUM/LOW)
Domain 5: Billing/Invoicing/Payment
Current Coverage: Partial (Order, Invoice, Subscription exist, but payment details missing)
Existing Models
- ✅
Order(commerce app) - Order records - ✅
Invoice(subscriptions app) - Invoice records synced from Stripe - ✅
Subscription(subscriptions app) - Subscription management - ✅
Tenant(tenants app) - Hasstripe_customer_id,stripe_subscription_id
Missing Models
5.1 Payment
Priority: HIGH Reason: Detailed payment transaction tracking (separate from orders)
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique payment identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
order | TenantForeignKey(Order) | SET_NULL, nullable | Linked order |
invoice | TenantForeignKey(Invoice) | SET_NULL, nullable | Linked invoice |
stripe_payment_intent_id | CharField(255) | Unique | Stripe PaymentIntent ID |
stripe_charge_id | CharField(255) | Nullable | Stripe Charge ID |
amount_cents | IntegerField | Payment amount in cents | |
currency | CharField(3) | default='usd' | Currency code |
status | CharField(20) | 'pending', 'processing', 'succeeded', 'failed', 'refunded', 'cancelled' | |
payment_method | CharField(50) | 'card', 'bank_account', 'google_pay', 'apple_pay' | |
card_last4 | CharField(4) | Nullable | Last 4 digits of card |
card_brand | CharField(20) | Nullable | Card brand (visa, mastercard, etc.) |
failure_code | CharField(50) | Nullable | Stripe failure code |
failure_message | CharField(500) | Nullable | Failure reason |
created_at | DateTimeField | auto_now_add | Payment creation timestamp |
succeeded_at | DateTimeField | Nullable | Payment success timestamp |
refunded_at | DateTimeField | Nullable | Refund timestamp |
Indexes: (tenant, -created_at), stripe_payment_intent_id, status
Constraints: None
5.2 Refund
Priority: MEDIUM Reason: Track refund transactions
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique refund identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
payment | TenantForeignKey(Payment) | CASCADE | Original payment |
stripe_refund_id | CharField(255) | Unique | Stripe Refund ID |
amount_cents | IntegerField | Refund amount in cents | |
currency | CharField(3) | default='usd' | Currency code |
reason | CharField(100) | 'duplicate', 'fraudulent', 'requested_by_customer' | |
status | CharField(20) | 'pending', 'succeeded', 'failed', 'cancelled' | |
refunded_by | TenantForeignKey(User) | SET_NULL, nullable | User who initiated refund |
created_at | DateTimeField | auto_now_add | Refund creation timestamp |
succeeded_at | DateTimeField | Nullable | Refund success timestamp |
Indexes: (payment, -created_at), stripe_refund_id
Constraints: None
5.3 TaxRate
Priority: MEDIUM Reason: Tax calculation for billing (required for compliance)
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique tax rate identifier |
stripe_tax_rate_id | CharField(255) | Unique | Stripe TaxRate ID |
display_name | CharField(100) | Display name (e.g., "VAT (20%)") | |
percentage | DecimalField(5,2) | Tax percentage (e.g., 20.00) | |
jurisdiction | CharField(100) | Tax jurisdiction (e.g., "EU", "CA", "US-NY") | |
country_code | CharField(2) | ISO 3166-1 alpha-2 country code | |
state_code | CharField(10) | Nullable | State/province code |
tax_type | CharField(20) | 'vat', 'gst', 'sales_tax' | |
inclusive | BooleanField | default=False | Tax included in price |
active | BooleanField | default=True | Tax rate active |
created_at | DateTimeField | auto_now_add | Creation timestamp |
updated_at | DateTimeField | auto_now | Last update timestamp |
Indexes: (country_code, state_code), active
Constraints: None
5.4 BillingAddress
Priority: HIGH Reason: Proper billing address storage (currently in Order.billing_details JSONField)
RECOMMENDATION: Enhance existing Order.billing_details JSONField OR create dedicated model.
If creating dedicated model:
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique address identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
address_type | CharField(20) | 'billing', 'shipping' | |
full_name | CharField(255) | Full name | |
company_name | CharField(255) | Nullable | Company name |
address_line1 | CharField(255) | Address line 1 | |
address_line2 | CharField(255) | Nullable | Address line 2 |
city | CharField(100) | City | |
state | CharField(100) | Nullable | State/province |
postal_code | CharField(20) | Postal/ZIP code | |
country_code | CharField(2) | ISO 3166-1 alpha-2 country code | |
phone | CharField(50) | Nullable | Phone number |
is_default | BooleanField | default=False | Default address for tenant |
created_at | DateTimeField | auto_now_add | Creation timestamp |
updated_at | DateTimeField | auto_now | Last update timestamp |
Indexes: (tenant, is_default)
Constraints: At most one is_default=True per tenant
Gap Summary - Billing/Invoicing/Payment
| Model | Priority | Status | Recommended App |
|---|---|---|---|
| Payment | HIGH | Missing | commerce or subscriptions |
| Refund | MEDIUM | Missing | commerce or subscriptions |
| TaxRate | MEDIUM | Missing | commerce or subscriptions |
| BillingAddress | HIGH | Partial (in JSONField) | commerce or new contacts app |
TOTAL: 4 missing/partial models (2 HIGH, 2 MEDIUM)
Domain 6: Contact Management
Current Coverage: None (email only in Tenant and User models)
Missing Models
6.1 Address
Priority: HIGH Reason: Multiple addresses per entity (billing vs shipping, multiple offices)
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique address identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
entity_type | CharField(50) | 'tenant', 'user', 'order' | |
entity_id | UUIDField | Related entity UUID | |
address_type | CharField(20) | 'billing', 'shipping', 'office', 'home' | |
label | CharField(100) | Nullable | Custom label (e.g., "HQ", "West Coast Office") |
full_name | CharField(255) | Nullable | Recipient name |
company_name | CharField(255) | Nullable | Company name |
address_line1 | CharField(255) | Address line 1 | |
address_line2 | CharField(255) | Nullable | Address line 2 |
city | CharField(100) | City | |
state | CharField(100) | Nullable | State/province |
postal_code | CharField(20) | Postal/ZIP code | |
country_code | CharField(2) | ISO 3166-1 alpha-2 country code | |
latitude | DecimalField(9,6) | Nullable | Latitude for geocoding |
longitude | DecimalField(9,6) | Nullable | Longitude for geocoding |
is_default | BooleanField | default=False | Default address for this entity + type |
is_verified | BooleanField | default=False | Address verified (e.g., via USPS API) |
created_at | DateTimeField | auto_now_add | Creation timestamp |
updated_at | DateTimeField | auto_now | Last update timestamp |
Indexes: (tenant, entity_type, entity_id), (tenant, is_default)
Constraints: GenericForeignKey pattern for entity_type + entity_id
6.2 PhoneNumber
Priority: MEDIUM Reason: Multiple phone numbers per entity (work, mobile, home, fax)
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique phone number identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
entity_type | CharField(50) | 'tenant', 'user' | |
entity_id | UUIDField | Related entity UUID | |
phone_type | CharField(20) | 'work', 'mobile', 'home', 'fax' | |
label | CharField(100) | Nullable | Custom label |
country_code | CharField(5) | Country dialing code (e.g., "+1", "+44") | |
phone_number | CharField(50) | Phone number (E.164 format preferred) | |
extension | CharField(20) | Nullable | Extension number |
is_default | BooleanField | default=False | Default phone for this entity |
is_verified | BooleanField | default=False | Phone number verified (via SMS) |
created_at | DateTimeField | auto_now_add | Creation timestamp |
updated_at | DateTimeField | auto_now | Last update timestamp |
Indexes: (tenant, entity_type, entity_id), (tenant, is_default)
Constraints: GenericForeignKey pattern for entity_type + entity_id
6.3 EmailAddress
Priority: LOW Reason: Multiple emails per user (work, personal, notification-only)
NOTE: Currently email is single field in User and Tenant. This model enables multiple emails.
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUIDField | PK | Unique email identifier |
tenant | ForeignKey(Tenant) | CASCADE | Organization |
entity_type | CharField(50) | 'tenant', 'user' | |
entity_id | UUIDField | Related entity UUID | |
email_type | CharField(20) | 'work', 'personal', 'notification' | |
label | CharField(100) | Nullable | Custom label |
email | EmailField | Email address | |
is_default | BooleanField | default=False | Default email for this entity |
is_verified | BooleanField | default=False | Email verified (via confirmation link) |
created_at | DateTimeField | auto_now_add | Creation timestamp |
updated_at | DateTimeField | auto_now | Last update timestamp |
Indexes: (tenant, entity_type, entity_id), email
Constraints: GenericForeignKey pattern for entity_type + entity_id
Gap Summary - Contact Management
| Model | Priority | Status | Recommended App |
|---|---|---|---|
| Address | HIGH | Missing | New contacts app |
| PhoneNumber | MEDIUM | Missing | New contacts app |
| EmailAddress | LOW | Missing | New contacts app |
TOTAL: 3 missing models (1 HIGH, 1 MEDIUM, 1 LOW)
Implementation Priority Matrix
CRITICAL Priority (Blocks Pilot - Must Implement Immediately)
| Model | Domain | App | Estimated Effort |
|---|---|---|---|
| Task/Issue | Project Management | pm | 2-3 hours |
| Document | DMS | dms | 2-3 hours |
| DocumentVersion | DMS | dms | 1-2 hours |
| Workflow | Workflow Analysis | workflows | 2-3 hours |
| WorkflowExecution | Workflow Analysis | workflows | 2-3 hours |
TOTAL CRITICAL: 8 models, ~12-16 hours
HIGH Priority (MVP Required - Must Implement Before Launch)
| Model | Domain | App | Estimated Effort |
|---|---|---|---|
| Sprint | Project Management | pm | 1-2 hours |
| TaskComment | Project Management | pm | 1 hour |
| Folder | DMS | dms | 1-2 hours |
| DocumentPermission | DMS | dms | 2-3 hours |
| WorkflowStep | Workflow Analysis | workflows | 1-2 hours |
| AuditLog | Audit Teams | audit | 2-3 hours |
| Payment | Billing | commerce | 2-3 hours |
| BillingAddress | Contact | contacts | 1-2 hours |
| Address | Contact | contacts | 2-3 hours |
TOTAL HIGH: 15 models, ~15-23 hours
MEDIUM Priority (Post-Launch - Can Implement After Pilot)
| Model | Domain | App | Estimated Effort |
|---|---|---|---|
| Milestone | Project Management | pm | 1-2 hours |
| TaskAttachment | Project Management | pm | 1-2 hours |
| TaskActivity | Project Management | pm | 1-2 hours |
| DocumentActivity | DMS | dms | 1-2 hours |
| DocumentShare | DMS | dms | 2-3 hours |
| WorkflowApproval | Workflow Analysis | workflows | 1-2 hours |
| AuditReview | Audit Teams | audit | 1-2 hours |
| Refund | Billing | commerce | 1-2 hours |
| TaxRate | Billing | commerce | 1-2 hours |
| PhoneNumber | Contact | contacts | 1-2 hours |
TOTAL MEDIUM: 9 models, ~12-20 hours
LOW Priority (Future Enhancements)
| Model | Domain | App | Estimated Effort |
|---|---|---|---|
| Board/KanbanBoard | Project Management | pm | 3-4 hours |
| ComplianceReport | Audit Teams | audit | 2-3 hours |
| EmailAddress | Contact | contacts | 1-2 hours |
TOTAL LOW: 3 models, ~6-9 hours
Field-Level Gaps in Existing Models
Users App
User Model - Missing Fields
| Missing Field | Type | Priority | Reason |
|---|---|---|---|
phone_number | CharField(50) | MEDIUM | Contact information |
avatar_url | URLField | LOW | User profile picture |
timezone | CharField(50) | MEDIUM | User timezone for scheduling |
language | CharField(10) | MEDIUM | Preferred language (i18n) |
notification_preferences | JSONField | MEDIUM | Email/Slack/webhook notification settings |
Tenants App
Tenant Model - Missing Fields
| Missing Field | Type | Priority | Reason |
|---|---|---|---|
phone_number | CharField(50) | MEDIUM | Organization contact |
website | URLField | LOW | Organization website |
industry | CharField(100) | LOW | Industry category |
company_size | CharField(20) | LOW | 'small', 'medium', 'large', 'enterprise' |
billing_email | EmailField | HIGH | Separate billing contact email |
tax_id | CharField(100) | HIGH | Tax ID (VAT, EIN, etc.) for invoicing |
Commerce App
Order Model - Missing Fields
| Missing Field | Type | Priority | Reason |
|---|---|---|---|
tax_cents | IntegerField | HIGH | Tax amount (separate from total) |
discount_cents | IntegerField | MEDIUM | Discount amount applied |
discount_code | CharField(50) | MEDIUM | Promo/coupon code used |
shipping_address | JSONField | MEDIUM | Shipping address (if different from billing) |
Cart Model - Missing Fields
| Missing Field | Type | Priority | Reason |
|---|---|---|---|
discount_code | CharField(50) | MEDIUM | Applied promo code |
discount_cents | IntegerField | MEDIUM | Discount amount |
tax_cents | IntegerField | HIGH | Calculated tax |
Subscriptions App
Subscription Model - Missing Fields
| Missing Field | Type | Priority | Reason |
|---|---|---|---|
trial_start | DateTimeField | HIGH | Trial period start |
trial_end | DateTimeField | HIGH | Trial period end |
billing_cycle_anchor | IntegerField | MEDIUM | Day of month for billing |
Multi-Tenant Compliance Issues
Issues Identified
1. workstations App - Using CharField for tenant_id
Issue: All workstation models use tenant_id = CharField(63) instead of ForeignKey(Tenant)
Impact: MEDIUM - No foreign key constraint, manual filtering required
Recommendation: Change to:
tenant = models.ForeignKey('tenants.Tenant', on_delete=models.CASCADE)
Affected Models:
- Workstation
- SharedWorkstation
- WorkstationUserAccess
- WorkstationUsageRecord
2. repositories App - Using CharField for tenant_id
Issue: GiteaOrganization uses tenant_id = CharField(63) instead of FK
Impact: MEDIUM - No foreign key constraint
Recommendation: Change to:
tenant = models.ForeignKey('tenants.Tenant', on_delete=models.CASCADE)
Affected Models:
- GiteaOrganization (then cascade via FK to Repository, etc.)
3. licenses App - Not Using TenantModel
Issue: License and Session use ForeignKey(Tenant) but don't inherit TenantModel
Impact: LOW - Still has tenant isolation, but not using django-multitenant automatic filtering
Recommendation: Consider migrating to TenantModel for consistency:
class License(TenantModel):
tenant_id = 'tenant_id'
tenant = models.ForeignKey('tenants.Tenant', on_delete=models.CASCADE, db_column='tenant_id')
4. Cart Model - Global (No Tenant)
Issue: Cart model has no tenant association (supports guest checkout)
Impact: LOW - By design for guest users
Recommendation: Keep as-is. Once user signs in, associate cart with user's tenant.
Recommendations
Immediate Actions (Next 48 Hours - Before Pilot Launch)
1. Implement CRITICAL Models (12-16 hours)
Create new Django apps:
pm- Project Management (Task, Sprint)dms- Document Management System (Document, DocumentVersion, Folder)workflows- Workflow Analysis (Workflow, WorkflowExecution)
Commands:
cd backend
python manage.py startapp pm
python manage.py startapp dms
python manage.py startapp workflows
Migrations:
python manage.py makemigrations
python manage.py migrate
2. Implement HIGH Priority Models (15-23 hours)
- Add remaining PM models (TaskComment, Sprint)
- Add remaining DMS models (Folder, DocumentPermission)
- Add remaining Workflow models (WorkflowStep)
- Add Audit model (AuditLog)
- Add Billing models (Payment, BillingAddress)
- Add Contact models (Address)
3. Fix Multi-Tenant Compliance (2-3 hours)
- Migrate workstations app to use ForeignKey(Tenant)
- Migrate repositories app to use ForeignKey(Tenant)
- Run migrations
4. Add Missing Fields to Existing Models (1-2 hours)
Priority fields:
Tenant.billing_emailTenant.tax_idOrder.tax_centsCart.tax_centsSubscription.trial_start,trial_end
Post-Pilot Actions (Week 1-2 After Launch)
- Implement MEDIUM priority models (12-20 hours)
- Add remaining field gaps
- Create comprehensive admin interfaces
- Build audit dashboards
- Implement workflow UI
Long-Term Roadmap (Months 2-3)
- Implement LOW priority models
- Advanced reporting and analytics
- AI-powered workflow recommendations
- Advanced compliance features
- Mobile apps for PM and DMS
Summary Statistics
Missing Models by Priority
| Priority | Count | Total Effort |
|---|---|---|
| CRITICAL | 8 | 12-16 hours |
| HIGH | 15 | 15-23 hours |
| MEDIUM | 9 | 12-20 hours |
| LOW | 3 | 6-9 hours |
| TOTAL | 35 | 45-68 hours |
Missing Models by Domain
| Domain | Missing Models | CRITICAL | HIGH | MEDIUM | LOW |
|---|---|---|---|---|---|
| Project Management | 7 | 1 | 2 | 3 | 1 |
| DMS | 6 | 2 | 2 | 2 | 0 |
| Workflow Analysis | 4 | 2 | 1 | 1 | 0 |
| Audit Teams | 3 | 0 | 1 | 1 | 1 |
| Billing/Payment | 4 | 0 | 2 | 2 | 0 |
| Contact Management | 3 | 0 | 1 | 1 | 1 |
| TOTAL | 35 | 8 | 15 | 9 | 3 |
Field-Level Gaps
| App | Model | Missing Fields | Priority |
|---|---|---|---|
| users | User | 5 | MEDIUM |
| tenants | Tenant | 6 | HIGH |
| commerce | Order | 4 | HIGH |
| commerce | Cart | 3 | HIGH |
| subscriptions | Subscription | 3 | HIGH |
Critical Path for Pilot Launch
Deadline: December 24, 2025 (2 days remaining)
Must-Have for Pilot:
- ✅ User authentication (exists)
- ✅ Multi-tenant isolation (exists)
- ✅ Commerce (products, cart, checkout) (exists)
- ❌ Project Management - Task tracking (MISSING - CRITICAL)
- ❌ Document Management - Document storage (MISSING - CRITICAL for DMS product)
- ❌ Workflow Analysis - Workflow execution (MISSING - CRITICAL for Workflow Analyzer product)
- ✅ Subscriptions and billing (exists)
- ❌ Audit logging (MISSING - HIGH priority for enterprise)
BLOCKER: Cannot launch DMS addon product without Document + DocumentVersion models. BLOCKER: Cannot launch Workflow Analyzer addon product without Workflow + WorkflowExecution models. BLOCKER: Cannot provide project management features without Task model.
Recommendation: DELAY PILOT LAUNCH by 2-3 days to implement CRITICAL models OR REDUCE SCOPE to launch with Core product only (no DMS, no Workflow Analyzer).
End of data-model-gap-analysis.md