Files
bellsystems-cp/.claude/crm-build-plan.md

6.3 KiB
Raw Blame History

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)

{
  "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)

{
  "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)

{
  "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)

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)

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_dbmqtt_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