# Command Sovereignty

B2B revenue forecasting and leak detection SaaS for home improvement companies. Connect CRM, accounting, and advertising tools — surface where revenue is being lost before it disappears.

[Live](https://builtdomains.com)

## What It Does

Command Sovereignty ties together disconnected business tools (CRM, QuickBooks, Google Ads, Five9, Jobber, etc.) into a single revenue operations view. Core features:

| Feature | Description |
|---|---|
| **Revenue Forecasting** | Project revenue, pipeline, and costs with confidence scoring |
| **Revenue Leak Detection** | Automated detectors for overdue invoices, stale CRM leads, speed-to-lead, project margin variance, and more |
| **Connector Integration** | OAuth 2.0 connections to 16+ tools: QuickBooks, HubSpot, Five9, Google Ads/Sheets, Jobber, ServiceTitan, Slack, and more |
| **Cascading Goals** | Org → department → team → rep goal trees with KPI tracking |
| **Estimate Funnel** | Track estimates from creation through close, synced with Jobber |
| **Lead Generation** | Campaign management, attribution tracking, optimization engine |
| **Coaching & Scorecards** | Coach/rep pairings with focus areas and performance tracking |
| **Multi-company Portfolios** | Super admins can manage multiple business accounts |

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│  Cloudflare Tunnel                                           │
│  builtdomains.com ───────────────────────────────────────── │
└───────────────────────────┬─────────────────────────────────┘
                            │ HTTPS
                            ▼
┌─────────────────────────────────────────────────────────────┐
│  Workstation (Debian Linux)                                  │
│                                                              │
│  ┌──────────────┐    port 5003    ┌──────────────────────┐  │
│  │  Gunicorn     │ ◄───────────── │  Flask (app/)        │  │
│  │  (systemd)    │                │                      │  │
│  └──────────────┘                │  - 17 blueprints      │  │
│                                  │  - 16 connectors      │  │
│                                  │  - APScheduler        │  │
│                                  │  - Leak detectors     │  │
│                                  └──────────┬───────────┘  │
│                                             │               │
│                          ┌──────────────────┴───────────┐  │
│                          │  SQLite (instance/auth.db)    │  │
│                          │  21+ tables, WAL mode         │  │
│                          └──────────────────────────────┘  │
│                                                              │
│  Backups: scripts/backup_db.sh (cron every 6h)               │
│  Watchdog: systemd timer (5m) — auto-restores on DB wipe     │
└─────────────────────────────────────────────────────────────┘
```

### Tech Stack

| Layer | Technology |
|---|---|
| **Frontend** | React 19, TypeScript, Vite 8, Tailwind CSS 4, React Router 7, Recharts, TanStack Query |
| **Backend** | Flask, Flask-Login, Flask-SQLAlchemy, Flask-Limiter, Flask-Mail |
| **Database** | SQLite (WAL mode), migrating to PostgreSQL via `scripts/migrate-to-postgres.sh` |
| **Auth** | Cookie-based sessions (Flask-Login), session revocation via UserSession table |
| **Scheduler** | APScheduler (leak detection, forecast updates, KPI aggregation) |
| **Payments** | Stripe (billing, checkout) |
| **Reverse Proxy** | Cloudflare Tunnel → localhost:5003 |
| **Process Manager** | Gunicorn, systemd user service |

## Project Structure

```
command-sovereignty/
├── app/
│   ├── __init__.py          # App factory, extensions, security headers
│   ├── models.py            # SQLAlchemy models (21+ tables)
│   ├── config.py            # Configuration
│   ├── scheduler.py         # APScheduler init (leak detectors, forecast updater)
│   ├── connectors/          # External integrations (16+ OAuth connectors)
│   ├── routes/              # Flask blueprints (17 route modules)
│   ├── services/
│   │   ├── forecast_service.py
│   │   ├── forecast_updater.py
│   │   ├── kpi_service.py
│   │   ├── leak_detectors/  # Revenue leak detection rules
│   │   ├── leak_alerts/     # Alert delivery (Slack, email)
│   │   ├── leak_remediation/
│   │   ├── leak_resolution/
│   │   ├── leak_severity/
│   │   └── lead_gen/        # Attribution, campaign gen, optimization
│   └── utils/               # CSRF, encryption, email, pagination, tenancy
├── frontend/                # React SPA (Vite + TypeScript)
├── migrations/              # SQL migration scripts (001–007)
├── scripts/
│   └── backup_db.sh         # Automated DB backup (cron)
├── templates/               # Flask Jinja2 templates
├── instance/
│   └── auth.db              # SQLite database (DO NOT run db.drop_all())
├── backups/                 # Compressed DB backups (auth_YYYYMMDD_HHMMSS.db.gz)
├── wsgi.py                  # Gunicorn entry point
├── run.py                   # Dev server entry point
├── gunicorn.conf.py         # Gunicorn configuration
├── .venv/                   # Python virtual environment
└── AGENTS.md                # Internal dev context (paths, pitfalls, rules)
```

## Quick Start

### Prerequisites

- Python 3.11+
- Node.js 18+
- Redis (for rate limiting — optional, graceful fallback)

### Backend Setup

```bash
cd /home/vincent/projects/command-sovereignty

# Create venv (skip if .venv/ exists)
python3 -m venv .venv
source .venv/bin/activate

# Install dependencies
pip install -r requirements.txt

# Set up environment
# Copy ~/.config/command-sovereignty/env as reference
# Required: SECRET_KEY, DATABASE_URL
# Optional: MAIL_*, OAUTH_*_CLIENT_ID/SECRET, RATELIMIT_*

# Run migrations
sqlite3 instance/auth.db < migrations/001_baseline.sql
sqlite3 instance/auth.db < migrations/002_profiles_role_allow_admin.sql
# ... apply remaining migrations in order (003–007)

# Start dev server
python run.py
```

### Frontend Setup

```bash
cd frontend
npm install
npm run dev          # Dev server
npm run build        # Production build → ../static/dist/
```

### Production

```bash
# Build frontend once
cd frontend && node node_modules/vite/bin/vite.js build && cd ..

# Start systemd service
systemctl --user start command-sovereignty.service
systemctl --user enable command-sovereignty.service

# Check status
systemctl --user status command-sovereignty.service
tail -50 logs/app.log
```

## Database

The database lives at `instance/auth.db` — **not** at the project root. A stale `auth.db` at root was deleted in July 2026.

### Critical Rules

1. **Never** run `db.drop_all()` — no migration system to recover from it
2. Before touching the DB: `sqlite3 instance/auth.db "SELECT count(*) FROM profiles;"`
3. If profiles count is 0, restore from `backups/`
4. Backups run every 6h via `scripts/backup_db.sh`
5. A watchdog timer (every 5m) detects DB wipes and auto-restores

### Migration to PostgreSQL

```bash
bash scripts/migrate-to-postgres.sh
```

Auto-installs `psql` if missing. Updates `DATABASE_URL` in `~/.config/command-sovereignty/env`.

## Security

- Session cookies: HttpOnly, SameSite=Lax, Secure (HTTPS only)
- Session fixation protection (re-issue ID each request)
- Session revocation (UserSession table — delete record → invalidate session)
- Brute force protection: failed login tracking, account lockout
- TOTP 2FA support per user
- CSRF protection on state-changing routes
- CSP headers (restricts inline scripts, frames, form actions)
- HSTS, X-Frame-Options, X-Content-Type-Options, X-XSS-Protection
- Request body cap: 16MB
- Rate limiting via Flask-Limiter (respects Cloudflare CF-Connecting-IP)
- Encrypted connector credentials at rest (Fernet symmetric encryption)

## Connectors

| Connector | Auth Method |
|---|---|
| QuickBooks | OAuth 2.0 |
| HubSpot | OAuth 2.0 |
| Google Ads | OAuth 2.0 |
| Google Sheets | OAuth 2.0 |
| Slack | OAuth 2.0 |
| Facebook Ads | OAuth 2.0 |
| Five9 | Per-connector API key |
| Jobber | OAuth 2.0 |
| ServiceTitan | OAuth 2.0 |
| JobNimbus | API key |
| LeadPerfection | Per-connector API key |
| Marlimar | Per-connector API key |
| Zapier | OAuth 2.0 |
| ANGI | OAuth 2.0 |
| SMS | Twilio API |
| Generic REST | Configurable |

## Monitoring

| Component | How |
|---|---|
| App health | `GET /health` — returns DB status, 503 on wipe detection |
| Logs | `logs/app.log` (10MB rotating, 5 backups) |
| DB backups | `scripts/backup_db.sh` every 6h, logged to `backups/backup.log` |
| DB watchdog | `command-sovereignty-db-watchdog.timer` (5m), auto-restores |
| System service | `systemctl --user status command-sovereignty.service` |

## Development Notes

- **Vite build quirk:** `npx vite build` triggers false background detection. Use `node node_modules/vite/bin/vite.js build` instead.
- **Login is cookie-based** (Flask-Login sessions), NOT JWT.
- **Auth model:** `User` table is `profiles` in SQLite.
- **paginate_query** returns `(list, dict)`, NOT a Pagination object — don't call `.items()` on the first element.
- **SESSION_COOKIE_SECURE=true** — cookies only work on HTTPS (via Cloudflare tunnel), not localhost HTTP.

## License

Private — see term sheet in `term_sheet.md` for co-founder agreement details.