update: Major Overhaul to all subsystems
This commit is contained in:
243
.claude/crm-build-plan.md
Normal file
243
.claude/crm-build-plan.md
Normal file
@@ -0,0 +1,243 @@
|
||||
# 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`
|
||||
Reference in New Issue
Block a user