TorbatYar/docs/crm-phase-6-1.md
Mortezakoohjani 064d67f099 Ship CRM Core Platform (phases 6.0–6.3) with docs and prod deploy.
Add the Sales CRM service through collaboration, sync architecture/registry docs, expose crm.torbatyar.ir, and include a production deploy script.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-24 20:32:00 +03:30

189 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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