62 lines
2.9 KiB
Markdown
62 lines
2.9 KiB
Markdown
# CRM Step 02 — Backend: Customers CRUD
|
|
|
|
## Context
|
|
Read `.claude/crm-build-plan.md` first for full data models, conventions, and IMPORTANT NOTES.
|
|
Step 01 must be complete (`backend/crm/` module exists).
|
|
|
|
## Task
|
|
Add Customers models, service, and router to `backend/crm/`.
|
|
|
|
## What to build
|
|
|
|
### 1. Add to `backend/crm/models.py`
|
|
|
|
**Contact entry:**
|
|
- `ContactType` enum — email, phone, whatsapp, other
|
|
- `CustomerContact` — type (ContactType), label (str, e.g. "personal"/"church"), value (str), primary (bool default False)
|
|
|
|
**Note entry:**
|
|
- `CustomerNote` — text (str), by (str), at (str ISO datetime)
|
|
|
|
**Owned items (3 tiers):**
|
|
- `OwnedItemType` enum — console_device, product, freetext
|
|
- `OwnedItem`:
|
|
- type: OwnedItemType
|
|
- For console_device: device_id (Optional[str]), label (Optional[str])
|
|
- For product: product_id (Optional[str]), product_name (Optional[str]), quantity (Optional[int]), serial_numbers (Optional[List[str]])
|
|
- For freetext: description (Optional[str]), serial_number (Optional[str]), notes (Optional[str])
|
|
|
|
**Location:**
|
|
- `CustomerLocation` — city (Optional[str]), country (Optional[str]), region (Optional[str])
|
|
|
|
**Customer models:**
|
|
- `CustomerCreate` — name (str), organization (Optional[str]), contacts (List[CustomerContact] default []), notes (List[CustomerNote] default []), location (Optional[CustomerLocation]), language (str default "el"), tags (List[str] default []), owned_items (List[OwnedItem] default []), linked_user_ids (List[str] default []), nextcloud_folder (Optional[str])
|
|
- `CustomerUpdate` — all fields Optional
|
|
- `CustomerInDB` — extends CustomerCreate + id, created_at, updated_at
|
|
- `CustomerListResponse` — customers: List[CustomerInDB], total: int
|
|
|
|
### 2. Add to `backend/crm/service.py`
|
|
Firestore collection: `crm_customers`
|
|
Functions:
|
|
- `list_customers(search=None, tag=None) -> List[CustomerInDB]`
|
|
- search matches against name, organization, and any contact value
|
|
- `get_customer(customer_id) -> CustomerInDB` — 404 if not found
|
|
- `create_customer(data: CustomerCreate) -> CustomerInDB`
|
|
- `update_customer(customer_id, data: CustomerUpdate) -> CustomerInDB`
|
|
- `delete_customer(customer_id) -> None`
|
|
|
|
### 3. Add to `backend/crm/router.py`
|
|
Add a second router or extend existing file with prefix `/api/crm/customers`:
|
|
- `GET /` — list_customers (query: search, tag)
|
|
- `GET /{customer_id}` — get_customer
|
|
- `POST /` — create_customer
|
|
- `PUT /{customer_id}` — update_customer
|
|
- `DELETE /{customer_id}` — delete_customer
|
|
|
|
Register this router in `backend/main.py` alongside the products router.
|
|
|
|
## Notes
|
|
- OwnedItem is a flexible struct — store all fields, service doesn't validate which fields are relevant per type (frontend handles that)
|
|
- linked_user_ids are Firebase Auth UIDs (strings) — no validation needed here, just store them
|
|
- Search in list_customers: do client-side filter after fetching all (small dataset)
|