Files
bellsystems-cp/.claude/crm-step-04.md

97 lines
3.7 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.
# CRM Step 04 — Backend: Comms Log + Media (SQLite)
## Context
Read `.claude/crm-build-plan.md` for full schema, conventions, and IMPORTANT NOTES.
Steps 0103 must be complete.
## Task
Add `crm_comms_log` and `crm_media` tables to the existing SQLite DB, plus CRUD endpoints.
## What to build
### 1. Add tables to `backend/mqtt/database.py`
Inside `init_db()`, add these CREATE TABLE IF NOT EXISTS statements alongside existing tables:
```sql
CREATE TABLE IF NOT EXISTS crm_comms_log (
id TEXT PRIMARY KEY,
customer_id TEXT NOT NULL,
type TEXT NOT NULL,
direction TEXT NOT NULL,
subject TEXT,
body TEXT,
attachments TEXT DEFAULT '[]',
ext_message_id TEXT,
logged_by TEXT,
occurred_at TEXT NOT NULL,
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS crm_media (
id TEXT PRIMARY KEY,
customer_id TEXT,
order_id TEXT,
filename TEXT NOT NULL,
nextcloud_path TEXT NOT NULL,
mime_type TEXT,
direction TEXT,
tags TEXT DEFAULT '[]',
uploaded_by TEXT,
created_at TEXT NOT NULL
);
```
### 2. Add to `backend/crm/models.py`
**Comms:**
- `CommType` enum — email, whatsapp, call, sms, note, in_person
- `CommDirection` enum — inbound, outbound, internal
- `CommAttachment` — filename (str), nextcloud_path (str)
- `CommCreate` — customer_id, type (CommType), direction (CommDirection), subject (Optional[str]), body (Optional[str]), attachments (List[CommAttachment] default []), ext_message_id (Optional[str]), logged_by (Optional[str]), occurred_at (str ISO — default to now if not provided)
- `CommUpdate` — subject, body, occurred_at all Optional
- `CommInDB` — all fields + id, created_at
- `CommListResponse` — entries: List[CommInDB], total: int
**Media:**
- `MediaDirection` enum — received, sent, internal
- `MediaCreate` — customer_id (Optional[str]), order_id (Optional[str]), filename, nextcloud_path, mime_type (Optional), direction (MediaDirection optional), tags (List[str] default []), uploaded_by (Optional[str])
- `MediaInDB` — all fields + id, created_at
- `MediaListResponse` — items: List[MediaInDB], total: int
### 3. Add to `backend/crm/service.py`
Import `from mqtt import database as mqtt_db` for aiosqlite access.
**Comms functions (all async):**
- `list_comms(customer_id, type=None, direction=None, limit=100) -> List[CommInDB]`
— SELECT ... WHERE customer_id=? ORDER BY occurred_at DESC
- `get_comm(comm_id) -> CommInDB` — 404 if not found
- `create_comm(data: CommCreate) -> CommInDB` — uuid id, created_at now, store attachments as JSON string
- `update_comm(comm_id, data: CommUpdate) -> CommInDB`
- `delete_comm(comm_id) -> None`
**Media functions (all async):**
- `list_media(customer_id=None, order_id=None) -> List[MediaInDB]`
- `create_media(data: MediaCreate) -> MediaInDB`
- `delete_media(media_id) -> None`
Parse `attachments` and `tags` JSON strings back to lists when returning models.
### 4. Add to `backend/crm/router.py`
Prefix `/api/crm/comms`:
- `GET /` — list_comms (query: customer_id required, type, direction)
- `POST /` — create_comm
- `PUT /{comm_id}` — update_comm
- `DELETE /{comm_id}` — delete_comm
Prefix `/api/crm/media`:
- `GET /` — list_media (query: customer_id or order_id)
- `POST /` — create_media (metadata only — no file upload here, that's Step 9)
- `DELETE /{media_id}` — delete_media
Register both in `backend/main.py`.
## Notes
- Use `mqtt_db.db` — it is an aiosqlite connection, use `async with mqtt_db.db.execute(...)` pattern
- Look at `backend/mqtt/database.py` for exact aiosqlite usage pattern
- attachments and tags are stored as JSON strings in SQLite, deserialized to lists in the Pydantic model