# 📖 System Architecture & Workflow Documentation

> **Project**: Hashtag Orange GBP Dealer Dashboard
> **Phase**: 5.1 (Security Audit Applied)
> **Architecture**: 3-Tier Multi-Tenant SaaS

---

## 1. File Responsibility Matrix

### 🔐 Authentication Workflow

**Goal**: Secure, role-based access with forced password reset for new users.

- **`backend/app/auth/routes.py`**: Handles credential verification and password updates.
  - `login()`: Validates bcrypt hash, issues JWT with `sub` (email) and `role`.
  - `change_password()`: Validates password strength (8+ chars, upper/lower/digit/special), verifies `old_password`, clears `needs_password_change`.
- **`backend/app/auth/jwt_handler.py`**: Pure utility for token security.
  - `create_access_token()`: Encodes claims into HS256 JWT with 24h expiry.
- **`backend/app/middleware/auth.py`**: The "Gatekeeper".
  - `get_current_user()`: Dependency that decodes tokens, fetches user from DB. Returns `id`, `email`, `role`, `parent_id`, `needs_password_change`, `full_name`.
  - `require_role(allowed_roles)`: Higher-order function used to protect routes (e.g., Agency can't see Dealer data).
- **`frontend/app.js`**:
  - `login form listener`: Captures credentials, stores JWT in `localStorage`.
  - `password-change form listener`: Handles the "First Login" forced reset.
  - `sanitize(str)`: XSS protection helper — escapes HTML entities before template injection.

### 🏢 Agency Workflow

**Goal**: Top-level administration of brand clients + own location tracking.

- **`backend/app/agency/routes.py`**:
  - `add_client()`: Auto-generates temp password using `secrets.token_urlsafe(8)`.
  - `list_clients()`: Uses a subquery to calculate `dealer_count` per client dynamically.
  - `deactivate_client()`: Cascade soft-delete — sets `is_active=FALSE` on the client record, client user, AND all child dealers + their user accounts.
  - `reactivate_client()`: Inverse cascade — reactivates client + all child dealers.
  - `initialize_agency_location()`: Creates internal client+dealer records for the agency's own GBP location tracking.
  - `get_agency_own_dashboard()`: Returns metrics + trend data for the agency's internal location.
- **`frontend/app.js`**:
  - `loadAgencyData()`: Renders the client table with sanitized output.
  - `submitAddClient()`: Triggers the "Temporary Password Toast" notification.
  - `loadAgencyOwnLocation()`: Renders the "My Location" tab metrics + trend chart.

### 📈 Client Workflow

**Goal**: Brand-level aggregation and regional management with 4-tab dashboard.

- **`backend/app/client/routes.py`**:
  - `get_global_dashboard()`: Aggregates metrics across ALL locations (dealers + HQ). Computes **Weighted Average Rating**: `SUM(rating × reviews) / SUM(reviews)`.
  - `get_network_dashboard()`: Aggregates metrics for sub-dealers only (excludes HQ location).
  - `get_hq_dashboard()`: Returns metrics for the client's own HQ location.
  - `add_dealer()`: Provisions new locations and triggers initial data sync as a BackgroundTask.
  - `add_client_own_location()`: Links the client's HQ using `HqLocationRequest` model (no dummy email needed).
  - `get_single_dealer_dashboard()`: Enables the "Drill-Down" feature with ownership verification.
- **`frontend/app.js`**:
  - `switchClientTab(tab)`: Manages the Global/Network/Add Dealer/HQ UI state (4 tabs).
  - `drillDownDealer(id)`: Opens modal with individual location stats + trend chart.

### 🏪 Dealer Workflow

**Goal**: Store-level performance tracking and customer engagement.

- **`backend/app/dealer/routes.py`**:
  - `get_dealer_dashboard()`: Fetches metrics + 6-month trend data for the user's `location_id`.
  - `create_post()`: Stub for publishing Google Posts.
- **`backend/app/google/mock_api.py`**:
  - `get_mock_google_metrics()`: Generates 8 realistic metrics including `direction_clicks`.
- **`frontend/app.js`**:
  - `loadDealerData()`: Binds metrics to the 7 KPI cards + renders trend chart.
  - `renderChart()`: Initializes Chart.js with data from `trend_cache`.

---

## 2. Data & Schema Workflow

### 🗄️ Persistence Layer

- **`backend/schema.sql`**: The canonical DDL (5 tables). Use this to rebuild the DB in production.
- **`backend/app/database.py`**:
  - `get_db_connection()`: Provides a thread-safe `pg8000` connection. Raises HTTPException on failure (never returns None).
  - `init_db()`: Programmatically creates all 5 tables if they don't exist (`users`, `clients`, `dealers`, `metrics_cache`, `trend_cache`).
- **`backend/app/google/sync.py`**:
  - `sync_location_metrics()`: Orchestrates data from API (Mock/Real) → `metrics_cache` + `trend_cache` tables.
  - `sync_all_active_dealers()`: Nightly cron job (APScheduler, 2 AM) that syncs all active dealer locations.

### 🧪 Seeding Workflow

- **`backend/seed_admin.py`**: Creates the Agency super-user (`Admin@123`).
- **`backend/seed_test_data.py`**: Creates the "Fenesta" environment (1 Client, 3 Dealers, full metrics + 6-month trend history).

---

## 3. Critical Functions & Logic

| Function | File | Logic Description |
| :--- | :--- | :--- |
| `require_role()` | `middleware/auth.py` | Checks `user.role` against a list. Returns 403 Forbidden if unauthorized. |
| `token_urlsafe(8)` | `agency/routes.py` | Generates secure 8-character passwords like `x9-G_k1w`. |
| `Weighted Avg` | `client/routes.py` | Prevents small locations with 5.0 ratings from skewing the brand average. |
| `sanitize()` | `frontend/app.js` | XSS protection — escapes HTML entities in all template literal injections. |
| `authHeaders()` | `frontend/app.js` | Helper that injects `Bearer <token>` into every `fetch` request. |
| `showDashboard()` | `frontend/app.js` | The router. Toggles `hidden` classes based on the user's role. |
| `sync_metrics` | `google/sync.py` | Uses `INSERT ... ON CONFLICT` to upsert latest metrics + trend data into the cache. |
| `cascade deactivation` | `agency/routes.py` | Disabling a client disables all child dealers + their user accounts. |

---

## 4. Current State Summary

- **Database**: PostgreSQL (5 tables: users, clients, dealers, metrics_cache, trend_cache) fully synced.
- **Auth**: JWT with 24h expiry + password strength validation (8+ chars, upper/lower/digit/special).
- **Metrics**: 8 KPIs (Views, Search, Maps, Clicks, Calls, Directions, Rating, Reviews) + 6-month trend history.
- **Security**: Cascade deactivation, XSS sanitization, RBAC middleware, soft-delete pattern.
- **Frontend**: Dark-themed, responsive SPA with role-based routing and `sanitize()` XSS helper.
- **Mock Mode**: `USE_MOCK_DATA=true` is active and generating realistic stats.
