# Phase 6.1 — Enterprise CRM Core Business Entities | Field | Value | | --- | --- | | Status | Complete | | Module | crm | | Version | 0.6.1.0 | | Database | `crm_db` | | Migration | `0002_phase_61_entities` | | Depends On | Phase 6.0 | ## Goal Implement the Sales CRM **core business entities** only: leads, contacts, organizations, lookups, tags, addresses, custom fields, notes, attachments (file references), and audit. Out of scope: Workflow, Automation, Customer360, Marketing, Communication, Helpdesk, Analytics, AI, Accounting / Restaurant / Marketplace integrations. ## Created Models ### Core aggregates (expanded) | Model | Table | Notes | | --- | --- | --- | | Lead | `leads` | lead_number, names, company, phones, source/status refs, owner, priority, soft delete, actors | | Contact | `contacts` | personal/business, multi phone/email JSON, social links, birthday, soft delete | | Organization | `organizations` | company/branch/department, legal/trade names, tax IDs, parent org, soft delete | ### Lookups | Model | Table | | --- | --- | | LeadSource | `lead_sources` | | LeadStatusDefinition | `lead_statuses` | | ContactType | `contact_types` | | OrganizationType | `organization_types` | | OrganizationIndustry | `organization_industries` | ### Supporting | Model | Table | | --- | --- | | LeadAssignment | `lead_assignments` | | CrmTag | `crm_tags` | | LeadTag / ContactTag / OrganizationTag | `lead_tags`, `contact_tags`, `organization_tags` | | CrmCustomField / CrmCustomFieldValue | `crm_custom_fields`, `crm_custom_field_values` | | CrmAddress | `crm_addresses` | | CrmNote / CrmNoteVersion | `crm_notes`, `crm_note_versions` | | CrmAttachment | `crm_attachments` (file_storage_id only) | | CrmAuditLog | `crm_audit` | Phase 6.0 aggregates retained: Pipeline, PipelineStage, Opportunity, SalesActivity, Quote. ## Relationships UUID references within `crm_db` only (no SQLAlchemy relationship graphs between aggregates): - Lead → `lead_source_id`, `lead_status_id`, `contact_id`, `organization_id` - Contact → `contact_type_id`, `organization_id` - Organization → `organization_type_id`, `organization_industry_id`, `parent_organization_id` - Addresses / Notes / Attachments / CustomFieldValues → `(entity_type, entity_id)` - Tag join tables → entity id + `tag_id` - Attachment → `file_storage_id` (File Storage service contract) ## ER Diagram ```mermaid erDiagram LEAD ||--o{ LEAD_ASSIGNMENT : assigns LEAD ||--o{ LEAD_TAG : tagged CONTACT ||--o{ CONTACT_TAG : tagged ORGANIZATION ||--o{ ORGANIZATION_TAG : tagged CRM_TAG ||--o{ LEAD_TAG : used CRM_TAG ||--o{ CONTACT_TAG : used CRM_TAG ||--o{ ORGANIZATION_TAG : used LEAD_SOURCE ||--o{ LEAD : sources LEAD_STATUS ||--o{ LEAD : statuses CONTACT_TYPE ||--o{ CONTACT : types ORGANIZATION_TYPE ||--o{ ORGANIZATION : types ORGANIZATION_INDUSTRY ||--o{ ORGANIZATION : industries ORGANIZATION ||--o{ ORGANIZATION : parent CRM_CUSTOM_FIELD ||--o{ CRM_CUSTOM_FIELD_VALUE : values LEAD ||--o{ CRM_ADDRESS : addresses LEAD ||--o{ CRM_NOTE : notes CRM_NOTE ||--o{ CRM_NOTE_VERSION : versions LEAD ||--o{ CRM_ATTACHMENT : attachments LEAD ||--o{ CRM_AUDIT : audited ``` ## Business Rules - Lead number unique per tenant; auto-generated when omitted (`LEAD-XXXXXXXXXX`) - Lead owner required - Soft delete + restore for Lead / Contact / Organization / Address / Note / Attachment - Organization name unique per tenant; parent cannot be self - Attachment stores **reference only** (no binary in CRM) - Notes are versioned on body update - Custom fields are per-tenant and per-entity with typed validation ## Validation Rules | Area | Rules | | --- | --- | | Email | RFC-ish format, lowercased | | Phone / Mobile | 5–30 chars of digits/spaces/`+()-` | | Owner | non-empty | | Lead status | known enum / status definition | | Amount | non-negative | | Custom fields | type match; required; select option membership | | Attachment | `file_storage_id` + `file_name` required | | Address | `line1` required | ## Events | Event | When | | --- | --- | | `crm.lead.created` / `crm.lead.updated` | Lead create/update | | `crm.contact.created` | Contact create | | `crm.organization.created` | Organization create | | `crm.note.created` | Note create | | `crm.attachment.added` | Attachment reference create | ## Permissions `crm.leads.*`, `crm.contacts.*`, `crm.organizations.*`, `crm.notes.*`, `crm.attachments.*`, `crm.customfields.*` (+ existing 6.0 trees). ## API Endpoints | Area | Paths | | --- | --- | | Leads | `POST/GET/PATCH /api/v1/leads`, `/assign`, `/delete`, `/restore` | | Contacts | `POST/GET/PATCH /api/v1/contacts`, `/delete` | | Organizations | `POST/GET/PATCH /api/v1/organizations`, `/delete` | | Lookups | `/api/v1/lookups/lead-sources\|lead-statuses\|contact-types\|organization-types\|organization-industries` | | Tags | `/api/v1/tags`, `/tags/leads\|contacts\|organizations/{id}` | | Addresses | `/api/v1/addresses` | | Notes | `/api/v1/notes` | | Attachments | `/api/v1/attachments` | | Custom fields | `/api/v1/custom-fields`, `/custom-fields/values` | | Audit | `/api/v1/audit` | ## Migration Summary - Alembic revision `0002_phase_61_entities` (down_revision `0001_initial`) - Expands metadata via `create_all` for additive tables/columns on fresh installs - Indexes on tenant + status/email/owner/entity polymorphic keys - Unique constraints: lead_number, org name, lookup codes, tag names, custom field keys ## Services / Repositories / Validators | Service | Repository | | --- | --- | | LeadService | LeadRepository (+ LeadAssignmentRepository) | | ContactService | ContactRepository | | OrganizationService | OrganizationRepository | | AddressService | CrmAddressRepository | | TagService | CrmTagRepository + join repos | | CustomFieldService | CrmCustomField* repositories | | AttachmentService | CrmAttachmentRepository | | NoteService | CrmNote* repositories | | AuditService | CrmAuditLogRepository | | LookupService | lookup repositories | Validators live in `app/validators/` (lead/contact/org/address/tag/custom field/attachment rules). ## Tests Executed - Model / architecture / dependency - Repository / service / validation / audit - API / permission / migration / tenant isolation - Documentation validation ## Known Limitations - File Storage resolve is contract-only (`FileStorageProvider`); no live S3/upload in CRM - Multi phone/email stored as JSON arrays (not separate child tables) - Schema evolution on already-applied 6.0 Postgres may need operational `ALTER` if 0001 ran with old columns only - No Automation / Customer360 consumption yet ## Next Phase Phase 6.2 completed — see [crm-phase-6-2.md](crm-phase-6-2.md). CRM Core Platform complete through [crm-phase-6-3.md](crm-phase-6-3.md). ## Related Documents - [crm-phase-6-0.md](crm-phase-6-0.md) - [Module Registry](module-registry.md#crm) - [Service README](../backend/services/crm/README.md) - [Progress](progress.md)