# 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)
