244 lines
6.3 KiB
Markdown
244 lines
6.3 KiB
Markdown
# BellSystems CRM — Build Plan & Step Prompts
|
||
|
||
## Overview
|
||
|
||
A bespoke CRM module built directly into the existing BellSystems web console.
|
||
Stack: FastAPI backend (Firestore), React + Vite frontend.
|
||
No new auth — uses the existing JWT + permission system.
|
||
No file storage on VPS — all media lives on Nextcloud via WebDAV.
|
||
|
||
---
|
||
|
||
## Architecture Summary
|
||
|
||
### Backend
|
||
- New module: `backend/crm/` with `models.py`, `service.py`, `router.py`
|
||
- Firestore collections: `crm_customers`, `crm_orders`, `crm_products`
|
||
- SQLite (existing `mqtt_data.db`) for comms_log (high-write, queryable)
|
||
- Router registered in `backend/main.py` as `/api/crm`
|
||
|
||
### Frontend
|
||
- New section: `frontend/src/crm/`
|
||
- Routes added to `frontend/src/App.jsx`
|
||
- Nav entries added to `frontend/src/layout/Sidebar.jsx`
|
||
|
||
### Integrations (later steps)
|
||
- Nextcloud: WebDAV via `httpx` in backend
|
||
- Email: IMAP (read) + SMTP (send) via `imaplib` / `smtplib`
|
||
- WhatsApp: Meta Cloud API webhook
|
||
- FreePBX: Asterisk AMI socket listener
|
||
|
||
---
|
||
|
||
## Data Model Reference
|
||
|
||
### `crm_customers` (Firestore)
|
||
```json
|
||
{
|
||
"id": "auto",
|
||
"name": "Στέλιος Μπιμπης",
|
||
"organization": "Ενορία Αγ. Παρασκευής",
|
||
"contacts": [
|
||
{ "type": "email", "label": "personal", "value": "...", "primary": true },
|
||
{ "type": "phone", "label": "mobile", "value": "...", "primary": true }
|
||
],
|
||
"notes": [
|
||
{ "text": "...", "by": "user_name", "at": "ISO datetime" }
|
||
],
|
||
"location": { "city": "", "country": "", "region": "" },
|
||
"language": "el",
|
||
"tags": [],
|
||
"owned_items": [
|
||
{ "type": "console_device", "device_id": "UID", "label": "..." },
|
||
{ "type": "product", "product_id": "pid", "product_name": "...", "quantity": 1, "serial_numbers": [] },
|
||
{ "type": "freetext", "description": "...", "serial_number": "", "notes": "" }
|
||
],
|
||
"linked_user_ids": [],
|
||
"nextcloud_folder": "05_Customers/FOLDER_NAME",
|
||
"created_at": "ISO",
|
||
"updated_at": "ISO"
|
||
}
|
||
```
|
||
|
||
### `crm_orders` (Firestore)
|
||
```json
|
||
{
|
||
"id": "auto",
|
||
"customer_id": "ref",
|
||
"order_number": "ORD-2026-001",
|
||
"status": "draft",
|
||
"items": [
|
||
{
|
||
"type": "console_device|product|freetext",
|
||
"product_id": "",
|
||
"product_name": "",
|
||
"description": "",
|
||
"quantity": 1,
|
||
"unit_price": 0.0,
|
||
"serial_numbers": []
|
||
}
|
||
],
|
||
"subtotal": 0.0,
|
||
"discount": { "type": "percentage|fixed", "value": 0, "reason": "" },
|
||
"total_price": 0.0,
|
||
"currency": "EUR",
|
||
"shipping": {
|
||
"method": "",
|
||
"tracking_number": "",
|
||
"carrier": "",
|
||
"shipped_at": null,
|
||
"delivered_at": null,
|
||
"destination": ""
|
||
},
|
||
"payment_status": "pending",
|
||
"invoice_path": "",
|
||
"notes": "",
|
||
"created_at": "ISO",
|
||
"updated_at": "ISO"
|
||
}
|
||
```
|
||
|
||
### `crm_products` (Firestore)
|
||
```json
|
||
{
|
||
"id": "auto",
|
||
"name": "Vesper Plus",
|
||
"sku": "VSP-001",
|
||
"category": "controller|striker|clock|part|repair_service",
|
||
"description": "",
|
||
"price": 0.0,
|
||
"currency": "EUR",
|
||
"costs": {
|
||
"pcb": 0.0, "components": 0.0, "enclosure": 0.0,
|
||
"labor_hours": 0, "labor_rate": 0.0, "shipping_in": 0.0,
|
||
"total": 0.0
|
||
},
|
||
"stock": { "on_hand": 0, "reserved": 0, "available": 0 },
|
||
"nextcloud_folder": "02_Products/FOLDER",
|
||
"linked_device_type": "",
|
||
"active": true,
|
||
"created_at": "ISO",
|
||
"updated_at": "ISO"
|
||
}
|
||
```
|
||
|
||
### `crm_comms_log` (SQLite table — existing mqtt_data.db)
|
||
```sql
|
||
CREATE TABLE crm_comms_log (
|
||
id TEXT PRIMARY KEY,
|
||
customer_id TEXT NOT NULL,
|
||
type TEXT NOT NULL, -- email|whatsapp|call|sms|note|in_person
|
||
direction TEXT NOT NULL, -- inbound|outbound|internal
|
||
subject TEXT,
|
||
body TEXT,
|
||
attachments TEXT, -- JSON array of {filename, nextcloud_path}
|
||
ext_message_id TEXT, -- IMAP uid, WhatsApp msg id, AMI call id
|
||
logged_by TEXT,
|
||
occurred_at TEXT NOT NULL,
|
||
created_at TEXT NOT NULL
|
||
);
|
||
```
|
||
|
||
### `crm_media` (SQLite table — existing mqtt_data.db)
|
||
```sql
|
||
CREATE TABLE 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, -- received|sent|internal
|
||
tags TEXT, -- JSON array
|
||
uploaded_by TEXT,
|
||
created_at TEXT NOT NULL
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## IMPORTANT NOTES FOR ALL STEPS
|
||
|
||
- **Backend location**: `c:\development\bellsystems-cp\backend\`
|
||
- **Frontend location**: `c:\development\bellsystems-cp\frontend\`
|
||
- **Auth pattern**: All routes use `Depends(require_permission("crm", "view"))` or `"edit"`. Import from `auth.dependencies`.
|
||
- **Firestore pattern**: Use `from shared.firebase import get_db`. See `backend/devices/service.py` for reference patterns.
|
||
- **SQLite pattern**: Use `from mqtt import database as mqtt_db` — `mqtt_db.db` is the aiosqlite connection. See `backend/mqtt/database.py`.
|
||
- **Frontend auth**: `getAuthHeaders()` from `../api/auth` gives Bearer token headers. See any existing page for pattern.
|
||
- **Frontend routing**: Routes live in `frontend/src/App.jsx`. Sidebar nav in `frontend/src/layout/Sidebar.jsx`.
|
||
- **Token**: localStorage key is `"access_token"`.
|
||
- **UI pattern**: Use existing component style — `SectionCard`, `FieldRow`, inline styles for grids. See `frontend/src/devices/` for reference.
|
||
- **No new dependencies unless absolutely necessary.**
|
||
|
||
---
|
||
|
||
## Step 1 — Backend: CRM Module Scaffold + Products CRUD
|
||
|
||
**File**: `.claude/crm-step-01.md`
|
||
|
||
---
|
||
|
||
## Step 2 — Backend: Customers CRUD
|
||
|
||
**File**: `.claude/crm-step-02.md`
|
||
|
||
---
|
||
|
||
## Step 3 — Backend: Orders CRUD
|
||
|
||
**File**: `.claude/crm-step-03.md`
|
||
|
||
---
|
||
|
||
## Step 4 — Backend: Comms Log + Media (SQLite)
|
||
|
||
**File**: `.claude/crm-step-04.md`
|
||
|
||
---
|
||
|
||
## Step 5 — Frontend: Products Module
|
||
|
||
**File**: `.claude/crm-step-05.md`
|
||
|
||
---
|
||
|
||
## Step 6 — Frontend: Customers List + Detail Page
|
||
|
||
**File**: `.claude/crm-step-06.md`
|
||
|
||
---
|
||
|
||
## Step 7 — Frontend: Orders Module
|
||
|
||
**File**: `.claude/crm-step-07.md`
|
||
|
||
---
|
||
|
||
## Step 8 — Frontend: Comms Log + Media Tab (manual entry)
|
||
|
||
**File**: `.claude/crm-step-08.md`
|
||
|
||
---
|
||
|
||
## Step 9 — Integration: Nextcloud WebDAV
|
||
|
||
**File**: `.claude/crm-step-09.md`
|
||
|
||
---
|
||
|
||
## Step 10 — Integration: IMAP/SMTP Email
|
||
|
||
**File**: `.claude/crm-step-10.md`
|
||
|
||
---
|
||
|
||
## Step 11 — Integration: WhatsApp Business API
|
||
|
||
**File**: `.claude/crm-step-11.md`
|
||
|
||
---
|
||
|
||
## Step 12 — Integration: FreePBX AMI Call Logging
|
||
|
||
**File**: `.claude/crm-step-12.md`
|