Files
vela-platform/CLAUDE.md
oimwiodev d1160673a7 🎉 v1.0.0 — Vela Platform launch
Self-hosted P&L tracking app with component-level pricing.
Offers: Atlas/Atlas+/Rif/Rif+ with granular cost breakdown.
API + MCP + multi-user auth.
2026-06-15 23:05:59 +01:00

4.2 KiB

Vela Platform 🏔️

A lightweight self-hosted P&L tracking app for a C2C server/storage business.

Stack

  • Python 3.11+ with FastAPI + uvicorn
  • SQLite via SQLAlchemy (single file, zero setup)
  • Jinja2 templates + Bootstrap 5 dark frontend
  • Chart.js for trend charts
  • JWT auth (cookie + Bearer header)
  • stdio MCP server for Hermes integration

Data Model

User

  • id, username, password_hash, display_name, role (admin|viewer)

Service (Offer)

  • id, name (Atlas/Atlas+/Rif/Rif+), description
  • sell_price (computed from components), cost_price (computed from components)
  • active

ServiceComponent

  • id, service_id (FK), name (RAM/HDD/SSD/etc.), unit_cost, unit_sell, quantity, notes
  • recompute_prices() method sums cost/sell from components

Transaction

  • id, service_id (FK), quantity, revenue (calculated: qty * service.sell_price), cost (calculated: qty * service.cost_price), month (YYYY-MM), notes, created_by (FK user), created_at

Monthly P&L (computed)

  • month, total_revenue, total_cost, gross_profit, gross_margin%, opex (800 MAD), net_profit, net_margin%

Preseed Data

  • Users: admin (password: admin123), viewer (password: viewer123)
  • Services with components (see COMPONENT_TEMPLATES in main.py)
  • Opex: 800 MAD/month hardcoded

Key Files

Path What
backend/main.py FastAPI app (API + frontend routes)
backend/models.py SQLAlchemy models
backend/auth.py JWT auth, cookie support
backend/database.py SQLite setup
backend/templates/ Jinja2 templates
mcp/server.py MCP stdio server
CLAUDE.md This file

API Endpoints

Auth

  • POST /api/auth/login -> {token, user} + set cookie
  • GET /api/auth/me -> current user

Services

  • GET /api/services -> list with components
  • GET /api/services/{id} -> single with components
  • POST /api/services -> create (admin)
  • PUT /api/services/{id} -> update (admin)
  • DELETE /api/services/{id} -> deactivate (admin)

Components

  • GET /api/services/{id}/components -> list
  • POST /api/services/{id}/components -> create (admin, JSON body)
  • PUT /api/components/{id} -> update (admin, JSON body) — auto-recomputes prices
  • DELETE /api/components/{id} -> delete (admin) — auto-recomputes prices

Transactions

  • GET /api/transactions?month=YYYY-MM -> list
  • POST /api/transactions -> create {service_id, quantity, month, notes}
  • DELETE /api/transactions/{id} -> (admin)

P&L

  • GET /api/pnl?month=YYYY-MM -> computed P&L
  • GET /api/dashboard -> current + 12-month trend

MCP Server (stdio)

Located at mcp/server.py. Run as a stdio MCP server via python3 mcp/server.py.

Tools: get_pnl, get_services, get_service, add_component, update_component, delete_component, add_transaction, get_dashboard Resources: vela://pnl/current, vela://services, vela://services/{id}

URLs

Component Pricing Templates

Each offer has its own set of components. The total sell/cost is auto-computed:

Atlas (1TB Storage)

HDD(1TB) 600/1000, RAM(16GB) 300/500, CPU alloc 200/400, Casing 200/300, Bandwidth 200/500, Setup 300/600, Support 200/700 → Total: cost 2000, sell 4000

Atlas+ (1TB + Backup)

HDD(1TB) 600/1000, SSD(256GB) 400/700, RAM(32GB) 600/1000, CPU alloc 300/600, Casing 200/300, Bandwidth 200/500, Sauvegarde 300/500, Setup 200/400, Support 200/700 → Total: cost 2800, sell 5000

Rif (500GB Server)

SSD(500GB) 300/600, RAM(16GB) 300/500, CPU alloc 200/400, Casing 200/300, Bandwidth 200/500, Setup 300/600, Support 200/700 → Total: cost 1700, sell 3500

Rif+ (500GB + Backup)

SSD(500GB) 300/600, HDD(1TB) 600/1000, RAM(32GB) 600/1000, CPU alloc 300/600, Casing 200/300, Bandwidth 200/500, Sauvegarde 300/500, Setup 200/400, Support 200/700 → Total: cost 2200, sell 4500

Deployment

cd ~/bestof-manager/backend && uvicorn main:app --host 0.0.0.0 --port 8788
# Or via systemd:
systemctl --user restart bestof-manager.service

Auth Flow

  • Page routes use cookie auth (httpOnly 'token' cookie set on login)
  • API routes use Bearer token from Authorization header
  • Login sets both cookie AND returns JSON token
  • Token expires after 24h
  • Pages without valid cookie redirect to /login