update: Major Overhaul to all subsystems

This commit is contained in:
2026-03-07 11:32:18 +02:00
parent 810e81b323
commit c62188fda6
107 changed files with 20414 additions and 929 deletions

96
.claude/crm-step-04.md Normal file
View File

@@ -0,0 +1,96 @@
# 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