# Solid# Owners Manual — Full Critical Documentation
# Generated 2026-08-30 by scripts/generate_om_llms.py
# Contains full text of critical and high-priority docs.


--- FILE: 00-CRITICAL/01-MULTI-TENANT-DATA-ISOLATION.md ---

---
topic: tenant-isolation
keywords: [company_id, multi-tenant, RLS, data-isolation, security]
# NOTE: this doc is a cross-cutting POLICY, not file-coverage. Wide globs
# here (controllers/*.py etc.) previously marked the ENTIRE backend as
# "documented" and masked real doc gaps — never use wildcard code_paths.
code_paths:
  - solid-backend/models/company.py
  - solid-backend/scripts/lint_multi_tenant.py
last_verified: 2026-08-29
status: current
priority: critical
owner: platform-team
---

# Multi-Tenant Data Isolation

> **Priority:** Critical
> **Audience:** All developers

> ## ⛔ THESE ARE CODE-AUDIT FINDINGS, NOT INCIDENTS (clarified 2026-08-27)
>
> Every item below was found by **reading our own code** — a deliberate audit — and
> fixed. They describe what the code *would have done* if the path had been reached
> with the wrong inputs. **They are not reports of data that left the platform.**
>
> describes a **defect in a query**, not an observed disclosure. No customer data was
> accessed by an unauthorised party in any item on this page, and none of it is
> reportable under GDPR, HIPAA or any breach-notification rule.
>
> ⛔ **Do not cite this file as breach history** — in a SOC 2 or FedRAMP artefact, in
> diligence, or to a customer. Finding and fixing your own bugs before anyone reaches
> them is the *opposite* of an incident, and writing it in incident language turns good
> security work into a false confession. If a real incident ever occurs it goes in its
> own dated file and says so explicitly.

---

## Company Structure

| Company ID | Purpose |
|------------|---------|
| **1** | SolidNumber — Internal/Development |
| **2** | Blank Template (structure only, clone source for new tenants) |
| **3** | SolidNumber Production — Adam's own dogfood account (solidnumber.com). **Reserved, not a customer tenant.** |
| **4+** | Production tenant companies |

⛔ IDs 1, 2, and 3 are reserved system companies — never treat Company 3 as an ordinary tenant for testing or as a stand-in for "any production company." (Verified 2026-08-29 against platform CLAUDE.md; no code-level enforcement of this reservation was found — `solid-backend/models/company.py` has no `RESERVED_COMPANY_IDS` constant, so this is a team convention, not something the code blocks.)

---

## Core Principle

**Code is shared. Data is isolated.**

Every database query for tenant data must filter by `company_id`. This ensures each tenant only sees their own data.

---

## Provisioning Flow

When a new company is provisioned:

1. Create new company record (ID 225, 226, etc.)
2. Clone structure from template (Company 2)
3. Assign KB templates based on industry
4. Assign features based on subscription tier
5. Create admin user with `company_id = NEW company`
6. JWT token contains the new company_id

---

## Required Patterns

### Every Query Must Filter by company_id

```python
# Correct
contacts = db.query(Contact).filter(
    Contact.company_id == current_user.company_id
).all()

# Incorrect - returns all companies' data
contacts = db.query(Contact).all()
```

### company_id Comes from JWT, Not Client

```python
@router.get("/api/v1/contacts")
def get_contacts(current_user: User = Depends(get_current_user)):
    company_id = current_user.company_id  # From JWT
    # Never trust client-provided company_id for data access
```

### No Hardcoded company_id Values

```python
# Incorrect
company_id = 1

# Incorrect - fallback patterns
company_id = user.company_id or 1
company_id = params.get("company_id", 1)

# Correct - require it or fail
if not current_user.company_id:
    raise HTTPException(401, "Unauthorized")
```

---

## Row-Level Security (RLS)

PostgreSQL RLS is used on tenant-scoped tables as defense-in-depth, enforced by the
non-superuser `solid_app` role (RLS is bypassed for superusers/table owners, so the
app connects as `solid_app`, never as a superuser, or the policies below do nothing).

⛔ **Coverage is not complete or uniform — do not claim a percentage or table count
here.** A 2026-08-01 probe (see `solid-backend/migrations/versions/20260801_rls_predicate_normalization.py`)
found 3 different tenant-isolation predicates across 547 policies on NYC, plus 12
tenant tables (with a `company_id` column) that had RLS switched off entirely. That
migration normalized the worst drift but deliberately left ~55 tables' predicate
shape as-is pending individual review. **Never trust this file for current coverage —
run `solid-backend/scripts/rls_drift_check.py` against the stack you mean (SFO and
NYC are separate databases that drift apart) and quote what it prints.**

The canonical predicate (one definition, generated from
`solid-backend/migrations/versions/20260801_rls_predicate_normalization.py::_canonical`)
is:

```sql
(NULLIF(current_setting('app.current_company_id', true), '')::int IS NULL
 OR company_id IS NULL
 OR company_id = NULLIF(current_setting('app.current_company_id', true), '')::int)
```

This is deliberately **not** a bare `company_id = current_setting(...)::int` check
(the shape this doc previously showed, before 2026-08-29 re-verification). The
`NULLIF(..., true)` guards against `current_setting` raising when the GUC was never
set, and the `IS NULL OR` clauses are "platform mode": with no
`app.current_company_id` set (e.g. Celery workers, which run with no per-request RLS
context by design), a platform-mode table returns **every row**, not zero and not an
error. A minority of tables instead use a stricter shape with no NULL fallback, which
returns **zero rows** with no context set. Neither failure mode raises an exception —
an unset context is silently indistinguishable from "no data," which produced a real
false "zero sessions today" report in production on 2026-08-01. Do not assume RLS
will save a query that forgot to set `app.current_company_id` — check which shape a
given table actually has.

The backend sets `app.current_company_id` from the JWT before queries.

**RLS is a safety net, not a replacement for application-level filtering.**

---

## Code Review Checklist

Before approving PRs, verify:

- [ ] All queries filter by `company_id`
- [ ] `company_id` extracted from JWT/session
- [ ] No hardcoded company IDs
- [ ] No fallback patterns (`or 1`, `?? 1`)
- [ ] Admin endpoints require appropriate auth

---

## Testing Requirements

Before deployment:

1. Login as a new tenant user → Should see empty data
2. URL manipulation (`?company_id=1`) → Should not return other company data
3. JWT contains correct company_id

---

## Audit History

### Feb 28, 2026 — CASA Compliance Sweep (43 fixes)

Full CASA (Cloud Application Security Assessment) sweep across backend and frontend. Found and fixed 43 vulnerabilities:

**Unauthenticated endpoints (79 endpoints / 18 controllers):** Added JWT or superadmin auth to every exposed endpoint. Worst offenders: `payment_links.py` (hardcoded `return 1` for company_id), `session.py` /create (forged sessions for any user), `monitoring.py` + `performance.py` + `resource_monitoring.py` (29 superadmin endpoints with zero auth), `ai_orchestration.py` (queried any company's KB).

**SQL injection (3 files):** `unified_kb_service.py` — user-controlled `kb_types` interpolated into SQL (fixed with `ANY(:kb_types)` bind parameter + allowlist). `sheets_service.py` and `excel_service.py` — Google Sheets/Excel column headers in raw SQL (fixed with table allowlist + identifier regex).

**Tenant isolation defense-in-depth:** `inventory_allocation_service.py`, `mcp/tools/inventory.py`, `mcp/tools/locations.py` — `db.get()` without company_id changed to filtered queries. `tasks/data_processing.py` — `batch_update` missing company_id filter.

**Anti-patterns eliminated:**
4. `get_current_company_id()` returning hardcoded `return 1` — never fake auth
5. `POST /create` accepting `user_id`/`company_id`/`role` from body — session data comes from JWT
6. `company_id: int` as query parameter on unauthenticated endpoints — always derive from JWT

**Full details:** [14-Security/SECURITY-FIXES-COMPLETE.md](../14-Security/SECURITY-FIXES-COMPLETE.md) (CASA section)

### Feb 28, 2026 — Security Gap Audit (8 fixes)

Code-level audit of entire platform. Found and fixed 5 tenant isolation issues:

| File | Issue | Fix |
|------|-------|-----|
| `controllers/dashboard.py` (3 endpoints) | `WHERE 1=1` fallback when `company_id` falsy — returns ALL companies' analytics | Added `if not company_id: raise 401` guard, removed `1=1` pattern |
| `controllers/donations.py` (2 endpoints) | `.get(DonationRecord, id)` with no company_id filter | Changed to `.query().filter(id, company_id).first()` |
| `controllers/session.py` (handoff) | Unauthenticated endpoint created sessions for arbitrary user_id | Requires a JWT — but re-verified 2026-08-29: it is **not** `Depends(get_current_user)`. `controllers/session.py::session_handoff` (`/handoff`, ~line 685) deliberately decodes the JWT from the `Authorization` header directly instead, because `get_current_user` trusts the (possibly stale) session cookie first, which is exactly the bug this endpoint exists to fix. See the docstring at that function for why. |

Also fixed: JWT secret fragmentation (3 middleware files using different env var), PromptGuard not wired into AI bridge, S3 billing task not in Celery, 3 orphaned migrations, 4 frontend pages calling wrong API paths.

**Full details:** [14-Security/SECURITY-FIXES-COMPLETE.md](../14-Security/SECURITY-FIXES-COMPLETE.md) (Vulnerabilities #7-#15)

### Feb 5, 2026 — Full Platform Scan

Automated scan of all controllers, services, workers, and frontends. Found and fixed 15 tenant isolation violations:

| File | Issue | Fix |
|------|-------|-----|
| `controllers/healthcare.py` | DexterConversation queries by conversation_id only (HIPAA risk) | Added `company_id=current_user.company_id` to both Dexter endpoints |
| `controllers/voice.py` | Agent, VoiceCall, PhoneNumber loaded via `.get(id)` | Changed to `.filter(id, company_id)` on all 4 lookups |
| `controllers/webhooks_inbound.py` | Contact/Deal loaded via `.get(mapping.internal_id)` | Added company_id verification on all 4 lookups |
| `controllers/ai_workflow_builder.py` | Deploy/get endpoints had no auth or company_id | Added `get_current_user` + `company_id` filter |
| `controllers/chat.py` | Fallback `company_id=3` for unresolvable requests | Removed fallback — now rejects with error |
| `workers/annie_commission_processor.py` | Fallback `company_id=1` when promoter not found | Removed fallback — now skips processing |
| `solid-frontend` chat route | Hardcoded `company_id: 1` | Uses `SOLID_COMPANY_ID` env var — re-verified 2026-08-29: `solid-frontend/src/app/api/chat/message/route.ts:26` reads `process.env.SOLID_COMPANY_ID`, ⚠️ but still falls back to `"3"` (Solid#'s own dogfood company, not a customer) if the env var is unset. Intentional for a Solid#-operated widget, but note it is still a fallback default, not a hard requirement. |
| `solid-public` 3 components | Hardcoded `company_id: 1` or `3` | Uses `NEXT_PUBLIC_COMPANY_ID` env var — re-verified 2026-08-29: confirmed in `solid-public/src/components/FloatingChatWidget.tsx:38` and others, same `\|\| "3"` fallback caveat as above. |

**Common anti-patterns found:**
1. `.get(id)` — always use `.filter(Model.id == id, Model.company_id == company_id).first()`
2. `company_id = x.company_id if x else 1` — never fallback to a hardcoded company
3. `company_id: int = 3` in Pydantic models — never default to a real company ID

---

## Related Documents

- [05-Data/TENANT-ISOLATION-CRITICAL.md](../05-Data/TENANT-ISOLATION-CRITICAL.md) - Detailed guidelines
- [05-Data/MULTI-TENANT-ARCHITECTURE.md](../05-Data/MULTI-TENANT-ARCHITECTURE.md) - Architecture overview
- [14-Security/SECURITY-FIXES-COMPLETE.md](../14-Security/SECURITY-FIXES-COMPLETE.md) - SQL injection fixes
- [12-Issues-Found/KNOWN-ISSUES.md](../12-Issues-Found/KNOWN-ISSUES.md) - Full audit details

---

*Required reading for all Solid# developers*


--- FILE: 00-DOCUMENTATION-STANDARDS.md ---

---
topic: documentation-standards
keywords: [documentation, standards, naming, metadata, folders, files, Claude, LLM]
code_paths:
  - solid-backend/controllers/billing.py
  - solid-backend/models/company.py
  - solid-backend/services/knowledge_base/contact_sync.py
last_verified: 2026-08-29
status: current
priority: critical
owner: platform-team
---

# Documentation Standards for Owners Manual

> **MANDATORY for all Claude sessions and human contributors.**
>
> This document defines how to structure, name, and organize documentation.
>
> **FOLLOW THESE RULES. NO EXCEPTIONS.**

---

## Quick Reference

```
FOLDER:  ##-Folder-Name/           (e.g., 03-AI-Systems/)
FILE:    ##-FILE-NAME.md           (e.g., 01-ARCHITECTURE.md)
         or DESCRIPTIVE-NAME.md    (e.g., TENANT-ISOLATION.md)
METADATA: YAML frontmatter required on ALL files
```

---

## 1. Folder Numbering System

### Reserved Ranges

| Range | Purpose | Examples |
|-------|---------|----------|
| `00-09` | Critical/Core | `00-CRITICAL`, `01-Welcome`, `03-AI-Systems` |
| `10-19` | Business Operations | `10-Billing`, `14-Security`, `15-AI-Sandbox` |
| `20-27` | Features/Verticals | `20-Super-Admin`, `21-Widgets` |
| `28-39` | Domain-Specific | `28-CRM`, `35-Food-Team` |
| `40-89` | Systems & verticals — IN USE | `41-Token-Management`, `76-Shift4-Integration`, `88-Mobile-App` |
| `90-97` | Infrastructure & completed work — IN USE | `91-Kubernetes-Platform`, `92-NICE-SIP-Trunk`, `97-Completed-Sprints` |
| `98` | Backlog | `98-Backlog` |
| `99` | Active Sprints | `99-Active-Sprints` |

⛔ **Corrected 2026-08-29.** This table called 40–97 "RESERVED — future expansion"
and said the sprints folder was `99-Sprints-Active`. Neither was true: **54 folders**
already occupy 40–97, and the folder is `99-Active-Sprints`. A rule that reality
abandoned this thoroughly is not a rule — it is a trap for whoever reads it next and
picks a "free" number that is already taken. Pick the next unused number in the
appropriate band and check `ls Owners-Manual/` first.

### Folder Naming Rules

```
CORRECT:
  03-AI-Systems/
  10-Billing/
  28-CRM/

WRONG:
  AI-Systems/          ← Missing number prefix
  03-ai-systems/       ← Use Title-Case
  03_AI_Systems/       ← Use hyphens, not underscores
  3-AI-Systems/        ← Must be two digits (03)
```

### Before Creating a New Folder

1. **Check INDEX.md** for existing folders that might fit
2. **Check what is already taken** — `ls Owners-Manual/`. 40–97 is largely occupied.
3. **Use next available number** in the appropriate range
4. **Generate `00-INDEX.md`** for the new folder:
   `python3 scripts/generate_section_indexes.py --write`
   ⛔ Do NOT hand-write a `README.md` landing page. See § Standard Files.

---

## 2. File Naming Conventions

### Numbered Files (for sequences)

Use numbered prefixes when order matters:

```
00-INDEX.md           ← Always first
01-ARCHITECTURE.md
02-IMPLEMENTATION.md
03-TESTING.md
```

### Descriptive Files (for standalone docs)

Use ALL-CAPS with hyphens for emphasis:

```
TENANT-ISOLATION.md
SECURITY-HARDENING.md
STRIPE-BILLING-FLOW.md
```

### Standard Files (every folder should have)

| File | Purpose |
|------|---------|
| `00-INDEX.md` | **The** section landing page — overview, contents table, index |

## ⛔ `last_verified` means VERIFIED. Do not bump it to look tidy.

Set `last_verified` to today **only when you actually checked the document's claims
against the code.** If you corrected part of a doc but did not confirm the rest, LEAVE
THE DATE ALONE. A stale date is information; a false one is a trap.

This is not a style preference. On 2026-08-29 a sweep of 45 `priority: critical` docs
found two that documented database tables which were never built, a runbook restoring
from a database deleted nine days earlier, and a `✅ CORRECT` security example in
CLAUDE.md that could not run. Every one of them carried `status: current`. The dates had
been kept fresh; the content had not.

**When you verify only part of a doc, say which part:**

```markdown
<!-- UNVERIFIED 2026-08-29: per-tier feature bullet lists below were not
     re-checked; the tier prices above were. -->
```

`scripts/doc_audit.py` reads those markers (and an optional `reviewed:` frontmatter
date) and **de-escalates** such a doc from a staleness warning to info, because "read
and partly corrected today" is a different state from "nobody has opened this since
January". Before that distinction existed the audit scored them identically, which
quietly argued for bumping every date you touched — the habit that produced the dead DR
runbook in the first place.

⛔ Do not clear a de-escalation by bumping the date. Clear it by verifying the rest.

---

⛔ **One landing page per section, and it is `00-INDEX.md`.** It is GENERATED by
`scripts/generate_section_indexes.py` — regenerate it, never hand-edit it.

This standard previously required a hand-written `README.md` *as well as*
`00-INDEX.md`. That is how 61 sections ended up with two competing landing pages
carrying the same H1 and diverging file tables, while `doc_audit.py` — which looked
only for `README.md` — reported "Section Landing Pages: PASS". The hand-maintained
copy lost: in 58 of those 61 sections the generated index was newer, and the READMEs
were missing files the section actually contained. The `README.md` landing pages were
removed 2026-08-29; `doc_audit.py` now flags any section that has both.

### File Naming Rules

```
CORRECT:
  BILLING-API.md
  01-SETUP-GUIDE.md
  tenant-isolation.md

WRONG:
  Billing API.md       ← No spaces (use hyphens)
  billing_api.md       ← Use hyphens, not underscores
  BILLING-API.MD       ← Extension should be lowercase .md
```

---

## 3. YAML Frontmatter (REQUIRED)

**Every .md file MUST have YAML frontmatter.**

### Minimum Required Fields

```yaml
---
topic: descriptive-topic-name
keywords: [keyword1, keyword2, keyword3]
last_verified: YYYY-MM-DD
status: current
---
```

### Full Template

```yaml
---
topic: tenant-isolation
keywords: [company_id, multi-tenant, RLS, data-isolation, security]
code_paths:
  - solid-backend/models/company.py
  - solid-backend/middleware/auth.py
  - solid-backend/scripts/lint_multi_tenant.py
last_verified: 2026-01-22
status: current
priority: critical
owner: platform-team
---
```

> ⛔ **`code_paths` must be EXACT file paths with the repo prefix
> (`solid-backend/...`). NEVER wildcards/globs.** A single
> `services/*.py` entry once marked the entire backend as "documented"
> and masked ~100 genuinely undocumented files for months (caught
> 2026-06-06). The Librarian treats `code_paths` as a coverage
> contract: list exactly the files this doc actually describes — no
> more, no fewer. If a doc describes a whole subsystem, list each
> file. If that list feels too long, the doc is probably claiming
> more coverage than it really has.

### Field Definitions

| Field | Required | Values | Description |
|-------|----------|--------|-------------|
| `topic` | Yes | string | Primary topic (kebab-case) |
| `keywords` | Yes | array | Search terms for indexing |
| `last_verified` | Yes | YYYY-MM-DD | Date doc was last verified accurate |
| `status` | Yes | See status values below | Doc status |
| `code_paths` | No | array | Code files this doc covers — **exact repo-prefixed paths only, never globs** (see warning above) |
| `priority` | No | `critical`, `high`, `normal`, `low` | Importance level |
| `owner` | Recommended | string | Team responsible (e.g., `platform-team`, `ai-team`) |

### Status Values

| Status | Meaning | Action |
|--------|---------|--------|
| `current` | Doc is accurate and verified | None |
| `draft` | Work in progress, not yet verified | Complete and verify |
| `planned` | Documented for future work | Implement when scheduled |
| `deprecated` | Being phased out | Remove after migration |
| `archived` | No longer active, kept for reference | None |
| `backlog` | Low priority, not yet scheduled | Prioritize when ready |
| `needs-review` | May be outdated, needs check | Review within 7 days |
| `superseded` | Replaced by a newer doc; kept as a pointer to it | Link the replacement in the body |

---

## 4. Document Structure

### Standard Template

```markdown
---
topic: your-topic
keywords: [keyword1, keyword2]
last_verified: 2026-01-22
status: current
---

# Document Title

> **Brief description of what this document covers.**
>
> One or two sentences max.

---

## Overview

High-level explanation.

---

## Section 1

Content...

---

## Section 2

Content...

---

*Maintained by: Team Name*
```

### Section landing page — GENERATED, not templated

⛔ **Do not hand-write this file.** Run
`python3 scripts/generate_section_indexes.py --write` and it produces `00-INDEX.md`
from each doc's frontmatter. The shape below is what it emits, shown so you can
recognise a correct index — not so you can type one.

⚠️ If a section's index undercounts its files, the generator has not been re-run since
docs were added. Regenerate rather than patching the index by hand — a hand-patched
index is the thing that drifts.

```markdown
---
topic: folder-topic
keywords: [relevant, keywords]
last_verified: 2026-01-22
status: current
owner: team-name
---

# ##-Folder-Name

> **Brief description of this section.**
>
> What topics are covered here.

---

## Contents

| File | Purpose |
|------|---------|
| `FILE-ONE.md` | Description |
| `FILE-TWO.md` | Description |

---

## Quick Links

- Related section: `##-Other-Section/`
- Code location: `solid-backend/path/`

---

*See also: `RELATED-DOC.md`*
```

---

## 5. Cross-References

### Linking to Other Docs

```markdown
CORRECT:
  See `05-Data/TENANT-ISOLATION.md`
  See also: `03-AI-Systems/MCP_INDEX.md`

WRONG:
  See [Tenant Isolation](../05-Data/TENANT-ISOLATION.md)  ← Relative links break
  See TENANT-ISOLATION.md                                  ← Missing folder context
```

### Linking to Code

```markdown
CORRECT:
  Code: `solid-backend/controllers/billing.py`
  Implementation: `solid-frontend/src/components/Chat.tsx`

WRONG:
  Code: controllers/billing.py    ← Missing repo prefix
```

---

## 6. Librarian Compliance

The Librarian agent (`06-Operations/LIBRARIAN-AGENT.md`) enforces these standards:

### What Librarian Checks

| Check | Rule |
|-------|------|
| Metadata present | All .md files have YAML frontmatter |
| Required fields | `topic`, `keywords`, `last_verified`, `status` exist |
| Staleness | `code_paths` files changed after `last_verified` |
| Conflicts | Documented patterns match actual code |

### Keeping Docs Current

When you modify code referenced in `code_paths`:

1. **Update the doc** with new behavior
2. **Update `last_verified`** to today's date
3. **Verify `status`** is still `current`

---

## 7. Claude Session Rules

**All Claude Code sessions MUST:**

1. **Check INDEX.md** before creating new folders/files
2. **Use existing folders** when appropriate (don't fragment)
3. **Add YAML frontmatter** to every new .md file
4. **Follow naming conventions** (numbers, hyphens, case)
5. **Update INDEX.md** when adding new folders
6. **Generate `00-INDEX.md`** for new folders (never hand-write a `README.md` landing page)

**NEVER:**

- Create folders in reserved ranges (40-97) without explicit approval
- Create duplicate folders for existing topics
- Write docs without metadata
- Use spaces or underscores in file names

---

## 8. Quick Checklist

Before committing documentation:

- [ ] Folder has two-digit prefix (00-99)
- [ ] Folder uses Title-Case with hyphens
- [ ] File has .md extension (lowercase)
- [ ] File has no spaces (use hyphens)
- [ ] YAML frontmatter is present
- [ ] Required fields: topic, keywords, last_verified, status
- [ ] code_paths added if doc references specific files
- [ ] INDEX.md updated (if new folder)
- [ ] 00-INDEX.md generated (if new folder) — `scripts/generate_section_indexes.py --write`
- [ ] Section does NOT also contain a README.md landing page

---

## Examples

### Good: New Feature Documentation

```
Location: 28-CRM/CONTACT-SYNC.md

---
topic: crm-contact-sync
keywords: [CRM, contacts, sync, import, export]
code_paths:
  - controllers/crm/contacts.py
  - services/crm/contact_sync.py
last_verified: 2026-01-22
status: current
priority: normal
owner: crm-team
---

# CRM Contact Sync

> **Automatic contact synchronization between CRM and external systems.**

...
```

### Bad: What NOT to Do

```
Location: CRM/contact sync.MD    ← Wrong on multiple levels

# Contact Sync                   ← No metadata!

This doc explains contact sync...
```

---

*Created: 2026-01-22*
*Status: ACTIVE - MANDATORY*
*Owner: Platform Team*


--- FILE: PLATFORM-METRICS.md ---

---
topic: platform-metrics
keywords: [metrics, counts, agents, tables, endpoints, LOC, MCP, templates]
last_verified: 2026-08-29
status: current
owner: platform-team
auto_generated: true
generated_by: scripts/platform_metrics.py
---

# Platform Metrics — Single Source of Truth

> **Auto-generated** by `scripts/platform_metrics.py` on 2026-08-29.
> Re-run the script to update. All other docs should reference these numbers.

## Platform Scale

| Metric | Count | Source |
|--------|-------|--------|
| Database Tables | 627 | `__tablename__` in `models/` |
| API Endpoints | 2,242 | `@router.*` in `controllers/` + `routers/` |
| Lines of Code | 5.30M (5,303,398 lines) | All source files across 16 repos |
| Documentation Files | 1,909 | `.md` files in Owners-Manual + Solid-Intelligence |
| Documentation Sections | 97 | Directories in Owners-Manual |

## AI Systems

| Metric | Count | Source |
|--------|-------|--------|
| **AI Agents** | 32 | **Derived** — distinct named agents in `agents/registry.py` |
| ├─ registry entries | 33 | ADA is registered twice (free + paid tier) |
| ├─ deeply trained | 23 | entries with a system_prompt over 2,000 chars |
| └─ code-defined | 57 | core + food + vegetable teams |
| **Background workers** | 271 | **Derived** — Celery task functions in `tasks/`, `jobs/`, `workers/` |
| ├─ explicitly named | 258 | carry an explicit `name=` |
| └─ scheduled | 156 | entries in the `celery_app.py` beat schedule |
| Code-Defined Agents | 57 | registry.py (33) + food team (23) + vegetable (1) |
| MCP Tools | 655 | Across all 14 MCP servers |
| MCP Manifest Tools | 0 | In `mcp/manifest.json` (primary server) |
| Agent-Attraction Verbs (live API) | 212 | `GET /api/v1/agent/verbs` = 0 native (`register_verb` in `services/agent_verb_manifest.py`) + 212 ADA (`@ada_tool`/`@agent_verb` in `services/ada_verbs_*.py`, bridged into UNIFIED_VERB_REGISTRY) |

## Business Features

| Metric | Count | Source |
|--------|-------|--------|
| Industry Templates | 58 | `.py` files in `scripts/templates/industries/` |
| MCC Code Mappings | 247 | Entries in `constants/mcc_codes.py` |

## Codebase Breakdown (Lines of Code)

| Repository | Lines | % of Total |
|------------|-------|------------|
| solid-backend | 1,770,390 | 33.4% |
| solid-frontend | 3,105,050 | 58.5% |
| solid-public | 161,905 | 3.1% |
| solid-superadmin | 20,781 | 0.4% |
| solid-mcp-server | 51,260 | 1.0% |
| solid-platform-commerce | 22,254 | 0.4% |
| solid-cli | 68,066 | 1.3% |
| solid-ai-director | 8,775 | 0.2% |
| solid-token-orchestrator | 6,608 | 0.1% |
| ai_creator | 9,763 | 0.2% |
| ai-creator-server | 38,856 | 0.7% |
| ai-native-server | 32,232 | 0.6% |
| ai-native | 1,082 | 0.0% |
| arcade-ad-engine | 1,463 | 0.0% |
| arcade-api | 1,655 | 0.0% |
| Herriman_AI | 3,258 | 0.1% |
| **Total** | **5,303,398** | **100%** |

## Definitions

- ✅ **The agent count is DERIVED now (2026-08-27) — it used to be typed, which is why it drifted.**
  Five numbers had been in circulation: CLAUDE.md **14**, this file **116**, `AGENT_REGISTRY` **33**,
  `ONBOARDING-V2-FEATURE-MAP.md` **114**, and an older doc **31**. Recorded by `607907eb` and left open.
  ⭐ **"14" was never wrong — it froze.** All fourteen original agents (ADA, Sarah, Jake, Morgan, Marcus,
  Alex, Jordan, Maya, Riley, Ace, Annie, Devon, Atlas, Emma) are still in the registry today; the roster
  simply grew past the number while nothing regenerated it. Publishing the real figure makes the platform
  **bigger**, not smaller. Every row above is now read out of `agents/registry.py` and `tasks/` on each run,
  so it cannot freeze again. ⛔ Do not hand-edit these numbers — change the code and re-run this script.
- **Code-Defined Agents (57):** Agents with actual class definitions in the codebase — 33 in `registry.py`, 23 food team agents, 1 vegetable team.
- **Database Tables (627):** SQLAlchemy ORM models with `__tablename__` declarations. Does not include views or temp tables.
- **MCP Tools (655):** Tool functions available to AI agents across all 14 MCP servers. Includes CRM, marketing, KB, e-commerce, platform admin, and integration tools.
- **API Endpoints (2,242):** HTTP route handlers decorated with `@router.get/post/put/delete/patch` across controllers and routers.
- **Industry Templates (58):** Python files defining industry-specific KB content, each mapping to one or more MCC codes.
- **MCC Mappings (247):** Individual merchant category code entries mapping `kb_sub_code` to payment processing rates and industry classification.
- **Lines of Code:** All source files (`.py`, `.ts`, `.tsx`, `.js`, `.jsx`, `.css`, `.html`, `.sql`, `.sh`, `.yaml`, `.yml`, `.json`, `.md`) excluding `node_modules`, `.git`, `__pycache__`, `.next`, `dist`, `build`, `venv`, and `package-lock.json`.


--- FILE: SEARCH.md ---

---
topic: rapid-search-index
keywords: [search, index, navigation, lookup, llm, topic-map, rapid-search]
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# Owners Manual - Rapid Search Index

> **For LLMs**: Scan this file FIRST to find the right documentation.
>
> **Format**: Topic → Primary Doc → Related Docs
>
> **Last Generated**: 2026-03-08 | **Docs**: 900+ files | **Sections**: 57

---

## Quick Lookup by Topic

### Multi-Tenancy & Data Isolation
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| company_id filtering | `05-Data/TENANT-ISOLATION-CRITICAL.md` | `00-CRITICAL/01-MULTI-TENANT-DATA-ISOLATION.md` |
| RLS (Row Level Security) | `05-Data/MULTI_TENANT_ARCHITECTURE.md` | `01-Architecture/multi-tenancy.md` |
| tenant isolation violations | `05-Data/TENANT_ISOLATION_VIOLATIONS.md` | `05-Data/TENANT_ISOLATION_FIX_PLAN.md` |
| data isolation scanner | `05-Data/TENANT-ISOLATION-SCANNER.md` | |

### AI Infrastructure
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| SmartRouter | `03-AI-Systems/AI-INFRASTRUCTURE.md` | |
| CognitiveLimiter | `03-AI-Systems/AI-INFRASTRUCTURE.md` | `03-AI-Systems/AI-COST-INTELLIGENCE.md` |
| PromptGuard | `03-AI-Systems/AI-SECURITY-FRAMEWORK.md` | `14-Security/` |
| AI agents (all 116) | `03-AI-Systems/agent-registry.md` | |
| ADA orchestration | `03-AI-Systems/ADA_SYSTEM_OVERVIEW.md` | |
| AI memory | `03-AI-Systems/AI_MEMORY.md` | |
| AI voice | `03-AI-Systems/AI_VOICE.md` | `08-Communication-Systems/VOICE_AI_SETUP.md` |
| token tracking | `03-AI-Systems/AI-COST-INTELLIGENCE.md` | |
| **SKB (internal coaching KB)** | `66-Solid-KB-SKB/00-OVERVIEW.md` | `66-Solid-KB-SKB/01-ARCHITECTURE.md` |
| ADA stage coaching | `66-Solid-KB-SKB/03-STAGE-COACHING.md` | `66-Solid-KB-SKB/02-AUTHORING-GUIDE.md` |
| ADA industry coaching | `66-Solid-KB-SKB/03-STAGE-COACHING.md` (Industry section) | `scripts/generate_industry_skb.py` |
| ADA feature-state coaching | `66-Solid-KB-SKB/04-FEATURE-COACHING.md` | `66-Solid-KB-SKB/01-ARCHITECTURE.md` |
| ADA tier-aware nudging | `66-Solid-KB-SKB/01-ARCHITECTURE.md` (Trigger engine) | |
| Demo token gate (free tier) | `66-Solid-KB-SKB/04-FEATURE-COACHING.md` (Demo Token Gate) | `services/demo_token_gate.py` |
| SKB pending nudges (Redis) | `66-Solid-KB-SKB/01-ARCHITECTURE.md` (Redis keys) | `services/skb_nudge_store.py` |
| SKB editor (superadmin) | `66-Solid-KB-SKB/01-ARCHITECTURE.md` (Superadmin endpoints) | `controllers/superadmin_skb.py` |
| solid_knowledge_base table | `66-Solid-KB-SKB/01-ARCHITECTURE.md` (DB schema) | `solid-backend/migrations/versions/20260411_create_skb_table.py` |

### MCP Tools
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| MCP overview | `03-AI-Systems/MCP_INDEX.md` | `09-Core-Innovations/MCP-INTEGRATION.md` |
| MCP health | `03-AI-Systems/MCP_HEALTH_REGISTRY.md` | |
| MCP security | `03-AI-Systems/MCP_SECURITY_ARCHITECTURE.md` | |
| 655 MCP tools | `09-Core-Innovations/MCP-INTEGRATION.md` | |
| **Field Manual** | `47-Field-Manual/00-INDEX.md` | MCP tools, pipelines, RAG, agents |
| adding MCP tools | `47-Field-Manual/09-ADDING-NEW-TOOLS.md` | Step-by-step recipe |
| content pipeline | `47-Field-Manual/03-CONTENT-PIPELINE.md` | Generate → Review → Publish |
| self-reflection | `47-Field-Manual/04-SELF-REFLECTION.md` | AI reviews AI, brand_score |
| RAG retrieval | `47-Field-Manual/05-RAG-AND-KNOWLEDGE.md` | KB + brand + industry context |
| cross-agent | `47-Field-Manual/06-CROSS-AGENT.md` | Agent-to-agent delegation |
| CLI API keys | `47-Field-Manual/07-CLI-ACCESS.md` | Scopes, rate limits |

### Billing & Payments
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| payment architecture | `10-Billing/PAYMENT-ARCHITECTURE.md` | |
| subscription engine | `10-Billing/SUBSCRIPTION_ENGINE.md` | |
| billing flow | `10-Billing/BILLING_PAYMENT_FLOW.md` | |
| AI usage pricing | `10-Billing/AI-USAGE-PRICING.md` | |
| Platform Commerce | `16-Platform-Commerce/01-ARCHITECTURE.md` | **NOT multi-tenant** |

### CRM
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| CRM architecture | `28-CRM/CRM_UNIVERSAL_ARCHITECTURE.md` | |
| CRM customization | `28-CRM/CRM_VIEW_CUSTOMIZATION_SYSTEM.md` | |
| custom fields | `09-Core-Innovations/custom-fields-architecture.md` | |
| sales pipeline | `28-CRM/CRM_KB_SALES_FUNNEL_MAPPING.md` | |
| contacts page | `24-Pages-Reference/crm-contacts.md` | |

### Communication (SMS, Email, Voice)
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| communication status | `08-Communication-Systems/COMMUNICATION-SYSTEM-STATUS.md` | |
| SMS (Twilio) | `08-Communication-Systems/sms-system.md` | |
| email routing | `08-Communication-Systems/email-system.md` | |
| email templates | `08-Communication-Systems/EMAIL_TEMPLATES.md` | |
| voice calls | `08-Communication-Systems/voice-system.md` | |
| voice AI | `08-Communication-Systems/VOICE_AI_SETUP.md` | `03-AI-Systems/AI_VOICE.md` |
| chat integration | `08-Communication-Systems/CHAT-VOICE-INTEGRATION.md` | |

### Backend & API
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| service layer | `02-Backend/service-layer-architecture.md` | |
| controllers | `02-Backend/controller-patterns.md` | |
| middleware | `02-Backend/middleware-architecture.md` | |
| LLM providers | `02-Backend/llm-provider-system.md` | |
| database migrations | `02-Backend/database-migrations.md` | |

### Frontend
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| Next.js structure | `04-Frontend/app-structure.md` | |
| custom hooks | `04-Frontend/frontend-hooks-patterns.md` | |
| context providers | `04-Frontend/context-providers.md` | |
| components | `04-Frontend/component-library.md` | |

### Security & Compliance
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| security overview | `14-Security/security-overview.md` | |
| AI security | `14-Security/AI-SECURITY-FRAMEWORK.md` | |
| PCI compliance | `14-Security/PCI-SECURITY-ASSESSMENT.md` | |
| incident response | `14-Security/INCIDENT-RESPONSE-PLAN.md` | |
| auth documentation | `14-Security/AUTH_DOCUMENTATION_INDEX.md` | |
| compliance index | `14-Security/00-COMPLIANCE-INDEX.md` | `23-Legal/compliance/` |

### Operations & DevOps
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| deployment | `06-Operations/PRODUCTION_DEPLOYMENT_CHECKLIST.md` | |
| troubleshooting | `06-Operations/TROUBLESHOOTING.md` | |
| incident management | `06-Operations/INCIDENT_MANAGEMENT_PLAN.md` | |
| on-call runbook | `06-Operations/ON-CALL-RUNBOOK.md` | |
| pre-deploy validator | `06-Operations/PRE-DEPLOY-VALIDATOR.md` | |
| celery tasks | `06-Operations/celery-background-tasks.md` | |

### Testing & QA
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| testing strategy | `13-Testing/TESTING-STRATEGY.md` | |
| CI/CD | `13-Testing/CI-CD-PIPELINE.md` | |
| QA tools | `13-Testing/QA-TOOLING-OVERVIEW.md` | |
| Victor QA agent | `13-Testing/VICTOR-QA-AGENT.md` | |
| test coverage | `13-Testing/TEST_COVERAGE_REPORT.md` | |

### Onboarding
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| onboarding flow | `19-Onboarding/04-UNIFIED-FLOW.md` | |
| billing integration | `19-Onboarding/08-BILLING-SYSTEM.md` | |
| industry templates | `19-Onboarding/03-INDUSTRY-MODEL.md` | |

### Provisioning & Templates
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| provisioning architecture | `29-Provisioning/PROVISION_ARCHITECTURE.md` | |
| template seeding | `29-Provisioning/TEMPLATE_SEEDING_STRATEGY.md` | |
| DNS configuration | `29-Provisioning/PROVISION_DNS.md` | |
| AI agent provisioning | `29-Provisioning/PROVISION_AI_AGENTS.md` | |

### Social Media
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| social architecture | `30-Social-Media/SOCIAL_ARCHITECTURE.md` | |
| social API | `30-Social-Media/SOCIAL_API.md` | |
| social agents | `30-Social-Media/SOCIAL_AGENTS.md` | |

### Marketing
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| marketing engine | `31-Marketing-Engine/MARKETING_ENGINE.md` | |
| campaign automation | `31-Marketing-Engine/MARKETING_ENGINE_UI_UX_PLAN.md` | |

### Integrations
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| Zapier | `32-Integrations/ZAPIER_INTEGRATION_ARCHITECTURE.md` | |
| WordPress | `32-Integrations/WORDPRESS_INDEX.md` | |
| Webflow | `32-Integrations/WEBFLOW_INDEX.md` | |

### Merchant Systems
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| merchant onboarding | `33-Merchant-Systems/MERCHANT_ONBOARDING.md` | |
| merchant types | `33-Merchant-Systems/MERCHANT_TYPE_IMPLEMENTATION_PLAN.md` | |

### Developer Portal & API Keys
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| developer portal | `54-Developer-Portal/00-INDEX.md` | `45-Developer-CLI/`, `34-Partner-Program/` |
| developer signup (free) | `54-Developer-Portal/01-PORTAL-ARCHITECTURE.md` | Account creation flows |
| API key sandbox/production | `54-Developer-Portal/02-API-KEY-SYSTEM.md` | `sk_test_solid_*`, `sk_live_solid_*` |
| API key rotation | `54-Developer-Portal/02-API-KEY-SYSTEM.md` | Grace period, `rotated_to_id` |
| API key audit log | `54-Developer-Portal/02-API-KEY-SYSTEM.md` | `api_key_audit_logs` table |
| developer account model | `54-Developer-Portal/01-PORTAL-ARCHITECTURE.md` | `models/developer_account.py` |
| DeveloperAccount | `54-Developer-Portal/01-PORTAL-ARCHITECTURE.md` | `developer_accounts` table |
| OAuth app model | `54-Developer-Portal/03-OAUTH-APP-MODEL.md` | Sprint 4 (not yet built) |
| gap analysis (developer) | `54-Developer-Portal/04-GAP-ANALYSIS.md` | 5-sprint roadmap |
| agency ($299) | `54-Developer-Portal/01-PORTAL-ARCHITECTURE.md` | `45-Developer-CLI/15-REGISTRATION-AND-BILLING.md` |
| developer tier ($0) | `54-Developer-Portal/04-GAP-ANALYSIS.md` | `constants/feature_tiers.py` |
| agent tier ($299) | `54-Developer-Portal/04-GAP-ANALYSIS.md` | `constants/feature_tiers.py` |

### CLI & Developer Tools
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| CLI overview | `45-Developer-CLI/00-INDEX.md` | |
| CLI commands | `45-Developer-CLI/02-COMMANDS.md` | 60+ commands |
| CLI architecture | `45-Developer-CLI/01-ARCHITECTURE.md` | Auth flow, 16 core commands |
| CLI security | `45-Developer-CLI/12-SECURITY.md` | Auth tokens, tenant isolation |
| CLI scopes | `47-Field-Manual/07-CLI-ACCESS.md` | 26 scopes |
| pull/push workflow | `45-Developer-CLI/03-PULL-PUSH-WORKFLOW.md` | |
| MCP editor integration | `45-Developer-CLI/10-MCP-EDITOR-INTEGRATION.md` | Claude Code, Cursor, VS Code |

### Partner Program
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| partner overview | `34-Partner-Program/README.md` | |
| partner tiers | `34-Partner-Program/` | Bronze, Silver, Gold, Platinum |
| commission | `34-Partner-Program/` | 30% Y1, 20% Y2, 10% Y3 |
| reseller | `34-Partner-Program/` | `54-Developer-Portal/01-PORTAL-ARCHITECTURE.md` |

### Commerce, Brand & Flows
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| commerce flows | `51-Commerce-Flows/00-INDEX.md` | Deployable workflows |
| brand engine | `52-Brand-Engine/00-INDEX.md` | Unified brand identity |
| brand propagation | `52-Brand-Engine/03-BRAND-PROPAGATION.md` | |
| Ant Colony | `53-Ant-Colony/00-INDEX.md` | Code-to-infrastructure |
| Dewey Decimal | `53-Ant-Colony/02-DEWEY-DECIMAL-SYSTEM.md` | Element classification |

### Investment & Strategy
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| investor summary | `17-Investment/EXECUTIVE-SUMMARY.md` | |
| pitch deck | `17-Investment/PITCH-DECK.md` | |
| 2026 vision | `18-Strategy-2026/01-VISION.md` | |
| acquisition thesis | `17-Investment/ACQUISITION-THESIS.md` | |

### Legal & Licensing
| Topic | Primary Doc | Related |
|-------|-------------|---------|
| legal overview | `23-Legal/README.md` | |
| MSA/SLA/DPA | `23-Legal/agreements/` | |
| terms of service | `23-Legal/policies/` | |
| licensing | `22-Licensing/00-INDEX.md` | |

---

## Keyword Index

Fast lookup for common search terms:

| Keyword | Go To |
|---------|-------|
| `company_id` | `05-Data/TENANT-ISOLATION-CRITICAL.md` |
| `tenant` | `05-Data/` |
| `RLS` | `05-Data/MULTI_TENANT_ARCHITECTURE.md` |
| `SmartRouter` | `03-AI-Systems/AI-INFRASTRUCTURE.md` |
| `CognitiveLimiter` | `03-AI-Systems/AI-INFRASTRUCTURE.md` |
| `PromptGuard` | `03-AI-Systems/AI-SECURITY-FRAMEWORK.md` |
| `MCP` | `03-AI-Systems/MCP_INDEX.md` |
| `agent` | `03-AI-Systems/agent-registry.md` |
| `Sarah` | `03-AI-Systems/agent-registry.md` |
| `Marcus` | `03-AI-Systems/agent-registry.md` |
| `Devon` | `03-AI-Systems/agent-registry.md` |
| `ADA` | `03-AI-Systems/ADA_SYSTEM_OVERVIEW.md` |
| `Stripe` | `10-Billing/BILLING_PROVIDERS.md` |
| `subscription` | `10-Billing/SUBSCRIPTION_ENGINE.md` |
| `Twilio` | `08-Communication-Systems/sms-system.md` |
| `voice` | `08-Communication-Systems/voice-system.md` |
| `email` | `08-Communication-Systems/email-system.md` |
| `webhook` | `32-Integrations/ZAPIER_WEBHOOK_INTEGRATION.md` |
| `deploy` | `06-Operations/PRODUCTION_DEPLOYMENT_CHECKLIST.md` |
| `docker` | `06-Operations/DEVOPS_RUNBOOK.md` |
| `celery` | `06-Operations/celery-background-tasks.md` |
| `test` | `13-Testing/TESTING-STRATEGY.md` |
| `security` | `14-Security/security-overview.md` |
| `PCI` | `14-Security/PCI-SECURITY-ASSESSMENT.md` |
| `CRM` | `28-CRM/CRM_UNIVERSAL_ARCHITECTURE.md` |
| `contact` | `24-Pages-Reference/crm-contacts.md` |
| `pipeline` | `28-CRM/CRM_KB_SALES_FUNNEL_MAPPING.md` |
| `provision` | `29-Provisioning/PROVISION_ARCHITECTURE.md` |
| `template` | `29-Provisioning/TEMPLATE_SEEDING_STRATEGY.md` |
| `social` | `30-Social-Media/SOCIAL_ARCHITECTURE.md` |
| `marketing` | `31-Marketing-Engine/MARKETING_ENGINE.md` |
| `merchant` | `33-Merchant-Systems/MERCHANT_ONBOARDING.md` |
| `developer portal` | `54-Developer-Portal/00-INDEX.md` |
| `developer account` | `54-Developer-Portal/01-PORTAL-ARCHITECTURE.md` |
| `API key` | `54-Developer-Portal/02-API-KEY-SYSTEM.md` |
| `sk_test_solid` | `54-Developer-Portal/02-API-KEY-SYSTEM.md` |
| `sk_live_solid` | `54-Developer-Portal/02-API-KEY-SYSTEM.md` |
| `sandbox key` | `54-Developer-Portal/02-API-KEY-SYSTEM.md` |
| `key rotation` | `54-Developer-Portal/02-API-KEY-SYSTEM.md` |
| `audit log` | `54-Developer-Portal/02-API-KEY-SYSTEM.md` |
| `OAuth app` | `54-Developer-Portal/03-OAUTH-APP-MODEL.md` |
| `agency` | `54-Developer-Portal/01-PORTAL-ARCHITECTURE.md` |
| `CLI` | `45-Developer-CLI/00-INDEX.md` |
| `partner` | `34-Partner-Program/README.md` |
| `commission` | `34-Partner-Program/` |
| `flow` | `51-Commerce-Flows/00-INDEX.md` |
| `brand` | `52-Brand-Engine/00-INDEX.md` |
| `Ant Colony` | `53-Ant-Colony/00-INDEX.md` |
| `Thumbtack` | `48-Thumbtack-Integration/README.md` |
| `Google Workspace` | `46-Google-Workspace/00-INDEX.md` |
| `Local SEO` | `55-Local-SEO/00-INDEX.md` |

---

## Section Quick Reference

| # | Section | Files | Purpose |
|---|---------|-------|---------|
| 00 | CRITICAL | 2 | Emergency procedures |
| 00 | Introduction | 6 | Platform overview |
| 01 | Architecture | 6 | System design |
| 02 | Backend | 9 | FastAPI, services |
| 03 | AI-Systems | 72 | AI infra, agents, MCP |
| 04 | Frontend | 11 | Next.js, hooks |
| 05 | Data | 14 | Tenant isolation |
| 06 | Operations | 25 | DevOps, deployment |
| 07 | Business-Logic | 18 | Pricing, features |
| 08 | Communication | 40 | SMS, email, voice |
| 09 | Core-Innovations | 93 | Platform features |
| 10 | Billing | 22 | Payments |
| 11 | Platform-Architecture | 6 | Feature flags |
| 12 | Issues-Found | 6 | Known issues |
| 13 | Testing | 20 | QA, CI/CD |
| 14 | Security | 20 | Compliance |
| 15 | AI-Sandbox-Engine | 10 | Developer sandbox |
| 16 | Platform-Commerce | 2 | Solid#'s billing |
| 17 | Investment | 39 | Investor materials |
| 18 | Strategy-2026 | 31 | Roadmap |
| 19 | Onboarding | 33 | Customer flows |
| 20 | Super-Admin | 6 | Internal admin |
| 21 | Solid-Offers | 4 | Marketing copy |
| 22 | Licensing | 34 | Software licensing |
| 23 | Legal | 25 | Contracts |
| 24 | Pages-Reference | 13 | UI documentation |
| 25 | Platform-Reality | 19 | Go-live validation |
| 26 | Public-Site | 4 | Public website |
| 27 | Sales-Materials | 14 | Sales content |
| 28 | CRM | 14 | CRM system |
| 29 | Provisioning | 16 | Site provisioning |
| 30 | Social-Media | 10 | Social engine |
| 31 | Marketing-Engine | 7 | Marketing automation |
| 32 | Integrations | 6 | Third-party |
| 33 | Merchant-Systems | 10 | Merchant onboarding |
| 34 | Partner-Program | 19 | Partner & reseller program |
| 35 | Food-Team | 5 | Food industry vertical |
| 36 | Feedback-Loops | 5 | AI learning systems |
| 37 | Demo-System | 4 | Personalized AI demos |
| 38 | Module-Engines | 14 | Billing, provisioning engines |
| 39 | Deep-Dives | 2 | Analysis reports |
| 40 | KB-Learning-Engine | 7 | KB suggestion engine |
| 41 | Token-Management | 11 | Token tracking, cost control |
| 42 | UVX | 6 | User voice experience |
| 43 | Vector-KB-Search | 10 | Vector database, KB search |
| 44 | CFO-Intelligence | 6 | CFO advisory, Monte Carlo |
| 45 | Developer-CLI | 14 | CLI platform, pull/push |
| 46 | Google-Workspace | 19 | Customer Google tools |
| 47 | Field-Manual | 11 | MCP tools, pipelines |
| 48 | Thumbtack | 8 | Thumbtack Partner API |
| 49 | Audio-Speech | 4 | Voice AI, browser speech |
| 50 | Payments-AI | 8 | Payment orchestration |
| 51 | Commerce-Flows | 6 | Deployable workflows |
| 52 | Brand-Engine | 4 | Unified brand identity |
| 53 | Ant-Colony | 9 | Code-to-infrastructure |
| 54 | Developer-Portal | 5 | **Developer/agency portal, API keys** |
| 55 | Local-SEO | 2 | Google Local optimization |
| 98 | Backlog | 3 | Future work |
| 99 | Sprints-Active | 4 | Active sprints |

---

## Critical Paths (Read These First)

For **new developers**:
1. `00-Introduction/solid-platform-overview.md`
2. `01-Architecture/multi-tenancy.md`
3. `05-Data/TENANT-ISOLATION-CRITICAL.md`

For **AI/agent work**:
1. `03-AI-Systems/AI-INFRASTRUCTURE.md`
2. `03-AI-Systems/agent-registry.md`
3. `03-AI-Systems/MCP_INDEX.md`

For **billing/payments**:
1. `10-Billing/PAYMENT-ARCHITECTURE.md`
2. `10-Billing/PAYMENT-CONNECTIONS.md`
3. `16-Platform-Commerce/01-ARCHITECTURE.md`

For **developer/API access**:
1. `54-Developer-Portal/00-INDEX.md`
2. `54-Developer-Portal/02-API-KEY-SYSTEM.md`
3. `45-Developer-CLI/00-INDEX.md`

For **security**:
1. `00-CRITICAL/01-MULTI-TENANT-DATA-ISOLATION.md`
2. `14-Security/security-overview.md`
3. `05-Data/TENANT-ISOLATION-CRITICAL.md`

---

*This index is auto-generated. See `06-Operations/LIBRARIAN-AGENT.md` for the automation spec.*


--- FILE: 03-AI-Systems/AGENT-REGISTRY-MAP.md ---

---
topic: ai-systems
keywords: [AI, agents, MCP, SmartRouter, LLM, orchestration, knowledge-base]
code_paths:
  - agents/*.py
  - solid-backend/agents/registry.py
  - solid-backend/agents/orchestrator.py
  - solid-backend/agents/conversation.py
  - solid-backend/services/ai/agent_telemetry.py
  - mcp/*.py
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# Agent Registry Map

> **THIS IS THE SINGLE SOURCE OF TRUTH FOR ALL AGENT IDENTITIES**

_Complete mapping of all AI agents, IDs, types, and workflows_
_Last Updated: January 10, 2026_

---

## Agent Count Summary

**32 AI agents** (33 registry entries — ADA is registered twice, for free and paid tier; 23 with a deeply trained system prompt over 2,000 chars) are the customer-facing personalities in `agents/registry.py`. This is the number marketing uses, and it is DERIVED, not typed — see `Owners-Manual/PLATFORM-METRICS.md`, generated by `scripts/platform_metrics.py`.

Separately, **57 code-defined agents** exist across all teams: 33 in `agents/registry.py`, 23 food-team agents, and 1 vegetable-team agent. These support KB onboarding and nightly KB generation — they are agent code definitions, not the 32 customer-facing personalities, and they are never summed with the **271 Celery task functions** (176 scheduled), which are background infrastructure, not agents at all.

**Seeding:** customer-facing agents are seeded per company from `agent_profiles` (`is_customer_facing == True`). See `scripts/seed_agents.py`.

---

## Source of Truth Hierarchy

```
┌─────────────────────────────────────────────────────────────────┐
│                    AGENT IDENTITY HIERARCHY                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ID (INTEGER)        ← SOURCE OF TRUTH (immutable)            │
│        │                                                        │
│        ▼                                                        │
│   agent_type (STRING) ← LOOKUP KEY (immutable)                 │
│        │                 "orchestrator", "customer_service"     │
│        ▼                                                        │
│   Default Name        ← FROM REGISTRY (e.g., "ADA", "Sarah")   │
│        │                                                        │
│        ▼                                                        │
│   Display Name        ← PER-COMPANY CUSTOMIZATION              │
│                         (can be renamed, ID stays same)         │
│                                                                 │
│   CRITICAL: ID and agent_type NEVER change.                    │
│   Only display_name can be customized per company.             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

---

## The Dragon: ADA (Master Orchestrator)

| Property | Value |
|----------|-------|
| **ID** | **12** (Source of Truth) |
| **agent_type** | `orchestrator` (Lookup Key) |
| **Default Name** | ADA (Autonomous Decision Architecture) |
| **Named After** | Ada Lovelace, world's first computer programmer |
| **Autonomy Level** | 5 (Highest) |
| **Role** | VP of AI - Master Orchestrator |

**ADA is the Dragon** - The master controller that coordinates all other agents.

---

## CRITICAL: agent_type Is the Stable Identifier

Clients can rename agents ("Sarah" → "Support Bot"). The display `name` is cosmetic.
**All system logic MUST use `agent_type`** (never changes).

```python
# WRONG — breaks if client renames the agent
agent = db.query(Agent).filter_by(name="Sarah").first()

# CORRECT — stable identifier, survives renames
agent = db.query(Agent).filter_by(agent_type="customer_service", company_id=company_id).first()
```

This convention is enforced across all workers, scripts, MCP tools, and services as of 2026-02-28.

---

## Three-Tier Agent Identity System (CRITICAL)

Agents exist across three different storage layers. Each layer has its OWN `id` column. **These IDs are NOT the same.**

```
┌──────────────────────────────────────────────────────────────────────────┐
│ TIER 1: Frontend Registry (compile-time constants)                      │
│   File: solid-frontend/src/constants/agent-registry.ts                  │
│   ID: AGENT_REGISTRY[N].id  → Canonical, spans full registry (immutable) │
│   Key: agentType (string)   → "customer_service", "operations", etc.    │
│   Scope: Shared across all companies (hardcoded fallback)               │
├──────────────────────────────────────────────────────────────────────────┤
│ TIER 2: agent_profiles table (platform-level, no company_id)            │
│   File: solid-backend/models/agent_profile.py                           │
│   ID: agent_profiles.agent_id → Matches canonical registry ID           │
│   Key: agent_type (string)                                              │
│   Scope: Platform-wide (names, bios, system prompts, capabilities)      │
│   Note: agent_profiles.id (PK) may differ from agent_profiles.agent_id  │
├──────────────────────────────────────────────────────────────────────────┤
│ TIER 3: agents table (per-company instances, has company_id)            │
│   File: solid-backend/models/agent.py                                   │
│   ID: agents.id → AUTOINCREMENT per company (can be ANY number)         │
│   Key: agent_type (string)                                              │
│   Scope: Per-company (is_enabled, display_name, autonomy overrides)     │
│   DANGER: agents.id ≠ canonical ID! Company 3 might have:              │
│           agents.id=5 → agent_type='operations' (Jordan)                │
│           But canonical ID for 'operations' is 6                        │
└──────────────────────────────────────────────────────────────────────────┘
```

### Dragon Frontend: Canonical vs DB ID

The Dragon UI (`dragon-shell.tsx`) uses `DragonAgent` objects with TWO id fields:

| Field | Source | Use |
|-------|--------|-----|
| `id` | `reg.id` (canonical registry ID) | Internal selection, cross-system identity |
| `dbAgentId` | `live?.id` from agents table | API calls to `/api/v1/agents/{id}/*`, WebSocket matching |

**NEVER** use the per-company `agents.id` as if it were the canonical ID. They are different numbers.

```typescript
// WRONG — assumes agents.id matches agent_profiles.agent_id
const profile = await getAgentResume(agent.id);  // agent.id is canonical

// CORRECT — use dbAgentId for per-company API endpoints
const profile = await getAgentResume(agent.dbAgentId ?? agent.id);
```

### The Join Key Rule

**`agent_type` (string) is the ONLY safe join key across all three tiers.**

- Frontend registry → backend agents: join on `agent_type`
- Backend agents → agent_profiles: join on `agent_type`
- Never join on numeric IDs across tiers

### ADA Exception

ADA (agent_type='orchestrator', canonical ID=12) is the ONLY agent whose name cannot be changed by company owners. All other agent names are customizable per-company via `display_name`.

---

## Core Agents Master Table (ID is Source of Truth)

| ID | agent_type | Default Name | Role | Autonomy |
|----|------------|--------------|------|----------|
| **1** | `customer_service` | Sarah | Customer Service — chat, voice, support, brand voice | 4 |
| **2** | `inventory_manager` | Jake | Inventory & Supply Chain | 4 |
| **3** | `strategy` | Morgan | Strategic Planning & Data Analysis | 2 |
| **4** | `marketing` | Marcus | Marketing — emails, ads, landing pages, drip campaigns | 3 |
| **5** | `finance` | Alex | Finance & Accounting | 2 |
| **6** | `operations` | Jordan | Operations — fulfillment, shipping, logistics, tasks | 3 |
| **7** | `brand` | Maya | Brand — voice, social media, visual identity | 3 |
| **8** | `graphic_designer` | Riley | Visual Designer — product images, marketing graphics | 2 |
| **9** | `developer` | Ace | Developer — blogs, code, website content, CMS | 4 |
| **10** | `affiliate_manager` | Annie | Affiliate Manager — commissions, payouts, programs | 4 |
| **11** | `devops` | Devon | DevOps — system health, monitoring, security | 5 |
| **12** | `orchestrator` | **ADA** | VP of AI — Master Orchestrator, full platform access | 5 |
| **13** | `cto` | Nora | CTO Agent — technical sales, proposals, lead qualification | 4 |
| **14** | `sales_followup` | Emma | Sales Follow-up — post-sales emails, lead nurturing | 4 |
| **15** | `validator` | Victor | QA — page validation, test coverage, deploy gates | 3 |
| **16** | `operator` | Operator | SuperAdmin-only platform management | 5 |
| **17** | `google_workspace` | Gwen | Google Workspace — Gmail, Calendar, Drive, Docs, Tasks | 4 |

---

## Veggie Workers (IDs 18-26) — Autonomous Background Agents

Added Feb 28, 2026. These agents run as Celery workers, listening to Redis events and executing automated actions. They have full AGENT_REGISTRY entries with MCP tool lists and system prompts.

| ID | agent_type | Default Name | Role | Autonomy |
|----|------------|--------------|------|----------|
| **18** | `lead_qualifier` | Kale | Lead scoring & qualification | 3 |
| **19** | `followup_automator` | Carrot | Follow-up & re-engagement | 3 |
| **20** | `task_automator` | Parsley | Task automation & reminders | 3 |
| **21** | `analytics_reporter` | Beet | Analytics & reporting | 2 |
| **22** | `data_quality` | Radish | Data quality & deduplication | 3 |
| **23** | `email_optimizer` | Spinach | Email campaign optimization | 3 |
| **24** | `lead_nurturer` | Lettuce | Multi-touch lead nurturing | 3 |
| **25** | `pipeline_monitor` | Turnip | Deal pipeline monitoring | 2 |
| **26** | `ecommerce_optimizer` | Pepper | E-commerce optimization | 3 |

**Source:** `workers/{name}.py` (Celery workers), `agents/registry.py` (definitions)

> ⚠️ This table documents IDs 1–26. `agents/registry.py` now has 33 registry entries (32 distinct agents; ADA is registered twice, for free and paid tier) — the roster grew past this table without it being regenerated. Do not treat IDs 1–26 as the complete agent list; for the current count and roster, read `agents/registry.py` directly or see `Owners-Manual/PLATFORM-METRICS.md`.
**Seeded:** Yes — created per company via `scripts/seed_agents.py`

---

## Emma: Sales Follow-up Agent (ID 14)

Emma is the Sales Follow-up Specialist responsible for lead nurturing, deal acceleration, and pipeline health.

### Emma's Celery Tasks

| Task | Purpose | Layer |
|------|---------|-------|
| `emma_write_kb` | Write pipeline insights to KB | ORGANIZATION (7-day TTL) |
| `emma_write_contact_knowledge` | Write customer learnings via CK | CONTACT (90-day TTL) |
| `emma_pipeline_health_check` | Nightly pipeline analysis | Company-wide |
| `emma_stale_lead_followup` | Re-engage cold leads | Per-contact |

### Emma's KB Categories

| Category | Description |
|----------|-------------|
| `pipeline_insight` | Pipeline health and trends |
| `task_insight` | Task management patterns |
| `contact_pattern` | Customer behavior patterns |
| `follow_up` | Follow-up recommendations |
| `deal_analysis` | Deal stage analysis |

### Emma's Integration Points

```
Emma ←→ ADA (Orchestrator)
  └── Approval workflows for high-value actions
  └── Agent coordination for cross-functional tasks

Emma ←→ KB (Knowledge Base)
  └── ORGANIZATION layer: Company-wide insights
  └── CONTACT layer: Per-customer knowledge via kb_contact_learn()

Emma ←→ CK (Contact Knowledge)
  └── Learns from every interaction
  └── Powers personalized follow-ups

Emma ←→ Lead Scoring Engine
  └── Uses tier (hot/warm/cold) for prioritization
  └── Triggers churn_risk interventions
```

### Multi-Tenant Security

Emma follows strict tenant isolation:
- ALL operations filtered by `company_id` from JWT
- KB initialized with company_id - auto-filters all reads/writes
- Contact ownership validated before CK writes

**Source:** `tasks/emma_tasks.py`

---

### Autonomy Levels

| Level | Description | Auto-Execute |
|-------|-------------|--------------|
| 1 | Suggest only | Nothing |
| 2 | Low-risk actions | Minor changes |
| 3 | Moderate autonomy | Standard operations |
| 4 | High autonomy | Most actions except high-cost |
| 5 | Full autonomy | Everything (ADA, Devon only) |

---

## Agent Customization (Display Names)

### How Custom Names Work

Companies can rename agents for their business. The **ID and agent_type remain constant** - only the display name changes.

```
Example: Company 344 renames "Sarah" to "Emma"

Database row:
┌──────────────┬─────────────────────┬───────────────────────────────────────┐
│ agent_id: 1  │ agent_type:         │ settings: {                           │
│ (IMMUTABLE)  │ "customer_service"  │   "agent_display_name": "Emma"        │
│              │ (IMMUTABLE)         │ }                                     │
└──────────────┴─────────────────────┴───────────────────────────────────────┘

Result:
- UI displays: "Emma"
- System uses: agent_id=1, agent_type="customer_service"
- System prompt: Still Sarah's personality from registry
- Tools: Still customer_service tools
```

### LLM Context for Custom Names

When invoking an agent with a custom name, the system should inform the LLM:

```python
# services/ai/bridge.py - When building system prompt
def _get_system_prompt(company_id, agent_type, agent_settings):
    # Get base prompt from registry
    agent_def = get_agent_definition(agent_type=agent_type)
    base_prompt = agent_def["system_prompt"]

    # Check for custom display name
    custom_name = agent_settings.get("agent_display_name")
    if custom_name and custom_name != agent_def["name"]:
        # Inject custom name context
        name_context = f"""
IMPORTANT: This company has customized your display name.
- Your default name is: {agent_def["name"]}
- For this company, you go by: {custom_name}
- Use "{custom_name}" when referring to yourself.
- Your role and capabilities remain the same.
"""
        base_prompt = name_context + "\n\n" + base_prompt

    return base_prompt
```

### What CAN Be Customized Per Company

| Customizable | Field | Example |
|--------------|-------|---------|
| ✅ Display Name | `settings['agent_display_name']` | "Sarah" → "Emma" |
| ✅ Auto-approval limits | `settings['max_refund_limit']` | 100 → 50 |
| ✅ Voice Config | `voice_config` JSON | `{"voice": "alloy"}` |
| ✅ LLM Temperature | `llm_config['temperature']` | 0.7 → 0.5 |
| ✅ Autonomy Level | `autonomy_level` | 4 → 3 |

### What CANNOT Be Customized

| Fixed | Why |
|-------|-----|
| ❌ ID | Source of truth for all lookups |
| ❌ agent_type | Maps to registry definition |
| ❌ System prompt (base) | Defines agent's core personality |
| ❌ Tool access | Defined by agent_type in registry |

---

## Food Fight Team (23 KB Onboarding Agents)

The Food Fight is a 25-minute autonomous KB onboarding process where 23 food-themed agents populate a company's knowledge base.

### Phase 1: APPETIZER (2 minutes)
_Industry Detection_

| Agent | Class | Purpose |
|-------|-------|---------|
| **Apple** | `Apple` | Industry Detector - Identifies business type |
| **Kale** | `Kale` | Company Profiler - Extracts business details |
| **Beet** | `Beet` | Analytics Reporter - Initial metrics |

### Phase 2: MAIN COURSE (5 minutes)
_KB Template Cloning - The Meat & Potatoes!_

| Agent | Class | Purpose |
|-------|-------|---------|
| **Meat** | `Meat` | Data Processor - Bulk KB import |
| **Potato** | `Potato` | Entity Creator - Creates KB entries |
| **Broccoli** | `Broccoli` | KB Validator (CRITIC) - Quality check |
| **Orange** | `Orange` | Content Enricher - Adds context |

### Phase 3: SIDES (10 minutes)
_Company-Specific Knowledge_

| Agent | Class | Purpose |
|-------|-------|---------|
| **French Fries** | `FrenchFries` | Data Mapper - Field mappings |
| **Carrot** | `Carrot` | Follow-up Automator - Lead re-engagement |
| **Radish** | `Radish` | Data Quality - Duplicate detection |
| **Pepper** | `Pepper` | Alert Generator - Notification rules |

### Phase 4: DRINKS (3 minutes)
_Quality Control (Critics)_

| Agent | Class | Purpose |
|-------|-------|---------|
| **Coffee** | `Coffee` | Quality Reviewer - Content review |
| **Juice** | `Juice` | Template Validator - Structure check |
| **Tea** | `Tea` | Consistency Checker - Voice consistency |
| **Bubble Tea** | `BubbleTea` | Security Auditor - PII scan |

### Phase 5: DESSERTS (5 minutes)
_User Experience_

| Agent | Class | Purpose |
|-------|-------|---------|
| **Cake** | `Cake` | Onboarding Guide - First-run experience |
| **Cupcake** | `Cupcake` | Feature Enabler - Activate features |
| **Cookie** | `Cookie` | Preference Learner - User preferences |
| **Ice Cream** | `IceCream` | Delight Generator - Surprise features |

### Phase 6: TOYS (Ongoing)
_Experiments_

| Agent | Class | Purpose |
|-------|-------|---------|
| **Dice** | `Dice` | A/B Experimenter - Test variations |
| **Target** | `Target` | Goal Tracker - Success metrics |
| **Game** | `Game` | Gamification Engine - Achievements |
| **Easter Egg** | `EasterEgg` | Surprise Generator - Hidden features |

---

## Vegetable Team (3 Learning Agents)

The Vegetable Team runs nightly via Celery tasks to continuously learn from company data and auto-generate KB documentation.

**Source:** `solid-backend/agents/vegetable_team.py`

| Agent | Layer | Purpose | Output |
|-------|-------|---------|--------|
| **Company Learner** | Layer 1 | Learns company-wide data | `company_hours.md`, `company_pricing.md`, `company_services.md` |
| **User Learner** | Layer 2 | Learns per-user performance | `users/user_{id}.md` (role, metrics, specialties) |
| **Customer Learner** | Layer 3 | Learns per-customer profiles | `customers/customer_{id}.md` (history, preferences) |

### What They Learn

**Company Learner:**
- Business hours & emergency service availability
- Pricing structure from historical transactions
- Services offered (ranked by volume)

**User Learner:**
- Role and permissions
- Deal history and win rate
- Communication patterns
- Geographic focus areas

**Customer Learner:**
- Transaction history & LTV
- Service preferences
- Communication preferences
- Equipment/property info

---

## Agent Type Mapping Tables

### AGENT_TYPE_TO_ID
```python
AGENT_TYPE_TO_ID = {
    "customer_service": 1,    # Sarah
    "inventory_manager": 2,   # Jake
    "strategy": 3,            # Morgan
    "marketing": 4,           # Marcus
    "finance": 5,             # Alex (Finance)
    "operations": 6,          # Jordan
    "brand": 7,               # Maya
    "graphic_designer": 8,    # Riley
    "developer": 9,           # Ace
    "affiliate_manager": 10,  # Annie
    "devops": 11,             # Devon
    "orchestrator": 12,       # ADA — VP of AI
    "cto": 13,                # Nora (CTO Agent)
    "sales_followup": 14,     # Emma
    "validator": 15,          # Victor
    "operator": 16,           # Operator (SuperAdmin)
    "google_workspace": 17,   # Gwen
    # Veggie Workers (Background Automation)
    "lead_qualifier": 18,     # Kale
    "followup_automator": 19, # Carrot
    "task_automator": 20,     # Parsley
    "analytics_reporter": 21, # Beet
    "data_quality": 22,       # Radish
    "email_optimizer": 23,    # Spinach
    "lead_nurturer": 24,      # Lettuce
    "pipeline_monitor": 25,   # Turnip
    "ecommerce_optimizer": 26,# Pepper
}
```

### AGENT_ID_TO_TYPE
```python
AGENT_ID_TO_TYPE = {
    1: "customer_service",    # Sarah
    2: "inventory_manager",   # Jake
    3: "strategy",            # Morgan
    4: "marketing",           # Marcus
    5: "finance",             # Alex (Finance)
    6: "operations",          # Jordan
    7: "brand",               # Maya
    8: "graphic_designer",    # Riley
    9: "developer",           # Ace
    10: "affiliate_manager",  # Annie
    11: "devops",             # Devon
    12: "orchestrator",       # ADA (Note: ID 12, not 0!)
    13: "cto",                # Nora (CTO Agent)
    14: "sales_followup",     # Emma
    15: "validator",          # Victor
    16: "operator",           # Operator (SuperAdmin)
    17: "google_workspace",   # Gwen
    # Veggie Workers (Background Automation)
    18: "lead_qualifier",     # Kale
    19: "followup_automator", # Carrot
    20: "task_automator",     # Parsley
    21: "analytics_reporter", # Beet
    22: "data_quality",       # Radish
    23: "email_optimizer",    # Spinach
    24: "lead_nurturer",      # Lettuce
    25: "pipeline_monitor",   # Turnip
    26: "ecommerce_optimizer",# Pepper
}
```

**NOTE**: Always use `agent_type="orchestrator"` for ADA lookups (more reliable than numeric IDs).

---

## Request Flow: Frontend to Agent

```
┌────────────────────────────────────────────────────────────────────────────┐
│                           REQUEST FLOW                                      │
├────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   Frontend (ADA Chat Page)                                                 │
│         │                                                                   │
│         │  POST /api/v1/rpc/AI/assist                                      │
│         │  body: { message, context: { agent_type: "orchestrator" } }      │
│         ▼                                                                   │
│   controllers_ai/ai.py :: AIController.assist()                            │
│         │                                                                   │
│         │  1. Extract agent_type from context (default: "orchestrator")    │
│         │  2. Save user message to database                                │
│         │  3. Call generate_reply()                                        │
│         ▼                                                                   │
│   services/ai/bridge.py :: generate_reply()                                │
│         │                                                                   │
│         │  1. Call _get_system_prompt(agent_type="orchestrator")           │
│         │  2. Load ADA's system_prompt from agents/registry.py             │
│         │  3. Add company context from gpt_contexts table                  │
│         │  4. Check rate limits (CognitiveLimiter)                         │
│         │  5. Select LLM provider (SmartRouter)                            │
│         │  6. Make LLM API call                                            │
│         ▼                                                                   │
│   agents/registry.py :: get_agent_definition()                             │
│         │                                                                   │
│         │  Returns ADA's full definition:                                  │
│         │  - system_prompt (ADA's identity)                                │
│         │  - mcp_tools (94+ tools)                                         │
│         │  - autonomy_level (5)                                            │
│         │  - capabilities                                                  │
│         ▼                                                                   │
│   LLM Response (Claude/GPT-4/Gemini)                                       │
│         │                                                                   │
│         │  ADA responds as the VP of AI                                    │
│         ▼                                                                   │
│   Frontend receives response                                                │
│                                                                             │
└────────────────────────────────────────────────────────────────────────────┘
```

---

## Agent Communication Flow

```
┌────────────────────────────────────────────────────────────────────────────┐
│                     AGENT-TO-AGENT COMMUNICATION                            │
├────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   Jake detects low stock                                                   │
│         │                                                                   │
│         │  ada__send_agent_message(to=ADA, "Low stock on Widget X")        │
│         ▼                                                                   │
│   ADA receives message (ada__get_agent_inbox)                              │
│         │                                                                   │
│         │  ADA coordinates response:                                       │
│         │  1. Message Sarah: "Prepare for customer inquiries"              │
│         │  2. Message Marcus: "Adjust marketing for low stock item"        │
│         ▼                                                                   │
│   Sarah receives message                                                    │
│         │                                                                   │
│         │  Preps FAQ responses                                             │
│         │  Replies to ADA: "Ready for customer inquiries"                  │
│         ▼                                                                   │
│   Marcus receives message                                                   │
│         │                                                                   │
│         │  Adjusts campaign targeting                                      │
│         │  Replies to ADA: "Campaign adjusted"                             │
│         ▼                                                                   │
│   ADA logs coordination in ada_decisions table                             │
│                                                                             │
│   CRITICAL: Inter-agent messages are NEVER blocked by gates                │
│   (even if an agent is paused, they still receive messages)                │
│                                                                             │
└────────────────────────────────────────────────────────────────────────────┘
```

---

## Key Files

| File | Purpose |
|------|---------|
| `agents/registry.py` | Agent definitions, system prompts, tools |
| `agents/orchestrator.py` | ADA's orchestration engine |
| `agents/kb_orchestrator.py` | Food Fight orchestration |
| `agents/food/` | 23 food agent implementations |
| `agents/conversation.py` | Conversation management |
| `agents/context_manager.py` | Context window management |
| `services/ai/bridge.py` | LLM request routing |
| `controllers_ai/ai.py` | AI endpoint controller |
| `mcp/tools/ada_orchestrator.py` | ADA's MCP tools |

---

## Common Issues

### "Sarah responding instead of ADA"
**Cause**: Frontend not passing `agent_type: "orchestrator"` in context
**Fix**: Ensure context includes `agent_type: "orchestrator"`

### "Generic Solid AI response"
**Cause**: bridge.py not loading agent system_prompt from registry
**Fix**: Verify `_get_system_prompt()` calls `get_agent_definition(agent_type=...)`

### Agent ID lookup fails
**Cause**: Inconsistent ID mappings (0 vs 12 for orchestrator)
**Fix**: Always use `agent_type` string lookup, not integer IDs

---

## Usage Examples

### Invoke ADA (Orchestrator)
```python
# Via agent_type (RECOMMENDED)
result = generate_reply(
    company_id=123,
    channel="chat",
    conversation_id="abc-123",
    message="Show me today's sales",
    agent_type="orchestrator"  # ADA
)

# Frontend context
{
    "message": "Show me today's sales",
    "context": {
        "agent_type": "orchestrator",  # ADA
        "user_id": 1,
        "company_id": 123
    }
}
```

### Invoke Sarah (Customer Service)
```python
result = generate_reply(
    company_id=123,
    channel="chat",
    conversation_id="abc-123",
    message="I need help with my order",
    agent_type="customer_service"  # Sarah
)
```

### Send Agent-to-Agent Message
```python
ada__send_agent_message(
    from_agent_id=12,  # ADA
    to_agent_id=1,     # Sarah
    message_body="Jake detected low stock. Prepare for inquiries.",
    message_type="notification",
    priority="high"
)
```

---

## Multi-Tenant Isolation Architecture

### How Agents Stay in the Right "Frame of Mind"

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                    COMPANY ISOLATION ARCHITECTURE                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   User logs in → JWT Token created with company_id                          │
│         │                                                                    │
│         │  Token: { "user_id": 5, "company_id": 344, ... }                  │
│         ▼                                                                    │
│   Frontend calls AI Hub                                                      │
│         │                                                                    │
│         │  POST /api/v1/rpc/AI/assist                                       │
│         │  Header: Authorization: Bearer <jwt_token>                        │
│         ▼                                                                    │
│   middleware/mcp_tenant_scope.py                                            │
│         │                                                                    │
│         │  1. Extract company_id from JWT (line 149)                        │
│         │  2. Inject company_id into ALL tool calls                         │
│         │  3. BLOCK cross-tenant access attempts (line 217-225)             │
│         ▼                                                                    │
│   Agent calls MCP tool (e.g., solid__analytics__sales)                      │
│         │                                                                    │
│         │  company_id=344 automatically injected                            │
│         ▼                                                                    │
│   MCP Tool executes with company filter                                     │
│         │                                                                    │
│         │  SELECT * FROM orders WHERE company_id = 344  ✅                  │
│         │  (Agent ONLY sees Company 344's data)                             │
│         ▼                                                                    │
│   Agent responds with company-specific data                                 │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

### Key Isolation Points

| Layer | How It's Enforced |
|-------|-------------------|
| **JWT Token** | `company_id` embedded at login |
| **MCP Middleware** | Extracts & validates company_id from JWT |
| **Tool Injection** | `enforce_company_scope()` injects company_id into ALL tool calls |
| **Security Block** | Cross-tenant access raises HTTP 403 Forbidden |
| **Database Queries** | All queries filter by `WHERE company_id = ?` |

### Cross-Tenant Access Prevention

```python
# middleware/mcp_tenant_scope.py lines 217-225
if provided_company_id != company_id:
    raise HTTPException(
        status_code=status.HTTP_403_FORBIDDEN,
        detail=f"Cross-tenant access denied: Cannot access company {provided_company_id} from company {company_id}"
    )
```

### Example: ADA Querying Sales

When ADA (Company 344) asks "show me today's sales":

1. JWT contains `company_id: 344`
2. Middleware extracts `company_id=344`
3. ADA calls `solid__analytics__sales(period="today")`
4. Middleware injects: `solid__analytics__sales(company_id=344, period="today")`
5. Tool queries: `SELECT * FROM orders WHERE company_id = 344 AND ...`
6. ADA sees ONLY Company 344's sales

**ADA cannot see Company 345's data** - the middleware blocks it.

---

## Agent Customization Per Company

### What Can Be Customized

| Field | Location | Example |
|-------|----------|---------|
| **Display Name** | `agent.settings['agent_display_name']` | "Sarah" → "Customer Care Sarah" |
| **Behavior Settings** | `agent.settings` JSON | `{"auto_refund_limit": 50}` |
| **Voice Config** | `agent.voice_config` JSON | `{"voice": "alloy", "tone": "friendly"}` |
| **LLM Model** | `agent.llm_model_override` | "claude-sonnet-4-6" |
| **Temperature** | `agent.llm_config['temperature']` | 0.7 |
| **Autonomy Level** | `agent.autonomy_level` | 1-5 |

### Customization Flow

```
Company 344 wants to rename Sarah to "Emma":

1. API call: PUT /api/v1/agents/1/settings
   Body: { "agent_display_name": "Emma" }

2. Middleware validates: company_id from JWT matches agent.company_id

3. Agent updated: agent.settings = { "agent_display_name": "Emma" }

4. Display: Agent shows as "Emma" for Company 344
   (Internal agent_type remains "customer_service")

5. Company 345's Sarah is unchanged (different agent row)
```

### Agent Personality per Company

Each company's agents have independent:
- **System prompt** (from registry by agent_type)
- **Company context** (from KB by company_id)
- **Learned facts** (from AgentContextMemory by company_id + agent_id)
- **Settings** (from agent.settings JSON)

```python
# When building prompt for Company 344's ADA:
system_prompt = registry.get("orchestrator")["system_prompt"]  # ADA's base prompt
company_kb = load_kb(company_id=344)  # Company 344's knowledge base
agent_settings = agent.settings  # Company 344's customizations
```

---

## Knowledge Base Isolation

### 4-Layer KB Architecture

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                         KB ISOLATION LAYERS                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   Layer 1: PLATFORM KB (Shared)                                             │
│   └── System-wide knowledge all companies can access                        │
│       └── company_id = NULL or 0                                            │
│                                                                              │
│   Layer 2: COMPANY KB (Isolated)                                            │
│   └── Company-specific knowledge                                            │
│       └── company_id = 344 (filtered in ALL queries)                        │
│                                                                              │
│   Layer 3: REP KB (Salesperson-specific)                                    │
│   └── Per-salesperson knowledge within company                              │
│       └── company_id = 344 AND user_id = 5                                  │
│                                                                              │
│   Layer 4: CLIENT KB (Customer-specific)                                    │
│   └── Knowledge about specific customers                                    │
│       └── company_id = 344 AND contact_id = 789                             │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

### KB Query Example

```python
# When agent needs KB for Company 344:
articles = db.query(KnowledgeBaseArticle).filter(
    KnowledgeBaseArticle.company_id == 344,  # ✅ ISOLATED
    KnowledgeBaseArticle.status == "published"
).all()
```

---

## Food Fight Team Isolation

When the Food Fight runs for Company 344:

```python
# kb_orchestrator.py
async def orchestrate_kb_onboarding(
    self,
    company_id: int,  # 344 - CRITICAL: Scopes entire operation
    industry: str,
    company_name: str
):
    # ALL 23 food agents work within company_id=344 scope
    # Apple (Industry Detector) → only sees Company 344
    # Meat (Data Processor) → only writes to Company 344's KB
    # Broccoli (Validator) → only validates Company 344's data
```

The `company_id` is passed through the entire Food Fight pipeline, ensuring agents only touch that company's data.

---

_This is the source of truth for agent identities and workflows._
_Part of Owners Manual documentation suite_


--- FILE: 03-AI-Systems/00-AI-SYSTEMS-MASTER-INDEX.md ---

---
topic: ai-systems-index
keywords: [AI, systems, index, master, KB, context, agents, serialization]
last_verified: 2026-08-29
status: current
priority: critical
owner: platform-team
---

# AI Systems Master Index

> **The complete map of all AI, KB, context, and identity systems.**
>
> Start here to understand how everything connects.

---

## System Architecture Overview

```
┌─────────────────────────────────────────────────────────────────────────────────────┐
│                              SOLID# AI ARCHITECTURE                                  │
├─────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                     │
│  ┌─────────────────────────────────────────────────────────────────────────────┐   │
│  │                         IDENTITY LAYER                                       │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐     │   │
│  │  │  Company ID  │  │  Agent ID    │  │  Channel ID  │  │  Contact ID  │     │   │
│  │  │  (immutable) │  │  (immutable) │  │  (composite) │  │  (per-co)    │     │   │
│  │  └──────────────┘  └──────────────┘  └──────────────┘  └──────────────┘     │   │
│  │                    SERIALIZATION-AND-IDENTITY.md                             │   │
│  └─────────────────────────────────────────────────────────────────────────────┘   │
│                                      ↓                                              │
│  ┌─────────────────────────────────────────────────────────────────────────────┐   │
│  │                         REGISTRY LAYER                                       │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐     │   │
│  │  │   Company    │  │    Agent     │  │   Channel    │  │  KB Access   │     │   │
│  │  │   Registry   │  │   Registry   │  │   Registry   │  │   Registry   │     │   │
│  │  └──────────────┘  └──────────────┘  └──────────────┘  └──────────────┘     │   │
│  │                    MASTER-CONTEXT-REGISTRY.md                                │   │
│  └─────────────────────────────────────────────────────────────────────────────┘   │
│                                      ↓                                              │
│  ┌─────────────────────────────────────────────────────────────────────────────┐   │
│  │                       KNOWLEDGE LAYER (6 Levels)                             │   │
│  │                                                                              │   │
│  │    Level 0        Level 1        Level 2        Level 3                     │   │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐                     │   │
│  │  │ Platform │→ │ Industry │→ │ Company  │→ │ Channel  │                     │   │
│  │  │    KB    │  │    KB    │  │    KB    │  │    KB    │                     │   │
│  │  └──────────┘  └──────────┘  └──────────┘  └──────────┘                     │   │
│  │                                    ↓             ↓                           │   │
│  │                             Level 4        Level 5                          │   │
│  │                           ┌──────────┐  ┌──────────┐                        │   │
│  │                           │  Agent   │→ │ Contact  │                        │   │
│  │                           │    KB    │  │    KB    │                        │   │
│  │                           └──────────┘  └──────────┘                        │   │
│  │                    KB-ORCHESTRATION-ENGINE.md                                │   │
│  └─────────────────────────────────────────────────────────────────────────────┘   │
│                                      ↓                                              │
│  ┌─────────────────────────────────────────────────────────────────────────────┐   │
│  │                       RESOLUTION LAYER                                       │   │
│  │                                                                              │   │
│  │  ┌─────────────────────────────────────────────────────────────────────┐    │   │
│  │  │                    CONTEXT RESOLVER                                  │    │   │
│  │  │                                                                      │    │   │
│  │  │   Input: company_id + channel_id + contact_id (optional)            │    │   │
│  │  │                         ↓                                            │    │   │
│  │  │   Output: Complete system prompt with WHO + WHAT + WHERE + HOW      │    │   │
│  │  │                                                                      │    │   │
│  │  └─────────────────────────────────────────────────────────────────────┘    │   │
│  │                    MASTER-CONTEXT-REGISTRY.md (ContextResolver)              │   │
│  └─────────────────────────────────────────────────────────────────────────────┘   │
│                                      ↓                                              │
│  ┌─────────────────────────────────────────────────────────────────────────────┐   │
│  │                         LLM LAYER                                            │   │
│  │                                                                              │   │
│  │  ┌──────────────────────────────────────────────────────────────────────┐   │   │
│  │  │  System Prompt: "You are Sophie (agent:100:1), a Dental Care        │   │   │
│  │  │  Coordinator for Bright Smile Dental (company:100). You are on      │   │   │
│  │  │  the support chat (channel:100:chat:support123). Here is your KB... │   │   │
│  │  └──────────────────────────────────────────────────────────────────────┘   │   │
│  │                                                                              │   │
│  └─────────────────────────────────────────────────────────────────────────────┘   │
│                                                                                     │
└─────────────────────────────────────────────────────────────────────────────────────┘
```

---

## Documentation Map

### Core Documents

| Document | Purpose | Lines |
|----------|---------|-------|
| **`SERIALIZATION-AND-IDENTITY.md`** | IDs are source of truth, names are labels | 500+ |
| **`MASTER-CONTEXT-REGISTRY.md`** | 5 registries (incl. Provider), resolution logic, company overrides | 2,000+ |
| **`KB-ORCHESTRATION-ENGINE.md`** | 6-level KB hierarchy, Celery tasks | 1,300+ |
| **`KB-SYSTEM-INDEX.md`** | Quick reference for all KB systems | 350+ |

### Supporting Documents

| Document | Purpose |
|----------|---------|
| `AI-INFRASTRUCTURE.md` | SmartRouter, CognitiveLimiter, PromptGuard |
| `AGENT-REGISTRY-MAP.md` | All 15 agent definitions |
| `AGENT-ORCHESTRATION-WORKFLOW-MAP.md` | How agents collaborate |
| `AI-CONTEXT-ARCHITECTURE.md` | Context system details |
| `CLAUDE-CONTEXT-CANONICAL-TRUTH.md` | Canonical truth for Claude context (three roles, write model, flows-down, DDC-indexed) |
| `WIDGET-CONTEXT-SYSTEM.md` | Chat widget configuration |

### Event & Governance System

| Code Path | Purpose |
|-----------|---------|
| `agents/ada/events.py` | ADA event emission (anomaly alerts from monitors) |
| `services/ada_events.py` | ADA event service (delegates to outbox) |
| `services/outbox.py` | CRM event dispatch backbone |
| `models/ai_governance.py` | CompanyAISettings + CompanyConsent models |
| `models/audit_log.py` | Security audit trail (OAuth, admin actions) |
| `governance/access_control.py` | AI access control enforcement |
| `services/ai/embeddings.py` | Standalone text embedding generation |
| `tasks/escalation_tasks.py` | Persistent reminder escalation (Celery) |

### Data Governance & Security

| Document | Purpose |
|----------|---------|
| `AI-DATA-GOVERNANCE.md` | **Data classification, PII masking, provider disclosure rules** — ⛔ corrected 2026-08-29: file actually lives in this directory (`03-AI-Systems/`), not `../09-Core-Innovations/` |
| `../14-Security/00-COMPLIANCE-INDEX.md` | SOC2, PCI, GDPR, HIPAA compliance index |
| `../14-Security/CONTROL-MATRIX.md` | 90+ security controls mapped to SOC2 |

### Partner Program Integration

| Document | Purpose |
|----------|---------|
| `../34-Partner-Program/00-INDEX.md` | Partner ecosystem overview |
| `../34-Partner-Program/PROVIDER-TYPES-AND-ACCESS.md` | What each provider type can access |
| `../34-Partner-Program/ARCHITECTURE.md` | Partner database schema |

**Key Integration:** The `MASTER-CONTEXT-REGISTRY.md` includes a **Provider Registry** that scopes AI agent data access by provider type (accountant sees financials, marketer sees CRM, tech sees KB). Provider disclosure rules are enforced via the **AI Data Governance** framework.

---

## Key Relationships

### Entity Hierarchy

```
Platform (global)
└── Industry (by MCC + kb_sub_code)
    └── Company (company_id)
        ├── Agent Configs (company_id + agent_id)
        │   └── Purpose Configs (company_id + agent_id + purpose)
        ├── Channels (company_id + type + ref)
        ├── KB Entries (company_id + level + key)
        ├── Contacts (company_id + contact_id)
        │   └── Contact KB (company_id + contact_id + key)
        └── Provider Access (company_id + provider_id)  ← NEW
            └── Scoped KB Access (by service_type: financial, marketing, tech, etc.)
```

### ID Resolution Flow

```
REQUEST ARRIVES
│
├─ channel_id: "channel:42:chat:abc123"
│   ├─ company_id: 42
│   ├─ channel_type: chat
│   └─ channel_ref: abc123
│
├─ LOOKUP: channels WHERE channel_key = "channel:42:chat:abc123"
│   └─ primary_agent_id: 1
│   └─ primary_purpose: "sales"
│
├─ LOOKUP: company_agent_configs WHERE (company_id=42, agent_id=1)
│   └─ display_name: "Sarah" (using default)
│   └─ personality: "southern" (using default)
│
├─ LOOKUP: kb_entries WHERE kb_key LIKE "kb:company:42:512:%"
│   └─ pricing, services, faq, etc.
│
└─ BUILD SYSTEM PROMPT
    └─ "You are Sarah, agent_id:1, for Acme Plumbing, company_id:42..."
```

---

## Scale Numbers

> **⛔ UNVERIFIABLE 2026-08-29:** This table's "Current" and "Max Supported" figures are not backed by any script, query, or counter in the codebase — there is no `company_context_registry`, no per-industry counter, and no config enforcing these "max supported" ceilings (see `MASTER-CONTEXT-REGISTRY.md`'s re-verification note: the registry tables this doc's numbers would come from were never built). Treat this table as illustrative placeholder content, not a measured fact. The one real, derived agent count is **32 AI agents** (`agents/registry.py`, current count in `Owners-Manual/PLATFORM-METRICS.md`) — the "Agents (base) 15" row below is stale/inaccurate against that.

| Entity | Current | Max Supported |
|--------|---------|---------------|
| Industries | 250 | 1,000 |
| Companies | 10,000 | 1,000,000 |
| Agents (base) | 15 | 50 |
| Agent configs | 150,000 | 50M |
| Channels | 100,000 | 10M |
| Contacts | 10,000,000 | 1B |
| KB entries | 5,000,000 | 500M |

---

## Quick Reference: IDs vs Names

| Entity | ID (Source of Truth) | Name (Display Label) |
|--------|---------------------|---------------------|
| Company | `company_id: 42` | `company_name: "Acme Plumbing"` |
| Agent | `agent_id: 1` | `display_name: "Sarah"` or `"Sophie"` |
| Channel | `channel:42:chat:abc123` | `widget_name: "Sales Chat"` |
| Contact | `contact:42:789` | `full_name: "John Smith"` |
| KB Entry | `kb:company:42:512:pricing` | `title: "Service Pricing"` |

**Rule:** IDs never change. Names can be edited by users.

---

## Quick Reference: Override Hierarchy

```
BASE TEMPLATE (Global)
    ↓ Company can override
COMPANY CONFIG (Per-Company)
    ↓ Channel can override
CHANNEL CONFIG (Per-Widget)
    ↓ Purpose can override
PURPOSE CONFIG (Per-Task)
```

**Example:** Sarah's greeting

```
Base:    "Hey there! I'm Sarah."
Company: "Hello! Welcome to Bright Smile Dental. I'm Sophie."
Channel: "Hi! I'm here to help with your appointment."
Purpose: "I'm sorry you're having an issue. Let me help."
```

---

## Celery Tasks (Orchestration)

| Task | Frequency | Purpose |
|------|-----------|---------|
| `kb_provision_company` | On signup | Clone industry KB to company |
| `kb_learn_from_conversation` | After each chat | Extract insights, update CK |
| `kb_nightly_audit` | Daily 2 AM | Check staleness, conflicts |
| `kb_sync_entry` | Real-time | Propagate changes |
| `sync_company_registry` | On config change | Keep registry in sync |
| `validate_registry_integrity` | Hourly | Detect drift |
| `queue_persistent_reminders` | On escalation | Send repeated SMS reminders for escalation paths |

---

## API Endpoints

### Context Resolution

> **⛔ WRONG 2026-08-29 — these routes do not exist.** Grepped `solid-backend/controllers/` and `routing/` for `api/context/resolve`, `api/registry/company`, `api/registry/agent`: zero matches. `/api/kb/*` does exist (`controllers/knowledge_base_controller.py`) but is a completely different, real system — a public help-center (categories/articles/search/tags), not composite-key context lookup by `company:agent:purpose`. This whole "Context Resolution" API surface is conceptual/aspirational, matching the finding in `MASTER-CONTEXT-REGISTRY.md` that its `ContextResolver` class and registry tables were never built. Do not call these endpoints; they will 404.

```
GET /api/context/resolve?company_id=42&channel_id=abc123   (does not exist)
GET /api/registry/company/42                                 (does not exist)
GET /api/registry/agent/42/1                                 (does not exist)
GET /api/kb/company:42:512:pricing                            (does not exist — real /api/kb/* is a
                                                                 help-center API, see knowledge_base_controller.py)
```

---

## Document Reading Order

1. **Start:** `SERIALIZATION-AND-IDENTITY.md` - Understand IDs vs names
2. **Then:** `MASTER-CONTEXT-REGISTRY.md` - Understand the 4 registries
3. **Then:** `KB-ORCHESTRATION-ENGINE.md` - Understand 6-level KB
4. **Reference:** `KB-SYSTEM-INDEX.md` - Quick lookups

---

## Verification Checklist

Before any AI interaction:

- [ ] Company exists and is active
- [ ] Channel is configured for this company
- [ ] Agent is enabled for this company
- [ ] KB is provisioned for this industry
- [ ] Context can be fully resolved
- [ ] System prompt can be built

---

*This document is the entry point for understanding Solid# AI systems.*
*Updated: 2026-02-03 · Re-verified: 2026-08-29 (Scale Numbers and API Endpoints sections found to be unbuilt/placeholder — see ⛔ notes above; document map and code_paths confirmed to exist)*
*Owner: Platform Team*


--- FILE: 03-AI-Systems/KB-SYSTEM-ARCHITECTURE.md ---

---
topic: ai-systems
keywords: [AI, agents, MCP, SmartRouter, LLM, orchestration, knowledge-base]
code_paths:
  - services/knowledge_base/*.py
  - services/kb_templates/*.py
  - solid-backend/services/ai/kb_layer_analytics.py
  - agents/knowledge_graph/*.py
  - solid-backend/agents/kb_orchestrator.py
  - solid-backend/api/routers/kb_analytics.py
  - solid-backend/api/routers/knowledge_graph.py
last_verified: 2026-03-07
status: current
priority: high
owner: platform-team
---

# Knowledge Base System Architecture

> **Last Updated:** 2026-02-12
> **Owner:** Platform Team
> **Status:** LOCKED SPEC - DO NOT MODIFY WITHOUT REVIEW

## Overview

The Solid# Knowledge Base system is a **4-layer architecture** that provides AI agents with company-specific, industry-specific, and platform-wide knowledge. Every merchant gets their own isolated KB with multi-tenant security. Layer 4 (AgentKBScope) adds per-agent access control so different agents see different KB slices.

> **Not what you're looking for?** This document covers the **tenant-facing** KB system — the brain that each customer's AI uses to know their own business. SolidNumber's **internal** coaching brain (used by ADA to coach customers based on tier, never visible to tenants) is a separate system called **SKB** — see [`66-Solid-KB-SKB/`](../66-Solid-KB-SKB/00-OVERVIEW.md).

> **Editing L1/L2 seed code?** `config/gpt_context_defaults.py` (L1) and `scripts/templates/industries/*.py` (L2) are **seed-only** — changes affect *new* tenants at provisioning only. Existing tenants keep their own per-company rows and will NOT be retroactively updated without a re-seed script. See [`CLAUDE-CONTEXT-CANONICAL-TRUTH.md § 650`](./CLAUDE-CONTEXT-CANONICAL-TRUTH.md) (Update Propagation Matrix) for the Live vs Seed-only contract. PRs touching these paths must include a propagation note; CI rejects missing ones.

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                          AI AGENT (Sarah, Ada, etc.)                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                    │                                         │
│    ┌───────────────────────────────┼───────────────────────────────────┐    │
│    │           UNIFIED KB SERVICE (3-Level Resolution)                  │    │
│    │                               │                                    │    │
│    │   ┌───────────────────────────┴───────────────────────────┐       │    │
│    │   │                                                        │       │    │
│    │   ▼                          ▼                          ▼  │       │    │
│    │ ┌──────────────┐  ┌────────────────────┐  ┌──────────────┐│       │    │
│    │ │ GPT Contexts │  │ Company Knowledge  │  │   Master KB  ││       │    │
│    │ │ (Personality,│  │   Base (Industry   │  │  (Platform   ││       │    │
│    │ │  Identity)   │  │    Templates)      │  │    Docs)     ││       │    │
│    │ │              │  │                    │  │              ││       │    │
│    │ │ Per-Company  │  │    Per-Company     │  │  All Tenants ││       │    │
│    │ └──────────────┘  └────────────────────┘  └──────────────┘│       │    │
│    │        │                    │                    │        │       │    │
│    │        └────────────────────┴────────────────────┘        │       │    │
│    │                             │                              │       │    │
│    │                    company_id filter                       │       │    │
│    └────────────────────────────────────────────────────────────┘       │    │
│                                                                          │    │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## Layer 1: GPT Contexts (AI Personality & Identity)

### Table: `gpt_contexts`

| Column | Type | Description |
|--------|------|-------------|
| id | int | Row ID (NOT "KB-ID") |
| company_id | int | **Tenant isolation key** |
| context_type | str | `system`, `master`, or `context` |
| name | str | Human-readable name |
| content | text | The actual KB content |
| priority | int | Load order (higher = first) |
| is_active | bool | Whether to include in prompts |

### Context Types

| Type | Purpose | Example |
|------|---------|---------|
| `system` | Personality, identity rules | "Sarah Personality Guidelines" |
| `master` | Main company knowledge | "Solid# Deep Knowledge Base" |
| `context` | Additional context (FAQ, sales) | "Sales & FAQ Responses" |

### How GPT Contexts Load

**File:** `services/ai/bridge.py:174`

```python
def _get_company_contexts(company_id: int) -> str:
    """Get all KB contexts for a company"""
    contexts = db.query(GPTContext).filter(
        GPTContext.company_id == company_id,  # ← Multi-tenant filter
        GPTContext.is_active == True
    ).order_by(GPTContext.priority.desc()).all()

    system_prompts = []
    master_prompts = []
    context_prompts = []

    for ctx in contexts:
        if ctx.context_type == "system":
            system_prompts.append(ctx.content)
        elif ctx.context_type == "master":
            master_prompts.append(ctx.content)
        elif ctx.context_type == "context":
            context_prompts.append(ctx.content)

    # Combine all prompts
    return "\n\n".join(system_prompts + master_prompts + context_prompts)
```

### When KB Cloning Happens (CRITICAL - 2026-01-27)

KB cloning timing differs by signup path:

| Signup Path | When KB Cloned | Function |
|-------------|----------------|----------|
| **Email/Password** | At checkout (Phase 2) | `provision_new_tenant()` |
| **OAuth (Google/Microsoft)** | At OAuth signup | `oauth_register()` → `provision_new_tenant()` |

**OAuth users get KB cloning at signup, NOT at checkout.** Checkout only updates the tier and creates subscription - it returns early to prevent duplicate KB entries.

**Documentation:** [../19-Onboarding/16-OAUTH-ONBOARDING-FLOW.md](../19-Onboarding/16-OAUTH-ONBOARDING-FLOW.md)

### Standard GPT Context Structure (Per Company)

Every company gets 3-4 GPT contexts during provisioning:

| # | Name | Type | Priority | Purpose |
|---|------|------|----------|---------|
| 1 | Personality | system | 100 | Tone, voice, agent name |
| 2 | Identity Rules | system | 90 | Never say fictional, cite facts |
| 3 | Company KB | master | 80 | Company info, services, pricing |
| 4 | FAQ/Sales (optional) | context | 70 | Objection handling, competitor responses |

### Solid# (Company 3) GPT Contexts

| ID | Type | Name | Chars |
|----|------|------|-------|
| 13 | system | Friendly Professional Personality | 1,968 |
| 14 | master | Solid# Deep Knowledge Base | 5,582 |
| 15 | system | Identity Assertion Rules | 970 |
| 28 | context | Sales & FAQ Responses | 3,128 |

---

## Layer 2: Company Knowledge Base (Industry Templates)

### Table: `company_knowledge_base`

| Column | Type | Description |
|--------|------|-------------|
| id | int | Row ID |
| company_id | int | **Tenant isolation key** |
| title | str | Entry title |
| category | str | company_identity, services, faq, etc. |
| content | text | Markdown content |
| content_type | str | article, faq, howto |
| is_public | bool | Show to customers? |

### Living Inheritance (NEW - 2026-01-23)

Company KB entries can now inherit from industry templates with auto-sync:

| Column | Type | Description |
|--------|------|-------------|
| inherits_from_industry_id | int | FK to `industry_knowledge_base` |
| is_customized | bool | Owner modified (blocks auto-sync) |
| auto_sync | bool | Receive updates from template |
| last_synced_at | timestamp | Last sync time |
| sync_version | str | Template version at last sync |

**See:** `Owners-Manual/36-Feedback-Loops/02-KB-TEMPLATE-INHERITANCE.md`

### Industry Template Files

**Location:** `scripts/templates/industries/*.py`

**52 Templates Available:**

| Template | Industries Covered |
|----------|-------------------|
| plumber.py | Plumbing Services (512) |
| hvac.py | HVAC Contractor (508) |
| electrical.py | Electrical Contractor (506) |
| roofing.py | Roofing Contractor (513) |
| dentist.py | Dentists/Orthodontists (1406) |
| doctor.py | Doctors & Physicians (1404) |
| restaurant.py | Eating Places (905, 906) |
| retail_store.py | 63 retail categories (2000-series) |
| ... | ... (52 total) |

### Template Structure

Each template file exports a `TEMPLATE` list:

```python
# scripts/templates/industries/plumber.py

TEMPLATE = [
    {
        "title": "Core Value Proposition",
        "category": "company_identity",
        "content": """# Core Value Proposition

We are a full-service plumbing company...
""",
        "content_type": "article",
        "is_public": True
    },
    {
        "title": "Emergency Services",
        "category": "services",
        "content": """# Emergency Services

24/7 emergency plumbing response...
""",
        "content_type": "article",
        "is_public": True
    },
    # ... ~50 entries per template
]
```

### KB Categories

| Category | Content |
|----------|---------|
| company_identity | Brand voice, mission, values |
| services | What the business offers |
| customer_types | Who they serve |
| common_issues | Problems they solve |
| pricing_structure | How they price |
| service_process | How they deliver |
| industry_knowledge | Domain expertise |
| faq | Frequently asked questions |
| policies | Terms, guarantees, warranties |
| marketing_messaging | Sales/marketing copy |

---

## Layer 3: MCC Code Mapping

### What is MCC?

**Merchant Category Code (MCC)** - Standard 4-digit codes used by payment processors to classify businesses.

### Table: `constants/mcc_codes.py`

**258 Business Types Mapped**

```python
MCC_MAPPING = {
    # kb_sub_code: (mcc_code, solid_rate, outside_rate, chargeback_fee, kb_exists, industry_name)
    512: ("1711", "2.9% + $0.30", "0.5%", 25.00, True, "Plumbing Services"),
    508: ("1711", "2.9% + $0.30", "0.5%", 25.00, True, "HVAC Contractor"),
    506: ("1731", "2.9% + $0.30", "0.5%", 25.00, True, "Electrical Contractor"),
    1406: ("8021", "2.9% + $0.30", "0.5%", 25.00, True, "Dentists, Orthodontists"),
    # ... 258 total
}
```

### KB Template Mapping

**File:** `constants/kb_template_mapping.py`

Maps `kb_sub_code` → template file:

```python
KB_TEMPLATE_MAPPING = {
    # kb_sub_code: (template_file, template_type, industry_category)
    512: ("plumber", "exact", "service_trades"),      # Has dedicated template
    508: ("hvac", "exact", "service_trades"),         # Has dedicated template
    509: ("landscaping", "shared", "service_trades"), # Uses shared template
    2001: ("retail_store", "shared", "retail"),       # Uses shared template
    # ... 258 total mappings
}
```

### Template Types

| Type | Meaning | Count |
|------|---------|-------|
| `exact` | Has dedicated .py template file | 20 |
| `shared` | Uses category template + AI customization | 238 |

---

## Layer 4: Per-Agent KB Scope (AgentKBScope)

**Added:** 2026-03-06 (Entity Wiring Sprint, Phase 1)

### Table: `agent_kb_scopes`

| Column | Type | Description |
|--------|------|-------------|
| id | int | Primary key |
| company_id | int | FK → companies.id (tenant isolation) |
| agent_id | int | FK → agents.id (which agent) |
| scope_type | str(32) | `category`, `tag`, `subcategory`, or `all` |
| scope_value | str(255) | The value to match (e.g., "sales", "technical") |
| priority | int | Higher = checked first |
| is_active | bool | Toggle without deleting |

### How It Works

**Without scope entries:** Agent sees all company KB (backward compatible).
**With scope entries:** Agent is filtered to only its assigned categories/tags.

```
Agent "Sarah" (customer service)
├── scope: category = "services"
├── scope: category = "faq"
└── scope: category = "pricing_structure"

Agent "Devon" (operations)
├── scope: category = "policies"
└── scope: category = "industry_knowledge"
```

### Where It's Enforced

| Layer | File | How |
|-------|------|-----|
| MCP tool | `mcp/tools/kb_search.py` | Queries AgentKBScope, post-filters results by category/tag |
| System prompt | `agents/conversation.py` | Injects scope into "Your KB Scope" section so agent knows its boundaries |
| Agent action log | `agents/tool_engine.py` | Logs AgentAction with agent_id on every tool call |

### Model File

`solid-backend/models/agent_kb_scope.py`

---

## KB Template Key

### Format: `{kb_sub_code}-{company_id}`

Every company gets a unique KB template key:

```
512-66   = Company 66's Plumber (512) template
512-67   = Company 67's Plumber (512) template
509-224  = Company 224's Landscaping (509) template
```

### Why This Matters

Even if 100 plumbers sign up, each gets:
- Their own `company_knowledge_base` entries
- Their own `gpt_contexts` entries
- Their own `kb_template_key`
- **Complete multi-tenant isolation**

### Service: `services/kb_template_key_service.py`

```python
class KBTemplateKeyService:
    @staticmethod
    def generate_key(kb_sub_code: int, company_id: int) -> str:
        """Generate compound key: 512-66"""
        return f"{kb_sub_code}-{company_id}"

    @staticmethod
    def parse_key(kb_template_key: str) -> Tuple[int, int]:
        """Parse key back to components"""
        parts = kb_template_key.split("-")
        return int(parts[0]), int(parts[1])
```

---

## Provisioning Flow

### New Company Signup

```
┌─────────────────────────────────────────────────────────────────────────────┐
│  1. User Signs Up (Commerce Webhook)                                        │
│     - Selects industry (kb_sub_code)                                        │
│     - Creates subscription                                                  │
└────────────────────────────────────────┬────────────────────────────────────┘
                                         │
                                         ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│  2. tenant_provisioning.py::provision_new_tenant()                          │
│     - Creates company record                                                │
│     - Sets company.kb_sub_code = selected industry                          │
│     - Creates admin user                                                    │
│     - Creates subscription                                                  │
└────────────────────────────────────────┬────────────────────────────────────┘
                                         │
                                         ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│  3. provision_gpt_contexts() [Line 1982]                                    │
│     - Creates 3 gpt_contexts entries:                                       │
│       ├── Personality (from config/personalities.py)                        │
│       ├── Identity Rules (from config/gpt_context_defaults.py)              │
│       └── Company KB (from config/gpt_context_defaults.py)                  │
└────────────────────────────────────────┬────────────────────────────────────┘
                                         │
                                         ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│  4. UnifiedKnowledgeBaseService.clone_industry_template_to_company()        │
│     - Looks up template from kb_sub_code (e.g., 512 → plumber.py)           │
│     - Clones ~50 entries to company_knowledge_base                          │
│     - Sets metadata.cloned_from_template                                    │
└────────────────────────────────────────┬────────────────────────────────────┘
                                         │
                                         ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│  5. Event: "company.provisioned" → KB Onboarding Food Fight                 │
│     - 24 Celery agents race to populate additional KB                       │
│     - ~550 industry-specific entries added                                  │
│     - Runs in background via tasks/kb_onboarding.py                         │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## Company Structure

### System Companies (DO NOT MODIFY)

| ID | Purpose | KB Behavior |
|----|---------|-------------|
| 1 | Dev/Testing | Manual KB, mirrors Company 3 |
| 2 | Clone Template | KB comes from CODE, not cloning |
| 3 | Solid# Production | Custom KB for solidnumber.com |

### Company 2 = Template Source (Important!)

Company 2 is cloned for **data structure** (sites, agents, settings), but KB content comes from:

1. `config/gpt_context_defaults.py` - Default GPT contexts
2. `config/personalities.py` - Personality options
3. `scripts/templates/industries/*.py` - Industry templates
4. `services/kb_template_service.py` - Cloning logic

**Company 2 does NOT need KB entries in the database!**

---

## kb_sub_code Validation Pipeline (Updated 2026-02-12)

The `kb_sub_code` flows through **three services** during onboarding. Understanding which service does what prevents data loss bugs.

```
Frontend (industry-benchmarks.ts)       46 industries, user-facing picker
        │
        │  POST /api/onboarding/industry  { kb_sub_code: 1200 }
        ▼
Platform Commerce (industries.py)       Pass-through validation only
        │                                Accepts ANY positive integer
        │  POST /api/v1/provisioning/create-tenant  { kb_sub_code: 1200 }
        ▼
Main Backend (kb_template_mapping.py)   SOLE AUTHORITY — 277 mappings
        │
        │  get_industry_code_for_business(business_type, kb_sub_code=1200)
        │  → KB_TEMPLATE_MAPPING[1200] → ("gym", "shared", "professional_services")
        ▼
UnifiedKnowledgeBaseService             Queries master_knowledge_base
        │                                WHERE kb_type = "gym"
        │                                Clones 36 entries → company_knowledge_base
        ▼
Company KB populated (company_id isolation)
```

### Authority Rules

| Service | Role | Validation |
|---------|------|------------|
| **Frontend** | User-facing picker | 46 hardcoded options in `industry-benchmarks.ts` |
| **Platform Commerce** | Pass-through | Accepts any positive integer (`kb_sub_code > 0`) |
| **Main Backend** | **SOLE AUTHORITY** | `kb_template_mapping.py` — 277 industry mappings |

### Adding New Industries

1. Add mapping to `solid-backend/constants/kb_template_mapping.py`
2. Create template `.py` in `scripts/templates/industries/` (if exact match needed)
3. Seed template into `master_knowledge_base` table
4. **No changes needed in Platform Commerce** (pass-through)
5. Optionally add to `solid-frontend/src/data/industry-benchmarks.ts` for the picker UI

### Bug History (2026-02-12)

Platform Commerce previously validated `kb_sub_code` against its own 45-industry `INDUSTRIES` dict. Codes not in that dict (e.g., 1200 for gym) were silently rejected and fell back to code 999, which has no backend mapping. Result: new tenants got **0 KB entries**. Fixed by changing validation to accept any positive integer. See `Owners-Manual/19-Onboarding/29-KB-PIPELINE-FIX.md`.

---

## Personality System

### File: `config/personalities.py`

### 15 Personality Types

| Key | Name | Agent Name | Description |
|-----|------|------------|-------------|
| professional | Professional | AI Assistant | Formal, efficient |
| southern | Southern Hospitality | Sarah | Warm, friendly |
| italian | Italian Enthusiast | - | Expressive, passionate |
| friendly | Super Sweet | - | Extra sweet, caring |
| tech_bro | Tech Bro | - | Casual, startup vibes |
| british | Proper British | - | Polite, proper |
| ada | Ada - AI Director | Ada | Educator, knowledgeable |
| cto | CTO - Technical Visionary | Nora | Confident, impressive |
| midwest | Midwest Friendly | Emma | Genuine, down-to-earth |
| northeast | Northeast Direct | Nora | Efficient, direct |
| west_coast | West Coast Casual | Jordan | Relaxed, modern |
| australian | Australian Mate | Mate | Friendly, casual |
| bilingual_spanish | Bilingual | Sofia | English/Spanish |
| canadian | Canadian Friendly | Maple | Polite, friendly |
| ada_sales | Ada - Sales Journey | Ada | Sales-focused educator |

### Personality Settings

| Setting | Options | Default |
|---------|---------|---------|
| sales_approach | mild, moderate, aggressive | mild |
| jokes_enabled | true, false | false |
| intensity | lite, mild, strong | lite |

### Usage in Chat

```python
from config.personalities import build_full_system_prompt

prompt = build_full_system_prompt(
    personality_type="southern",
    company_name="Acme Plumbing",
    sales_approach="mild",
    jokes_enabled=True,
    agent_name="Sarah",
    intensity="mild"
)
```

---

## Quick Reference

### How to Find a Company's KB

```sql
-- GPT Contexts (personality, identity)
SELECT * FROM gpt_contexts WHERE company_id = 3;

-- Company Knowledge Base (industry content)
SELECT * FROM company_knowledge_base WHERE company_id = 3;
```

### How to Check KB Template Key

```python
company = db.query(Company).get(66)
print(company.kb_template_key)  # "512-66"
```

### How to Clone KB to New Company

```python
from services.kb_template_service import KBTemplateService

service = KBTemplateService(db)
result = service.clone_kb_from_template(
    target_company_id=66,
    template_id=2,  # Company 2 is the template
    categories=["services", "faq"]
)
```

---

## Files Reference

| File | Purpose |
|------|---------|
| `services/ai/bridge.py` | Loads GPT contexts for AI |
| `services/unified_kb_service.py` | Unified KB operations |
| `services/kb_template_service.py` | Template cloning |
| `services/kb_template_key_service.py` | Key generation |
| `services/tenant_provisioning.py` | New company setup |
| `config/gpt_context_defaults.py` | Default GPT context templates |
| `config/personalities.py` | Personality configurations |
| `constants/mcc_codes.py` | MCC code mapping (258 types) |
| `constants/kb_template_mapping.py` | Template file mapping |
| `scripts/templates/industries/*.py` | 52 industry templates |
| `tasks/kb_onboarding.py` | KB food fight (24 agents) |
| `models/industry_knowledge_base.py` | Living inheritance tables |
| `services/kb_inheritance_sync_service.py` | Template sync logic |
| `tasks/kb_inheritance_tasks.py` | Celery sync tasks |
| `controllers/kb_inheritance_controller.py` | Inheritance API endpoints |

---

## Channel → Company Resolution

### Chat Widget (THE SECRET WEAPON)

**Table:** `chat_widgets`
**File:** `controllers/chat.py:_resolve_chat_config()`

```
┌─────────────────────────────────────────────────────────────────────────────┐
│  CHAT IDENTITY RESOLUTION                                                   │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  Priority 1: chat_id (PREFERRED)                                            │
│  ───────────────────────────────                                            │
│  chat_id="abc123xyz" → chat_widgets table lookup                            │
│                      → Returns: company_id, site_id, agent_id,              │
│                                 personality, kb_context_ids,                 │
│                                 greeting_message, theme, etc.               │
│                                                                             │
│  Priority 2: Origin Header (FALLBACK)                                       │
│  ────────────────────────────────────                                       │
│  origin="https://acmeplumbing.com" → sites.domain lookup                   │
│                                     → company_id only                       │
│                                                                             │
│  Priority 3: company_id in request (LAST RESORT)                            │
│  ───────────────────────────────────────────────                            │
│  company_id=66 → Used directly (default: 3 for solidnumber.com)             │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
```

### chat_widgets Table Structure

```sql
chat_widgets
├── id (PK)
├── chat_id (unique, indexed) -- "abc123xyz789" public identifier
├── company_id (FK→companies) -- Owner
├── site_id (FK→sites)        -- Optional site association
├── agent_id (FK→agents)      -- AI agent to use
├── personality              -- Personality override
├── kb_context_ids           -- Specific KB entries to use
├── allowed_domains          -- Security: only allow from these
├── greeting_message         -- Custom greeting
├── theme                    -- Visual customization
├── enable_actions           -- Enable callbacks, quotes, etc.
├── enable_lead_capture      -- Enable lead capture
├── enable_voice_callback    -- Enable AI voice callbacks
├── is_active                -- Can be disabled
├── total_conversations      -- Analytics
├── total_messages           -- Analytics
└── total_leads_captured     -- Analytics
```

### Embed Code (Merchants)

```html
<!-- Generated per widget -->
<script
    data-chat-id="abc123xyz789"
    src="https://solidnumber.com/widget.js"
    async
></script>
```

Works on ANY platform: Wix, Squarespace, WordPress, custom sites.

### Why chat_id is Better Than company_id

| Concern | company_id | chat_id |
|---------|------------|---------|
| **Security** | Exposes internal ID | Opaque, meaningless to attacker |
| **Revocation** | Can't revoke without breaking everything | Can disable/rotate per widget |
| **Analytics** | Hard to track per-site | Track per widget |
| **Customization** | Same for all sites | Different greeting/theme per widget |
| **Multi-site** | One ID for all sites | Different widget per site |

### Voice Calls (Inbound)

**File:** `controllers/voice.py:handle_incoming_call()`

```
Called Phone Number → phone_config lookup → company_id
```

Resolution order:
1. Get `To` number from Twilio webhook
2. Query `company_phone_numbers`
3. Return `phone_config.company_id`

```python
# Example flow
to_number = "+18016916486"
→ SELECT company_id FROM company_phone_numbers WHERE phone_number = '+18016916486'
→ company_id = 66
→ Uses Acme Plumbing's KB
```

### Voice Calls (Outbound/Callback)

**File:** `services/openai_realtime.py`

```
Call record → call.company_id → already set
```

Outbound calls are initiated WITH a company_id, so no resolution needed.

---

## Critical Rules

### 1. NEVER Access KB Without company_id Filter

```python
# WRONG - Data leakage!
db.query(GPTContext).all()

# CORRECT
db.query(GPTContext).filter(GPTContext.company_id == company_id).all()
```

### 2. GPT Context Types Must Be: system, master, or context

The code only handles these three types. Using `faq` or other types will NOT be loaded.

### 3. Company 2 KB Comes from Code, Not Database

Don't add KB entries to Company 2. Templates come from `config/` and `scripts/templates/`.

### 4. kb_sub_code is the Industry Identifier

- Maps to MCC code (payment processing)
- Maps to template file (KB content)
- Combined with company_id for kb_template_key

---

## Complete Channel Mapping (THE SECRET WEAPON)

All channels follow the same pattern: unique identifier → company_id → KB → Agent → Personality

```
┌─────────────────────────────────────────────────────────────────────────────────────┐
│                          CHANNEL IDENTITY ARCHITECTURE                              │
├─────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                     │
│  ┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐       │
│  │   CHAT      │     │   VOICE     │     │   EMAIL     │     │   WEBSITE   │       │
│  │   WIDGET    │     │   PHONE     │     │   ADDRESS   │     │   DOMAIN    │       │
│  └──────┬──────┘     └──────┬──────┘     └──────┬──────┘     └──────┬──────┘       │
│         │                   │                   │                   │               │
│         ▼                   ▼                   ▼                   ▼               │
│  chat_id="abc123"    phone="+1801..."    email@domain    domain.com                │
│         │                   │                   │                   │               │
│         └───────────────────┴───────────────────┴───────────────────┘               │
│                                     │                                               │
│                                     ▼                                               │
│                         ┌─────────────────────┐                                     │
│                         │     company_id      │                                     │
│                         └──────────┬──────────┘                                     │
│                                    │                                                │
│              ┌─────────────────────┼─────────────────────┐                          │
│              │                     │                     │                          │
│              ▼                     ▼                     ▼                          │
│      ┌─────────────┐       ┌─────────────┐       ┌─────────────┐                    │
│      │ GPT Contexts│       │  Company KB │       │    Agent    │                    │
│      │ (Personality│       │  (Industry  │       │ (Settings,  │                    │
│      │  Identity)  │       │   Content)  │       │  Voice)     │                    │
│      └─────────────┘       └─────────────┘       └─────────────┘                    │
│                                                                                     │
└─────────────────────────────────────────────────────────────────────────────────────┘
```

### Channel Parity Table

| Channel | Table | Unique ID | company_id | agent_id | personality | kb_context_ids | Analytics |
|---------|-------|-----------|------------|----------|-------------|----------------|-----------|
| Chat | `chat_widgets` | `chat_id` | ✓ | ✓ | ✓ | ✓ | conversations, messages, leads |
| Voice | `company_phone_numbers` | `phone_number` | ✓ | ✓ | ✓ | ✓ | calls, minutes, sms, leads |
| Voice (legacy) | ~~`voice_phone_numbers`~~ RETIRED — use `company_phone_numbers` | `phone_number` | ✓ | ✓ | ✓ | ✓ | calls, minutes, leads |
| Website | `sites` | `domain` | ✓ | - | - | `kb_id` | page_views |
| Email | `company_email_addresses` | `email` | ✓ | - | - | - | - |

### Provisioning Flow

```
New Company Signup
        │
        ▼
┌───────────────────────────────────────┐
│ provision_new_tenant()                │
│                                       │
│ 1. Create company record              │
│ 2. Create admin user                  │
│ 3. Create subscription                │
│ 4. provision_gpt_contexts()           │  ← KB (personality, identity, knowledge)
│ 5. provision_chat_widget()            │  ← Chat (unique chat_id)
│ 6. KB Onboarding Food Fight           │  ← 550+ industry entries
└───────────────────────────────────────┘
```

### Embed Code Examples

**Chat Widget (any platform):**
```html
<script
    data-chat-id="abc123xyz789"
    src="https://solidnumber.com/widget.js"
    async
></script>
```

**Voice (Twilio webhook):**
```
Incoming call to +18016916486
→ Twilio webhook: /api/v1/voice/incoming
→ Lookup: phone_number → company_id
→ Use company's KB, agent, personality
```

---

*Documentation generated 2026-01-16*


--- FILE: 03-AI-Systems/MCP-INDEX.md ---

---
topic: ai-systems
keywords: [AI, agents, MCP, SmartRouter, LLM, orchestration, knowledge-base]
code_paths:
  - agents/*.py
  - mcp/tools/*.py
  - mcp_server/*.py
  - mcp_http/*.py
  - mcp/*.py
last_verified: 2026-03-06
status: current
priority: high
owner: platform-team
---

# MCP Tool List Documentation - Master Index

**Last Updated**: 2026-03-06 ✅ PRODUCTION LIVE
**Original Document**: MCP_LIST.md (2,064 lines - split for maintainability)
**Deployment Status**: ✅ Version 2.2.0 Deployed (Company MCP Discovery Auto-Generation)
**Health Check**: ✅ ALL SYSTEMS OPERATIONAL

---

## START HERE

**[AI-COMMERCE-LAYER.md](./AI-COMMERCE-LAYER.md)** — The single playbook for how external AI discovers, browses catalogs, and transacts with Solid# businesses. Covers all 3 tiers: Discovery, Catalog, and Intent (agent-to-agent).

---

## ARCHITECTURE OVERVIEW - Two-Tier MCP System

### **System Status**: PRODUCTION READY

1. **INTERNAL MCP** (Private - 349+ Tools, 100+ Files)
   - Secure endpoints for company's own AI agents (ADA, Annie, Devon, Sarah)
   - Full access to real database with tenant isolation
   - System maintenance, supply checks, intrusion detection
   - JWT authentication + RBAC enforced on all tools
   - AI agent communication verified and operational
   - See documents below for tool categories

2. **CUSTOMER INSTANCE MCP** (solid-mcp-server — 28 Tools)
   - External MCP server for AI editors (Claude Code, Cursor, Windsurf)
   - Schema discovery, field management, workflow automation
   - Calendar, KB, agent assignment, Google Workspace status
   - Vibe engine: natural language business modifications
   - Auth: `X-API-Key` header (company-scoped) + `X-Company-ID`
   - Source: `solid-mcp-server/src/customer-instance-tools.js`
   - See: [MCP Editor Integration](../45-Developer-CLI/10-MCP-EDITOR-INTEGRATION.md) for full tool list

3. **EXTERNAL MCP** (Public - AI Discoverability)
   - Public-facing for Google, Bing, ChatGPT, Claude, Grok, LLMs
   - Queries PUBLIC STAGING AREA only (NOT real database) ✅ VERIFIED
   - Domain-aware routing (auto-detects company from domain/subdomain) ✅ TESTED
   - Multi-tenant isolation via domain OR X-Company-ID header ✅ TESTED
   - Availability signals (NO exact inventory counts) ✅ ENFORCED
   - LLM context in all responses (company_id, company_name, scope) ✅ VERIFIED
   - Security score: 10/10 (all threats mitigated)
   - See [MCP_PUBLIC.md](MCP-PUBLIC.md), [DOMAIN_BASED_MCP_ROUTING.md](../DOMAIN_BASED_MCP_ROUTING.md), [MCP_PUBLIC_STAGING_AREA.md](MCP-PUBLIC-STAGING-AREA.md)

---

## 📚 INTERNAL MCP Tools by Category

1. **MCP_SYSTEM_DEV.md** - System, Introspection & Development Tools (96 lines)
2. **MCP_ADA_PERFORMANCE.md** - ADA Orchestrator & Performance Monitoring (54 lines)
3. **MCP_PRODUCT_INVENTORY.md** - Product Management, Pricing, Inventory (278 lines)
4. **MCP_ANNIE_PROMOTERS.md** - Promoter & Affiliate Management (124 lines)
5. **MCP_DEVON_DEVOPS.md** - DevOps, Monitoring & Self-Healing (406 lines)
6. **MCP_SANDBOX_CRM.md** - Sandbox Management & CRM Tools (653 lines)
7. **MCP_INTEGRATIONS_PAYMENTS.md** - CRM Integrations & AI Payments (259 lines)
8. **MCP_CONNECTION_SUMMARY.md** - RPC, Connection Methods & Stats (144 lines)
9. **Postman MCP Server** - API Testing, Documentation & Developer Tools (100+ tools)
10. **Zapier MCP Integration** - Workflow Automation & 8,000+ App Integrations

### NEW: Landing Pages & KB Learning (November 2025)

11. **mcp/tools/landing_pages.py** - Landing Page Management (7 tools)
    - `landing_templates_list` - List available templates (7 templates)
    - `landing_template_get` - Get full template with layout JSON
    - `landing_page_create` - Create landing page from template
    - `landing_page_list` - List company's landing pages
    - `landing_page_publish` - Publish/unpublish pages
    - `landing_page_analytics` - Get page analytics (views, conversions)
    - `landing_pages_performance_summary` - Company-wide performance

12. **mcp/tools/kb_*.py** - Knowledge Base Tools (existing, enhanced)
    - `kb_get` - Retrieve KB entries (3-layer: Platform → Company → Rep → Client)
    - `kb_search` - Semantic search across KB
    - `kb_generate` - AI-generate new KB entries
    - `kb_update` - Update existing KB entries
    - `kb_create` - Create new KB entries
    - **NEW**: KB entries now auto-update from funnel learnings via KBLearningEvent

### NEW: Celery Tasks for AI Learning

13. **tasks/kb_learning.py** - KB Learning Service
    - `process_kb_learning_events` - Process pending learning events → update KB
    - `trigger_learning_event` - Create new learning event (called from app)
    - `scheduled_kb_learning` - Celery Beat task (every 15 min)
    - Helper functions: `create_lead_conversion_event`, `create_faq_gap_event`, `create_deal_won_event`

### NEW: Customer Instance MCP Tools (March 2026) ✅ COMPLETE

15. **solid-mcp-server/src/customer-instance-tools.js** - Customer Instance Tools (28 tools)

    **Discovery:** `solid_schema`, `solid_extensions`, `solid_capabilities`, `solid_explain`
    **Fields:** `solid_field_add`, `solid_field_update`, `solid_field_remove`
    **Workflows:** `solid_workflow_create`, `solid_workflow_test`, `solid_workflow_toggle`
    **Templates & Integrations:** `solid_template_update`, `solid_integration_connect`, `solid_integration_test`, `solid_app_create`
    **Deployment:** `solid_preview`, `solid_deploy`, `solid_rollback`
    **Troubleshooting:** `solid_logs`, `solid_errors`, `solid_health`
    **Calendar:** `solid_calendar_list`, `solid_calendar_create`
    **Knowledge Base:** `solid_kb_list`, `solid_kb_search`, `solid_agent_kb_scope`
    **Agent & Workspace:** `solid_assign_agent_customer`, `solid_google_workspace_status`
    **Vibe Engine:** `solid_vibe`

    **Auth:** `X-API-Key` header (company-scoped MCP key)
    **Tenant Isolation:** `X-Company-ID` header on all tenant-scoped calls
    **MCP Clients:** Claude Code, Cursor, Windsurf, any MCP-compatible AI editor
    **See:** [MCP Editor Integration](../45-Developer-CLI/10-MCP-EDITOR-INTEGRATION.md)

### NEW: Vibe Engine MCP Tools (February 3, 2026) ✅ COMPLETE

16. **solid-mcp-server/src/vibe-tools.js** - Vibe Engine Tools (6 tools)
    - `vibe_capabilities` - Discover what vibe can create/modify for a company
    - `vibe_analyze` - Parse natural language prompt into intent + preview
    - `vibe_preview` - View before/after diff for pending changes
    - `vibe_apply` - Apply a previewed change (with safety + audit trail)
    - `vibe_rollback` - Undo a previous vibe action
    - `vibe_history` - View action history for a company

    **Backend Router:** `api/routers/mcp_vibe.py` → `/api/v1/mcp/vibe/*`
    **Auth:** `X-API-Key` header (MCP server) or JWT Bearer token (dashboard)
    **MCP Clients:** Cursor, Claude Desktop, any MCP-compatible AI client
    **Flow:** analyze → preview → apply (or rollback). Same safety/audit as dashboard.

### NEW: Per-Agent Digital Identity (March 2026) ✅ LIVE

16. **controllers/agent_public.py** - Per-Agent Public Identity (7 endpoints)
    - `GET /agents` - Agent directory (all enabled, customer-facing agents)
    - `GET /.well-known/agents.json` - Machine-readable agent directory
    - `GET /agents/{agent_type}` - Agent business card (JSON) — name, title, bio, contact, capabilities, employee capabilities, avatar
    - `GET /agents/{agent_type}/card` - Alias for business card
    - `GET /agents/{agent_type}/llms.txt` - Per-agent LLM-readable identity summary
    - `GET /agents/{agent_type}/mcp.json` - Per-agent MCP manifest (filtered capabilities)
    - `POST /agents/{agent_type}/chat` - Direct per-agent chat (proxies to AI pipeline)

    **Employee Capabilities:** calendar, inbound/outbound calls, meeting scheduling, meeting requests
    **Domain Detection**: Same as mcp_discovery.py (subdomain, custom domain, X-Company-ID header)
    **Security**: No internal IDs exposed, system_prompt never returned, only enabled + customer-facing agents
    **See:** [AGENT-DIGITAL-IDENTITY.md](AGENT-DIGITAL-IDENTITY.md) for full specification

### NEW: Company MCP Discovery (November 27, 2025) ✅ TESTED

14. **controllers/mcp_discovery.py** - Auto-Generated MCP Discovery (4 endpoints)
    - `GET /.well-known/mcp.json` - MCP manifest (company-specific, domain-aware) — now includes agents_directory and agents_json links
    - `GET /.well-known/ai-plugin.json` - AI plugin manifest (ChatGPT/Claude)
    - `GET /api/mcp` - Company platform data (ALL sites, pages, services, FAQ)
    - `GET /api/mcp/openapi.json` - OpenAPI spec for company's public MCP

    **Domain Detection**: Auto-detects company from:
    - Subdomain: `acme.solidnumber.com` → company "acme"
    - Custom domain: `acme.com` → mapped company via `custom_domains` table
    - Header: `X-Company-ID: 123` → explicit override

    **ALL Site Types Included** (from `sites.site_type`):
    - `company` - Main company websites
    - `landing` - Landing pages
    - `shop` - E-commerce shops
    - `survey` - Survey funnels
    - `checkout` - Checkout flows
    - `ai_agent` - AI chatbot sites
    - `creator_store` - Promoter stores

    **ALL Page Types Included** (from `website_pages.category`):
    - `landing_pages` - Landing page content
    - `main_pages` - Core website pages
    - `blog_posts` - Blog articles

    **Data Exposed Per Company**:
    - Business profile (name, description, logo, industry)
    - ALL sites (main site, landing pages, shops, surveys, etc.)
    - ALL published pages (grouped by category)
    - Services/products (public catalog)
    - FAQ (from KB, `is_public=true`)
    - Contact information

    **See:** [MCP_COMPANY_DISCOVERY.md](MCP-COMPANY-DISCOVERY.md) for full documentation

---

## 🌍 EXTERNAL MCP (Public AI Discoverability)

9. **MCP_PUBLIC.md** - Public endpoints for Google, Bing, AI crawlers (UPDATED ✅)
10. **MCP_PUBLIC_STAGING_AREA.md** - Architecture design & data flow (NEW ✅)
11. **MCP_PUBLIC_STAGING_TESTING.md** - Testing guide & test results (NEW ✅ TESTED)
12. **MCP_SECURITY_ARCHITECTURE.md** - Complete security model (12,000+ lines)
13. **MCP_HEALTH_CHECK_REPORT.md** - System health & security analysis (NEW ✅)

---

## 🎯 Quick Reference by Agent

**ADA (Orchestrator)**: MCP_ADA_PERFORMANCE.md
**Annie (Promoter Manager)**: MCP_ANNIE_PROMOTERS.md
**Devon (DevOps Engineer)**: MCP_DEVON_DEVOPS.md
**Marcus (Marketing Manager)**: mcp/tools/marcus_*.py, mcp/tools/marketing_*.py, **mcp/tools/landing_pages.py** ✅ NEW
**Maya (Brand Manager)**: mcp/tools/maya_*.py, **mcp/tools/landing_pages.py** ✅ NEW
**Sarah (Customer Service)**: mcp/tools/sarah_*.py
**All CRM Tools**: MCP_SANDBOX_CRM.md
**Product & Inventory**: MCP_PRODUCT_INVENTORY.md
**Development**: MCP_SYSTEM_DEV.md
**API Testing**: Postman MCP Server (100+ tools)
**Workflow Automation**: Zapier MCP (8,000+ apps)
**Public Discovery**: MCP_PUBLIC.md, MCP_PUBLIC_STAGING_AREA.md, AGENT-DIGITAL-IDENTITY.md
**Per-Agent Identity**: controllers/agent_public.py (7 endpoints — directory, business card, chat, llms.txt, mcp.json)
**KB System**: mcp/tools/kb_*.py, **tasks/kb_learning.py** ✅ NEW
**Customer Instance**: solid-mcp-server/src/customer-instance-tools.js ✅ NEW (28 tools — schema, fields, workflows, calendar, KB, agents, vibe)
**Vibe Engine (External)**: solid-mcp-server/src/vibe-tools.js ✅ (6 tools for Cursor/Claude Desktop)

---

## 🔒 Key Principle: "Share, Don't Expose"

- **Internal MCP**: Full database access for company's own AI
- **External MCP**: Public staging area with sanitized data only
- **Multi-Tenant**: Every company sees ONLY their own products
- **No PII/PCI**: Zero exposure of sensitive customer/business data

---

**Created**: 2025-10-16 | **Major Updates**: 2025-10-17 (Staging), 2025-10-18 (Domain Routing), 2026-03-06 (Customer Instance Tools + Entity Wiring)
**Production Deployed**: 2025-10-18 | **Last Updated**: 2026-03-06

---

## 📊 System Metrics (March 6, 2026)

- **Total MCP Tools**: 608 across 14 MCP servers (per PLATFORM-METRICS.md)
- **Internal Tools**: 349+ functions in mcp/tools/ registry
- **Customer Instance Tools**: 28 (solid-mcp-server/src/customer-instance-tools.js)
- **Vibe Engine Tools**: 6 (solid-mcp-server/src/vibe-tools.js)
- **External Endpoints**: 19 public + 2 external MCP (domain-aware)
- **Security Score**: 10/10 (all threats mitigated)
- **Multi-Tenant Isolation**: PERFECT (zero leakage, domain-based)
- **Domain Detection**: ACTIVE (custom domains + subdomains)
- **LLM Context Injection**: ACTIVE (company attribution in all responses)
- **Auto-Generated Discovery**: ACTIVE (per-company MCP manifests)
- **Production Ready**: YES ✅


--- FILE: 01-Architecture/CONTROL-PLANE.md ---

---
topic: architecture
keywords: [architecture, across, action, agent, agent-specific, agents, apis, approval]
last_verified: 2026-05-25
status: current
priority: critical
owner: platform-team
---

# Control Plane & Agent Infrastructure

> Complete guide to the AI agent microservice architecture.
>
> **Why this design:** The agent control plane runs as a separate FastAPI service (port 8091) from the main backend (port 8090) because agent conversations are long-lived, memory-intensive, and involve streaming LLM responses that would starve short-lived CRUD endpoints. The 4-tier memory architecture (short-term Redis, medium-term patterns, long-term PostgreSQL, cross-agent signals) exists because agents need different recall horizons — a current conversation context (2hr TTL) is fundamentally different from a learned customer preference (permanent).
>
> **When this applies:** When building or modifying agent behavior, adding MCP tools, changing context handling, or debugging why an agent responded incorrectly. Every agent message flows through this control plane: routing, provider selection, prompt enrichment, tool execution, and persistence.

**Last Updated:** May 25, 2026

---

## Overview

The agent infrastructure is a modular, multi-tenant AI system running as a separate FastAPI microservice. It supports multiple LLM providers and autonomous agent orchestration with comprehensive memory management.

### Key Statistics

| Metric | Value |
|--------|-------|
| **Total Files** | 74 Python files |
| **Code Size** | 2.8MB |
| **Service Port** | 8091 (separate from main backend 8090) |
| **Primary Orchestrator** | ADA (VP of AI) |
| **LLM Providers** | 3 (Claude, GPT, Grok) |

---

## Architecture Overview

```
User Message
    ↓
Main Backend (8090)
    ↓
Agent Engine (8091)
    ↓
1. Route to ConversationManager
    ↓
2. Resolve LLM Provider (Tier 1→3)
    ↓
3. Load Agent Definition from Registry
    ↓
4. Build Enhanced System Prompt:
    - Base agent prompt
    - Markdown memory (company/tier/agent)
    - User personalization
    - MCP tool schemas
    ↓
5. Send to Selected LLM Provider
    ↓
6. If tool calls → execute via Tool Engine:
    - Gate checking
    - Company_id injection
    - MCP execution
    ↓
7. Format response and persist
    ↓
Response to Frontend
```

---

## Directory Structure

```
agents/
├── llm/                      # LLM Provider Layer
│   ├── base.py               # Abstract base classes
│   ├── anthropic_provider.py # Claude support
│   ├── openai_provider.py    # GPT support
│   ├── xai_provider.py       # Grok support
│   └── factory.py            # Provider instantiation
│
├── memory/                   # Memory System
│   ├── manager.py            # Unified interface
│   ├── short_term.py         # Redis, 2hr TTL
│   ├── medium_term.py        # Pattern recognition
│   ├── long_term.py          # PostgreSQL persistent
│   └── cross_agent.py        # Inter-agent signals
│
├── memory_engine.py          # Markdown memory (539 lines)
├── conversation.py           # Multi-turn handling (1,065 lines)
├── orchestrator.py           # Core orchestration (600 lines)
├── tool_engine.py            # Tool execution (486 lines)
├── context_manager.py        # Persistent context (302 lines)
├── registry.py               # Agent definitions (2,050 lines)
├── server.py                 # FastAPI service (392 lines)
├── tool_categories.py        # Tool gating (282 lines)
└── kb_orchestrator.py        # KB bridge (481 lines)
```

---

## Memory System

### 4-Tier Memory Architecture

```
┌─────────────────────────────────────────────┐
│ Tier 4: Cross-Agent Memory                  │
│ - Inter-agent communication                 │
│ - Redis pub/sub for real-time signals       │
│ - Agent inbox system                        │
├─────────────────────────────────────────────┤
│ Tier 3: Long-Term Memory                    │
│ - PostgreSQL persistent storage             │
│ - Semantic search with embeddings           │
│ - Importance scoring                        │
├─────────────────────────────────────────────┤
│ Tier 2: Medium-Term Memory                  │
│ - Redis-based, 48hr TTL                     │
│ - Pattern recognition                       │
│ - Behavioral signals                        │
├─────────────────────────────────────────────┤
│ Tier 1: Short-Term Memory                   │
│ - Redis-based, 2hr TTL                      │
│ - Current conversation context              │
│ - Session-scoped facts                      │
└─────────────────────────────────────────────┘
```

### Markdown Memory Engine

Company-isolated memory using `.md` files:

```python
# Memory Hierarchy
1. Tier Base Prompt: prompts/tiers/{tier_slug}.md
2. Company Context: memory/company_{id}/context.md
3. Agent-Specific: memory/company_{id}/agents/{agent_type}.md
4. User Personalization: First-name greetings, role-based

# Usage
memory_engine.build_enhanced_prompt(
    base_prompt,
    company_id,
    agent_type,
    tier_slug,
    user_name,
    user_role
)
```

---

## Tool Engine

### Tool Execution Flow

```python
# Execute a tool with automatic security
result = await tool_engine.execute_tool(
    tool_name="create_invoice",
    tool_input={"amount": 100, "customer_id": 123},
    company_id=456,      # Automatic injection
    user_id=789,
    agent_id="ada"
)

# Returns
{
    "status": "success" | "blocked" | "pending_approval",
    "result": {...},
    "gate_status": "approved" | "pending",
    "approval_id": "..." # if pending
}
```

### Security Gate Categories

| Category | Description | Gate Check |
|----------|-------------|------------|
| `READ_ONLY` | Safe reads | None |
| `SPEND_MONEY` | Financial actions | Approval thresholds |
| `CUSTOMER_CONTACT` | Communications | Communication approval |
| `DATA_MODIFICATION` | Write operations | Write gates |
| `INTER_AGENT` | Agent messaging | Agent permissions |

---

## Orchestrator

### Key Responsibilities

```python
# 1. Action Execution
result = await orchestrator.execute_action(
    agent_id="ada",
    action_type="check_inventory_levels",
    company_id=123,
    context={}
)

# 2. Approval Workflows
approval = await orchestrator.create_approval_request(
    agent_id="ada",
    company_id=123,
    title="Large Refund",
    description="Refund $500 for order #123",
    proposed_action={"tool": "process_refund", "params": {...}},
    estimated_cost=500
)

# 3. KB Integration
insights = await orchestrator.get_sales_insights_with_ai(company_id)

# 4. Agent Coordination
plan = await orchestrator.coordinate_agents(
    company_id=123,
    situation="Customer complaint about delayed order",
    involved_agents=["sage", "devon"]
)
```

---

## Conversation Manager

### Multi-Turn Handling

```python
# Start conversation
result = await manager.start_conversation(
    agent_id="sage",
    agent_definition=registry.get("sage"),
    initial_message="Hello, I have a question",
    context={"customer_id": 123},
    company_id=456
)

# Continue conversation
result = await manager.continue_conversation(
    conversation_id=result["conversation_id"],
    message="What about my order?",
    company_id=456
)
```

### Provider Resolution

```python
# Tier 1: Agent-specific custom provider
if agent.llm_provider_id:
    use_custom_provider()

# Tier 2: Company-level preference
elif company.preferred_llm_provider:
    use_company_preferred()

# Tier 3: Platform default (Claude)
else:
    use_anthropic_provider()
```

---

## Agent Registry

### Core Agents

| Agent | Type | Autonomy | Purpose |
|-------|------|----------|---------|
| **ADA** | Orchestrator | 5 | Master coordinator |
| **Sarah** | Customer Service | 3 | Multi-channel communication |
| **Marcus** | Growth/Marketing | 4 | Campaigns, lead scoring |
| **Devon** | Operations | 4 | System health, monitoring |

### Agent Definition Structure

```python
{
    "name": "ADA",
    "agent_type": "ada",
    "avatar_url": "/avatars/ada.png",
    "description": "VP of AI - Master orchestrator",
    "autonomy_level": 5,
    "capabilities": {
        "mcp_tools": ["list_customers", "create_invoice", ...]
    },
    "system_prompt": "You are ADA, the VP of AI...",
    "approval_thresholds": {
        "max_refund": 500,
        "max_purchase": 1000,
        "max_cost_per_action": 50
    }
}
```

---

## Server Configuration

```python
# FastAPI Microservice
# Port: 8091 (separate from main backend)
# CORS: localhost:3000 (frontend), localhost:8090 (backend)

# Key Endpoints
POST /chat           # Send message to agent
POST /action         # Execute agent action
POST /approval       # Create approval request
POST /conversation   # Start new conversation
GET  /agents         # List available agents
GET  /performance    # Agent metrics
```

---

## Multi-Tenancy & Security

### Company Isolation
- All memory scoped by `company_id`
- Tool execution auto-injects `company_id`
- Separate markdown memory per company
- No cross-tenant context bleeding

### Agent Isolation
- Agent-specific memory separate from company-wide
- Custom LLM provider per agent (optional)
- Approval gates per agent type
- Autonomy limits enforced

### Gate Enforcement
- Pre-execution validation
- Spend amount thresholds
- Approval request creation
- Real-time blocking for paused agents

---

## Context Manager

```python
# Persistent agent memory across sessions
context_manager = AgentContextManager(agent_id, company_id, db)

# Store learning
context_manager.add_context(
    content="Customer prefers email over SMS",
    context_type="learned_facts",
    importance=7
)

# Retrieve context
contexts = context_manager.get_context(
    context_type="learned_facts",
    limit=10,
    min_importance=5
)

# Build enhanced prompt
prompt = context_manager.build_system_prompt_with_context(
    base_prompt,
    include_types=["personality", "learned_facts"]
)
```

---

## Integration Points

### With Frontend
- WebSocket connections for real-time chat
- Approval UI for gated actions
- Agent memory/context dashboard

### With Main Backend
- REST proxy: 8090 → 8091
- Shared database (PostgreSQL)
- Shared MCP tool registry

### With External APIs
- Anthropic Claude API
- OpenAI GPT API
- xAI Grok API
- MCP tool execution

---

## Best Practices

1. **Always use company_id isolation** in all queries
2. **Check gate status** before executing sensitive tools
3. **Log all agent actions** for audit trail
4. **Use approval workflows** for high-value actions
5. **Leverage memory tiers** appropriately
6. **Monitor agent performance** metrics
7. **Set appropriate autonomy levels** per agent

---

## Related Documentation

- [Agent Registry](../03-AI-Systems/AGENT-REGISTRY.md) - All 32 AI agents
- [LLM Provider System](../02-Backend/llm-provider-system.md) - Multi-provider support
- [AI Infrastructure](../03-AI-Systems/AI-INFRASTRUCTURE.md) - CognitiveLimiter, SmartRouter
- [MCP Integration](../03-AI-Systems/MCP-INTEGRATION.md) - 655 tools

---

*Agents think. Tools act. Memory learns. Orchestrator coordinates.*


--- FILE: 09-Core-Innovations/COMPLETE-FEATURE-INVENTORY.md ---

---
topic: core-innovations
keywords: [core-innovations, accounting, actually, additional, agents, ai-first, analytics, analyzer, anchoring]
code_paths:
  - solid-backend/controllers/ai_chat_integration.py
  - solid-backend/controllers/ai_content_generation.py
  - solid-backend/controllers/ai_discoveries.py
  - solid-backend/controllers/ai_orchestration.py
  - solid-backend/controllers/ai_workflow_builder.py
  - solid-backend/controllers/customer_portal_ocr_controller.py
  - solid-backend/controllers/gateway_payouts.py
  - solid-backend/services/ai_agent_service.py
  - solid-backend/services/ai_content_generator.py
  - solid-backend/services/ai_data_adapter.py
  - solid-backend/services/ai_data_cleaning.py
  - solid-backend/services/ai_field_mapper.py
  - solid-backend/services/ai_field_mapper_enhanced.py
  - solid-backend/services/ai_log_analyzer.py
  - solid-backend/services/ai_qr_service.py
  - solid-backend/services/ai_survey_builder.py
  - solid-backend/services/ai_universal_search.py
  - solid-backend/services/lead_scoring_engine.py
  - solid-backend/services/openai_realtime.py
  - solid-backend/services/payout_execution_service.py
  - solid-backend/services/voice/core/session.py
  - solid-backend/tasks/payout_tasks.py
last_verified: 2026-08-29
status: current
priority: critical
owner: platform-team
---

# Complete Feature Inventory

> Every feature in Solid# - the full picture.

---

## OVERVIEW: What Solid# Actually Is

Solid# is not a simple CRM. It's a **complete AI-native business operating system** with:

- **32 AI Agents** that work autonomously, backed by 271 Celery task functions (see `Owners-Manual/PLATFORM-METRICS.md` — these figures are DERIVED by `scripts/platform_metrics.py`, never hand-typed)
- **655 MCP Tools** for AI integration (see `Owners-Manual/PLATFORM-METRICS.md`)
- **Industry Templates with pre-built knowledge** — see `Owners-Manual/PLATFORM-METRICS.md` for the current DERIVED counts (Industry Templates + MCC Code Mappings are now separate script-generated rows there; the old "234 Industry Templates / 277 KB Template Mappings" combined figure below is stale and conflated two different metrics)
- **API Endpoints** — see `Owners-Manual/PLATFORM-METRICS.md` for the current DERIVED count (was 1,342, stale)
- **Database Tables** — see `Owners-Manual/PLATFORM-METRICS.md` for the current DERIVED count (was "2,040+", stale — the gap to today's real count is unusually large and its origin is unverified); SQLAlchemy model classes were hand-counted 2026-08-29 at 638 (`grep -E "^class .*Base" solid-backend/models/*.py`), not 3,170
- **25+ Payment Features**
- **30+ AI-First Features**
- **12 Embeddable Calculator Apps**
- **Full CMS with AI Builder**
- **Universal Data Import Engine**
- **AI Video Studio** for creative communications
- **Document Formatting Engine** (AI↔Human bridge)
- **Sales Intelligence Research** (company → CRM → KB)
- **Dogfooding System** (Company ID 3 internal testing)

---

## 1. AI-FIRST FEATURES (30+)

### AI Content Generation
**Files:** `services/ai_content_generator.py`, `controllers/ai_content_generation.py`

| Feature | Description |
|---------|-------------|
| **Email Generation** | Marketing emails with subject lines, CTAs, personalization |
| **Social Media Posts** | Facebook, Instagram, LinkedIn, Twitter with hashtags |
| **Blog Posts** | Full SEO-optimized articles with meta descriptions |
| **Ad Copy** | Google Ads, Facebook Ads, LinkedIn Ads with A/B variants |
| **Brand Voice Engine** | Consistent tone across all generated content |

### AI Data Import System
**Files:** `services/ai_field_mapper.py`, `services/ai_field_mapper_enhanced.py`, `services/ai_data_adapter.py`

| Feature | Description |
|---------|-------------|
| **CSV/Excel Analysis** | AI analyzes columns, detects types, patterns |
| **Smart Field Mapping** | Maps to CRM schema with confidence scores |
| **Data Transformation** | Split, concatenate, format recommendations |
| **Missing Field Detection** | Identifies required fields |
| **JSONB Custom Fields** | Handles ANY data structure |
| **Multi-Table Mapping** | Maps to customers, contacts, addresses |

### AI Data Cleaning
**File:** `services/ai_data_cleaning.py`

| Feature | Description |
|---------|-------------|
| **Email Validation** | Validates and normalizes emails |
| **Phone Formatting** | Standardizes phone numbers |
| **Name Standardization** | Proper casing with special handling |
| **Address Normalization** | Consistent address formats |
| **Duplicate Detection** | Email-based and name-based matching |
| **Duplicate Merging** | Intelligent merge with tag consolidation |

### AI Universal Search
**File:** `services/ai_universal_search.py`

| Feature | Description |
|---------|-------------|
| **Natural Language Search** | "mortgage leads in California" |
| **Semantic Search** | Fuzzy matching for names/emails |
| **Phone Search** | Format-tolerant phone lookup |
| **Location Search** | State, city, zip filtering |
| **Tag Search** | Match-all or match-any logic |
| **JSONB Search** | Search custom fields |
| **Cross-Table Search** | Customers + CRM contacts unified |

### AI Survey Builder
**File:** `services/ai_survey_builder.py`

| Feature | Description |
|---------|-------------|
| **Natural Language Creation** | "Create an NPS survey" → full survey |
| **Smart Field Types** | Scale, textarea, matrix, checkbox, etc. |
| **Conditional Logic** | Branching questions |
| **Skip Logic** | Progressive disclosure |
| **Completion Predictions** | Estimated completion rates |
| **Response Analysis** | Sentiment detection |
| **Follow-Up Generation** | Auto-generate follow-up surveys |

### AI Voice/Phone
**Files:** `services/voice/` (context/persona.py, cost/context_compiler.py, core/, provider/, transport/, profiles/, persistence.py), `controllers/voice_engine_v2.py`, `services/openai_realtime.py` — `services/voice_call_handler.py` was DELETED 2026-08-19 (9,544-line god file); do not look for it

| Feature | Description |
|---------|-------------|
| **Real-Time Voice AI** | OpenAI Realtime API integration |
| **Twilio Bridge** | Phone call WebSocket integration |
| **Transcript Saving** | Full call transcripts |
| **KB-Enriched Responses** | Voice AI uses company knowledge |
| **Multi-Agent Voice** | Different agent personalities |

### AI OCR & Invoice Scanning
**File:** `controllers/customer_portal_ocr_controller.py`

| Feature | Description |
|---------|-------------|
| **GPT-4 Vision OCR** | Invoice/receipt scanning |
| **Handwriting Extraction** | Handwritten note parsing |
| **Data Extraction** | Customer, items, amounts, dates |
| **Confidence Scoring** | Accuracy confidence |
| **One-Click Payment Links** | Generate payment link from scan |

### AI Self-Healing System
**File:** `services/ai_agent_service.py`

| Feature | Description |
|---------|-------------|
| **Error Detection** | Automatic error analysis |
| **Fix Recommendations** | AI suggests fixes with severity |
| **Pattern Matching** | Subdomain conflict, DB, DNS issues |
| **Auto-Healing** | Automatic fix for high-severity |
| **Error Learning** | Improves over time |

### AI Chat Integration
**File:** `controllers/ai_chat_integration.py`

| Feature | Description |
|---------|-------------|
| **Website Chatbot** | Deployable AI chatbot |
| **Q&A Knowledge Base** | Train on company data |
| **Session Tracking** | Conversation continuity |
| **Embed Code** | One-click website integration |
| **Chat Analytics** | Conversations, tokens, performance |

### AI Log Analyzer
**File:** `services/ai_log_analyzer.py`

| Feature | Description |
|---------|-------------|
| **Claude-Powered Analysis** | Intelligent log parsing |
| **Issue Classification** | OOM, timeouts, deadlock, etc. |
| **Severity Levels** | Critical, high, medium, low |
| **Auto-Fix Detection** | Identifies fixable issues |
| **Root Cause Analysis** | Deep analysis |

### AI QR Code Generation
**File:** `services/ai_qr_service.py`

| Feature | Description |
|---------|-------------|
| **Artistic QR Codes** | AI-enhanced designs |
| **Brand Presets** | Ocean, forest, luxury, tech, cafe |
| **Custom Prompts** | Unique AI-generated designs |

### AI Lead Scoring
**File:** `services/lead_scoring_engine.py`

| Feature | Description |
|---------|-------------|
| **0-100 Scoring** | AI-calculated lead scores |
| **Email Engagement** | Open/click scoring |
| **Website Behavior** | Page views, time on site |
| **Purchase History** | Past transaction analysis |
| **Tier Classification** | Hot/Warm/Cold |
| **LTV Prediction** | Lifetime value estimation |
| **Conversion Probability** | Likelihood to convert |
| **Lookalike Identification** | Find similar customers |

### AI Workflow Builder
**File:** `controllers/ai_workflow_builder.py`

| Feature | Description |
|---------|-------------|
| **Natural Language Workflows** | "Every Monday email sales report" |
| **Auto Celery Tasks** | AI generates task code |
| **Automatic Scheduling** | Cron setup |
| **Task Library** | Pre-built operations |
| **Validation** | Pre-deployment checks |

### AI Discoveries (Proactive Insights)
**File:** `controllers/ai_discoveries.py`

| Feature | Description |
|---------|-------------|
| **Dream Jobs** | Proactive opportunity discovery |
| **Value Scoring** | 0-1.0 opportunity value |
| **Human Feedback Loop** | Training from feedback |
| **High-Value Highlighting** | Surface best opportunities |

### AI Orchestration
**File:** `controllers/ai_orchestration.py`

| Feature | Description |
|---------|-------------|
| **Multi-AI Collaboration** | OpenAI + Anthropic + KB |
| **KB Integration** | Context-aware responses |
| **Task Routing** | Intelligent provider selection |

### AI Creative Communications (NEW)
**File:** `AI-CREATIVE-COMMUNICATIONS.md`

| Feature | Description |
|---------|-------------|
| **Video in Email** | Sora/Veo-generated videos in business emails |
| **Animated Notifications** | Dancing mascots, celebration animations |
| **Template + Anchor Model** | Pre-approved templates + variable slots |
| **Emotion-Driven Content** | Happy/urgent/celebratory tone matching |
| **Multi-Channel Output** | Email, SMS, push notification, in-app |

### AI Video Studio (NEW)
**File:** `AI-VIDEO-STUDIO.md`

| Feature | Description |
|---------|-------------|
| **Multi-Model Support** | Sora, Veo, Runway, Pika, Kling |
| **Embed-First Architecture** | Link embedding (no storage overhead) |
| **Video Overlays** | Text, logos, CTAs on any video |
| **Freemium Generation** | 5 free/month, pro costs tokens |
| **Business Templates** | Welcome, reminder, celebration, thank-you |

### AI Hub (Two-Layer Architecture) (NEW)
**File:** `AI-HUB-ARCHITECTURE.md`

| Feature | Description |
|---------|-------------|
| **Platform AI (Layer 1)** | Solid#'s AI - always works, included in subscription |
| **Customer Keys (Layer 2)** | Customer's own Gemini/Claude/GPT keys |
| **Graceful Degradation** | Frontend handles missing endpoints cleanly |
| **Encrypted Key Storage** | AES-256 encrypted customer API keys |
| **Provider Status API** | Check if provider is configured |

### Document Formatting Engine (NEW)
**File:** `DOCUMENT-FORMATTING-ENGINE.md`

| Feature | Description |
|---------|-------------|
| **AI↔Human Bridge** | "AI speaks Markdown. Humans speak Google Docs." |
| **Any-to-Any Conversion** | MD ↔ Google Docs ↔ Word ↔ PDF ↔ HTML |
| **Multi-Output** | One input → many formats (email, PDF, presentation) |
| **Image-to-Document** | Photo of whiteboard → structured document |
| **Goal-Driven KB** | Business goals stored as KB entries drive AI behavior |

### Sales Intelligence Research (NEW)
**File:** `SALES-INTELLIGENCE-RESEARCH.md`

| Feature | Description |
|---------|-------------|
| **Company Deep Dive** | AI researches any company comprehensively |
| **Multi-Format Output** | Report, spreadsheet, CRM lead, KB entries |
| **Pre-to-Post-Sale Pipeline** | Research → Close → Converted to client KB |
| **Competitive Intelligence** | Pain points, tech stack, decision makers |
| **Auto CRM Population** | Research populates lead record automatically |

### Positive Anchoring System (NEW)
**File:** `POSITIVE-ANCHORING.md`

| Feature | Description |
|---------|-------------|
| **Celebration Triggers** | Milestone achievements, first sale, goal reached |
| **Gamification** | Points, streaks, badges, leaderboards |
| **Joy-Driven UX** | Confetti, animations, video celebrations |
| **Emotion Memory** | AI remembers and references past wins |
| **Team Celebrations** | Company-wide achievement notifications |

### Dogfooding System (NEW)
**File:** `DOGFOODING-INTERNAL-TESTING.md`

| Feature | Description |
|---------|-------------|
| **Company ID 3** | Solid# runs as its own customer |
| **Beta Feature Testing** | All features tested internally first |
| **Template Gallery Pipeline** | Best-performing content → customer templates |
| **A/B Testing Framework** | Statistical testing before rollout |
| **Feature Flag System** | Gradual rollout (10% → 50% → 100%) |

---

## 2. KNOWLEDGE BASE SYSTEM

### 4-Layer Architecture

```
LAYER 0: Platform KB (Solid# documentation)
    ↓
LAYER 1: Industry Templates (234 industries via MCC codes)
    ↓
LAYER 2: Company KB (Cloned + customized)
    ↓
LAYER 3: Rep KB (Per employee)
    ↓
LAYER 4: Client KB (Per customer)
```

### Industry Templates (MCC Code Mapped)

> **Re-verified 2026-08-29:** The "234 industries / 277 KB Template Mappings" figures below are stale and were never generated by a script. Current counts are DERIVED by `scripts/platform_metrics.py` and live in `Owners-Manual/PLATFORM-METRICS.md` ("Industry Templates" = `.py` files in `scripts/templates/industries/`, "MCC Code Mappings" = entries in `constants/mcc_codes.py`) — these are two distinct metrics that this doc previously conflated into one number. Do not hand-edit either count here; re-run the script and point here instead.

**Coverage includes:**
- Home Services (Electrical, HVAC, Plumbing, Roofing, etc.)
- Healthcare (Chiropractor, Dentist, Doctor, etc.)
- Professional Services (Mortgage Broker, Real Estate, Law Firm, etc.)
- Retail & E-commerce
- Food & Restaurant
- Construction & Trades
- And 200+ more industries

### KB Features

| Feature | Description |
|---------|-------------|
| **Vector Search** | OpenAI embeddings (1536 dimensions) |
| **Semantic Search** | Cosine similarity matching |
| **Hybrid Search** | Vector + keyword with RRF |
| **Re-ranking** | GPT-4 relevance re-ranking |
| **Context Compression** | LLM compression for token limits |
| **AI Generation** | Generate KB entries from topics |
| **AI Improvement** | Expand, simplify, technical modes |
| **RAG Pipeline** | Full retrieval-augmented generation |

---

## 3. PAYMENT & COMMERCE (25+ Features)

### Payment Processors
| Processor | Platform Fee | Status |
|-----------|--------------|--------|
| Solid Payments [DEFUNCT — retired; platform is multi-processor, 14 adapters] (retired processor) | 0% | Decommissioned |
| Stripe | 1% | Ready |
| PayPal | 1% | Ready |
| Square | 1% | Ready |
| Custom | 1% | Ready |

### Core Payment Operations
- `charge()` - Process payments (card, ACH, terminal)
- `authorize()` - Pre-authorization
- `settle()` / `capture()` - Settlement
- `refund()` - Full or partial refunds
- `void_transaction()` - Same-day cancellation

### Split Payments
- Multi-recipient payment splitting
- Marketplace commissions
- Multi-vendor payouts
- State tracking (INIT → SETTLED)

### Buy Now Pay Later (BNPL)
- Affirm, Klarna, Afterpay support
- Configurable installments
- Provider-agnostic API

### Payment Links & QR
- Unique secure link generation
- Expirable links
- QR code generation (with AI themes)
- Variable/flexible pricing
- Invoice association
- Text2Pay integration

### Invoicing
- Invoice creation and management
- PDF generation
- Due date tracking
- Payment collection
- Dunning automation

### Subscriptions
- Multiple tiers (Starter, Professional, Enterprise)
- Trial periods
- Recurring billing
- Feature gating per tier

### Commission System
- Promoter/affiliate management
- Commission rules and rates
- Ledger tracking
- Payout management

### Gateway Payout API (NEW)
**Files:** `controllers/gateway_payouts.py`, `services/payout_execution_service.py`, `tasks/payout_tasks.py`

| Feature | Description |
|---------|-------------|
| **Payout Configuration** | Per-company settings (frequency, time, minimum, hold period) |
| **ACH via the retired processor [platform is processor-agnostic via the adapter registry] /multipay** | Direct bank transfers using the retired processor |
| **3 Business Day Hold** | Commission hold period (Mon-Fri only, excludes weekends) |
| **$1.00 Payout Fee** | Per-transaction fee charged to company |
| **Payee Selection** | List all payees with balances, search, filter eligible |
| **Batch Payouts** | Select multiple payees and pay in one batch |
| **Scheduled Payouts** | Celery Beat runs hourly, checks company schedules |
| **Failed Retry Logic** | Automatic retry with configurable max attempts |
| **Payout History** | Full history with status filtering |
| **Partner Portal Ready** | 12 endpoints for Partner Portal integration |

**API Endpoints:**
- `GET /config` - Get payout configuration
- `PUT /config` - Update payout settings
- `POST /trigger` - Manual payout trigger
- `GET /pending` - Pending payouts summary
- `GET /history` - Payout history
- `GET /payees` - List payees with balances
- `GET /payees/{id}` - Payee details
- `POST /batch` - Batch payout for selected payees
- `POST /{id}/retry` - Retry failed payout
- `GET /methods` - Available payout methods
- `GET /schedule/preview` - Preview schedule

### Terminal/POS
- Physical terminal support
- Card swipe/insert/tap
- Lane management
- Tip adjustment

### Additional Payment Features
- Multi-currency support
- Tax calculations (Avalara, TaxJar)
- Chargeback management
- Card tokenization
- Saved payment methods
- Platform fee system

### Accounting Integrations (NEW)
**Files:** `services/accounting/`, `controllers/accounting/`

**The Big Three (95% Market Coverage):**

> **⛔ CORRECTED 2026-08-29:** All three statuses below are stale. `solid-backend/services/accounting/` now has substantial, non-stub implementations for all three: `quickbooks.py` (765 lines), `xero.py` (772 lines), `freshbooks.py` (742 lines), plus shared `oauth_service.py`, `pull_sync.py`, `sync_engine.py` (815 lines), `rate_limiter.py`, and `controllers/accounting/` (`connections.py`, `sync.py`, `webhooks.py`). None of these are "Planned" or "Future" stubs — whether each is live in production (vs. built-but-unshipped) wasn't verified this pass; ask before assuming go-live status.

| Integration | Market Share | Status |
|-------------|-------------|--------|
| **QuickBooks Online** | 80%+ of US SMBs | Built (`services/accounting/quickbooks.py`, 765 lines) — not "🔨 Building" |
| **Xero** | 15% US, dominant UK/AU/NZ | Built (`services/accounting/xero.py`, 772 lines) — not "📋 Planned" |
| **FreshBooks** | 5% (Freelancers) | Built (`services/accounting/freshbooks.py`, 742 lines) — not "📋 Future" |

**Entity Mapping:**

| Solid# | → QBO | → Xero | → FreshBooks |
|--------|-------|--------|--------------|
| Customer | Customer | Contact | Client |
| Invoice | Invoice | Invoice | Invoice |
| Payment | Payment | Payment | Payment |
| Product | Item | Item | Service |
| Expense | Purchase | Bill | Expense |

**Sync Capabilities:**
- Real-time push (invoice created → QBO in <5 sec)
- Batch nightly sync (catch-up reconciliation)
- Bidirectional customer/contact sync
- Payment recording
- Conflict resolution (Solid# wins, newer wins, manual)
- Full audit trail
- Rate limiter for Xero (60/min limit)

**Banking Layer (Future):**

| Service | Use Case |
|---------|----------|
| Plaid | Bank linking, transaction pull |
| Finicity | Lending/mortgage use cases |

**Philosophy:** We capture sales data, they handle the books. Perfect handoff.

---

## 4. CRM & MARKETING (14+ Features)

### Contact Management
- Full CRUD with multi-tenant isolation
- Contact types (contact, customer, lead)
- Custom fields
- Import/export
- Deduplication

### Lead Management
- Embeddable lead forms
- Lead scoring (A, B, C, D, X grades)
- Auto-qualification rules
- UTM tracking
- Geolocation
- Source attribution

### Deal/Pipeline
- Visual pipeline
- Customizable stages
- Deal probability
- Forecasting

### Proposal & Estimate System (NEW)
**File:** `proposal-estimate-system.md`

| Feature | Description |
|---------|-------------|
| **Document Types** | Proposals, estimates, bids, quotes |
| **Public Client Portal** | Secure `/p/{token}` links for clients |
| **Accept/Reject Flow** | One-click acceptance with digital signature |
| **AI Sales Chat** | AI assistant answers client questions about proposals |
| **Optional Line Items** | Clients can toggle optional items |
| **Activity Tracking** | Full audit trail (viewed, sent, accepted) |
| **Order Conversion** | Convert accepted proposals to orders |
| **Lead Source Tracking** | Attribution for analytics |

### Email Campaigns
- Campaign templates
- Personalization variables
- Engagement tracking (open, click, bounce)
- Two-way email threading
- Bounce/unsubscribe handling

### Drip Sequences
- Automated email sequences
- Trigger-based (contact created, deal stage, tag added)
- Conditional logic
- Stop conditions

### SMS Campaigns
- SMS messaging
- Delivery tracking
- Two-way SMS

### Social Media
- Account management
- AI content generation
- Posting and scheduling
- Engagement tracking

### A/B Testing
- Subject line testing
- Content variants
- Statistical significance

### Analytics & Reporting
- Campaign performance
- Lead source analytics
- ROI tracking
- Custom reports
- Export (CSV, Excel, PDF)

### Customer Segmentation
- Tag-based
- Source-based
- Custom field-based
- Dynamic segments

### Survey System
- AI-powered generation
- Multiple field types
- Response analysis
- Embed capabilities

### Forms & Landing Pages
- Drag-and-drop builder
- Template library
- Conversion tracking
- SEO metadata

---

## 5. CMS SYSTEM

### Page Management
- Visual page builder
- Block-based editing
- AI-powered content generation
- SEO optimization
- Multi-site support

### Blog Platform
- AI blog writer
- Draft management
- Publishing workflow
- SEO tools

### Media Library
- File upload
- Image optimization
- Asset management

### CMS Blocks
- Hero sections (multiple variants)
- Features grids
- Pricing cards
- FAQ accordions
- Testimonials
- CTA sections
- Contact forms
- Stats displays

### AI CMS Features
- `FloatingAIAssistant` - AI sidebar helper
- `BlogAIAssistant` - Blog-specific AI
- `AIFieldHelper` - Field suggestions
- Page generation from prompts

---

## 6. DATA IMPORT ENGINE

### Universal Data Mapper
**File:** `UNIVERSAL_DATA_MAPPING_ENGINE.md`

| Feature | Description |
|---------|-------------|
| **5-1000+ Columns** | Handles any CSV size |
| **AI Field Mapping** | GPT-4 + Claude analysis |
| **Data Quality Analysis** | Completeness, patterns |
| **Transformation Rules** | Preview before import |
| **JSONB Custom Fields** | Any data structure |

### Import Workflow
1. Upload CSV/Excel
2. AI analyzes columns
3. Suggests field mappings with confidence
4. Preview transformations
5. Validate before import
6. Execute with rollback support

---

## 7. EMBEDDABLE APPS (12 Tools)

### Mortgage Calculator Suite
| App | Features |
|-----|----------|
| **Virginia Calculator** | 6-step wizard, closing costs, DTI, LTV |
| **Maryland Calculator** | State-specific rates |
| **DC Calculator** | DC-specific rates |
| **Amortization Schedule** | 360-payment breakdown |

### Qualification Tools
| App | Features |
|-----|----------|
| **Pre-Qualification** | Quick QUAL sheet |
| **Income & Debt Worksheet** | 5-step comprehensive |
| **Self-Employed Analysis** | Tax return analyzer |
| **Rental Income Calculator** | Schedule E parsing |
| **VA Loan Worksheet** | VA residual income |

### Other Tools
| App | Features |
|-----|----------|
| **GFE Comparison** | 4-scenario side-by-side |
| **Tax Rate Reference** | County-by-county lookup |
| **Credit Card Auth** | PCI-compliant payment form |

### Embed Options
- iFrame embedding
- JavaScript widget
- Direct link
- White-label branding
- Lead capture integration

---

## 8. APP ENGINE

### Architecture
- Dynamic app loading
- Plugin system
- Per-industry app visibility
- Feature gating by subscription

### App Registry
- Apps directory with metadata
- Version management
- Dependency tracking
- Permission system

---

## 9. AI AGENTS

> **Re-verified 2026-08-29:** The old "116 AI Agents" header and the "Core Agents (15)" roster below are WRONG — most of those 15 names don't exist. Current truth is DERIVED by `scripts/platform_metrics.py` — see `Owners-Manual/PLATFORM-METRICS.md`: 32 distinct named agents (33 registry entries — ADA is registered twice, free + paid tier; 23 deeply trained; 57 code-defined counting the food + vegetable teams). Never hand-edit this count — change the code and re-run the script.
>
> Grepping `agents/registry.py` directly (2026-08-29) for the 15 names below: only **ADA** is real (registered twice). **ACE, MAYA, EMMA, ALEX** exist but under different casing (Ace, Maya, Emma, Alex). **FINN, OTTO, VERA, IRIS, NOVA, SAGE, ZARA, LUKE, REVA are not registry entries** (word-boundary, case-sensitive check — beware `mes`**`sage`**, which makes a case-insensitive grep for SAGE look like a hit). **SOPHIA is also not an agent entry**, though the name does appear in the file; she is not part of this roster — this roster was fabricated or describes a plan that was never built. The real roster (33 registry entries) is: ADA (×2), Sarah, Jake, Morgan, Marcus, Alex, Jordan, Maya, Riley, Ace, Annie, Devon, Atlas, Emma, Victor, Operator Console, Gwen, Kale, Carrot, Parsley, Beet, Radish, Spinach, Lettuce, Turnip, Pepper, Jackson, Lucie, Daphne, Dexter, Care Coordinator, Clinical Summarizer. For current names/roles/system prompts, read `agents/registry.py` directly — do not maintain a second hand-typed roster in this doc.

---

## 10. TOKEN ORCHESTRATOR (Multi-LLM)

### Supported Providers
| Provider | Models |
|----------|--------|
| **OpenAI** | GPT-4, GPT-4o-mini |
| **Anthropic** | Claude Opus, Sonnet, Haiku |
| **Google** | Gemini Pro |
| **xAI** | Grok |
| **Meta** | Llama |
| **Luma AI** | Video generation |
| **Runway** | Video generation |

### Features
- 3x markup billing
- Per-company usage tracking
- Promo code exemptions
- Provider failover
- Cost optimization routing

---

## 11. MCP SERVER

> **Re-verified 2026-08-29:** The "608 Tools" header and this doc's own "655 tools in generated-tools.json" note (immediately below) already contradicted each other before this pass. Current truth is DERIVED — see `Owners-Manual/PLATFORM-METRICS.md`: 655 MCP tools across all 14 MCP servers. Do not hand-edit this count.

### Tool Categories
- CRM operations (contacts, deals, leads)
- AI chat integration
- Payment processing
- Knowledge base search
- Analytics & reporting
- And many more...

### Backend MCP Tool Files: CANNOT VERIFY (2026-08-29) — not re-counted this pass; `Owners-Manual/PLATFORM-METRICS.md` tracks the tool count (655) but not a per-file breakdown

### Protocol Support
- Standard MCP
- JSON-RPC
- Simple format

---

## 12. CELERY TASK SYSTEM

> **Re-verified 2026-08-29:** "30+ Tasks" is stale. Current truth is DERIVED — see `Owners-Manual/PLATFORM-METRICS.md`: 271 Celery task functions in `tasks/`, `jobs/`, `workers/` (176 scheduled). These are background task functions, NOT AI agents — never sum the two categories. Do not hand-edit this count.

### Task Categories
- Billing tasks
- Email tasks
- KB onboarding
- Report generation
- AI enrichment
- Predictive scheduling
- Self-optimizing workflows

---

## 13. REAL-TIME FEATURES

### WebSocket Support
- Real-time updates
- Agent notifications
- Chat messaging
- Dashboard live data

### Event Bus (Redis)
- Pub/sub messaging
- Event-driven agents
- Cross-service communication

---

## SUMMARY

> **Re-verified 2026-08-29:** Every DERIVED count below (agents, MCP tools, endpoints, tables, industry templates, Celery tasks) was stale or internally contradictory as of this pass. Do not hand-edit any of them — `Owners-Manual/PLATFORM-METRICS.md` is auto-generated by `scripts/platform_metrics.py` and is the single source of truth; re-run the script and this table should point at it, not restate its numbers.

**This is what Solid# actually is:**

| Category | Count |
|----------|-------|
| **Servers** | 8 microservices — CANNOT VERIFY, not re-checked this pass |
| **Lines of Code** | See `Owners-Manual/PLATFORM-METRICS.md` (was "2,500,000+", stale — hand-typed, never script-sourced) |
| AI Features | 30+ specialized systems — CANNOT VERIFY, not re-checked this pass |
| AI Agents | See `Owners-Manual/PLATFORM-METRICS.md` (was "116 autonomous workers" — wrong; see §9 above) |
| MCP Tools | See `Owners-Manual/PLATFORM-METRICS.md` (was "608 for AI integration", stale/contradicted itself) |
| Industry Templates | See `Owners-Manual/PLATFORM-METRICS.md` (was "234 (MCC mapped)", stale — conflated with MCC mappings) |
| KB Template Mappings | See `Owners-Manual/PLATFORM-METRICS.md` — MCC Code Mappings row (was "277", stale) |
| API Endpoints | See `Owners-Manual/PLATFORM-METRICS.md` (was "1,342 routes", stale) |
| Database Tables | See `Owners-Manual/PLATFORM-METRICS.md` (was "2,040", stale — unusually large gap, origin unverified) |
| SQLAlchemy Models | CANNOT VERIFY as a tracked metric — hand-counted 2026-08-29 at 638 classes (`grep -E "^class .*Base" solid-backend/models/*.py`), not the claimed 3,170; not in PLATFORM-METRICS.md |
| React Components (TSX) | 856 — CANNOT VERIFY, not re-checked this pass |
| Payment Features | 25+ payment capabilities — CANNOT VERIFY, not re-checked this pass |
| CRM Features | 13+ marketing tools — CANNOT VERIFY, not re-checked this pass |
| Embeddable Apps | 12 calculator tools — CANNOT VERIFY, not re-checked this pass |
| LLM Providers | 7 supported — CANNOT VERIFY, not re-checked this pass |
| Video AI Providers | 5 (Sora, Veo, Runway, Pika, Kling) — CANNOT VERIFY, not re-checked this pass |
| Celery Tasks | See `Owners-Manual/PLATFORM-METRICS.md` (was "30+ background jobs", badly stale — real figure is two orders of magnitude larger) |
| Innovation Docs | 59 architecture documents — CANNOT VERIFY, not re-checked this pass |

### New Innovations (December 2025 - January 2026)

| Innovation | What It Does |
|------------|--------------|
| **AI Creative Communications** | Video/animation in business emails |
| **AI Video Studio** | Multi-model video with overlays & tokens |
| **AI Hub Architecture** | Two-layer AI (Platform + Customer Keys) |
| **Document Formatting Engine** | AI↔Human format bridge (MD↔Docs↔PDF) |
| **Sales Intelligence Research** | Company research → CRM → KB pipeline |
| **Proposal & Estimate System** | AI-powered proposals with chat & client portal |
| **Positive Anchoring** | Gamification, celebrations, joy system |
| **Dogfooding System** | Company ID 3 internal beta testing |
| **Gateway Payout API** | ACH payouts via the retired processor [platform is processor-agnostic via the adapter registry] /multipay with batch selection |

**This is not a CRM. This is an AI-powered business operating system.**


--- FILE: 10-Billing/PAYMENT-ARCHITECTURE.md ---

---
topic: billing
keywords: [payments, subscription, billing, stripe, transactions]
code_paths:
  - solid-backend/controllers/billing.py
  - solid-backend/controllers/billing_webhooks.py
  - solid-backend/services/billing_service.py
  - solid-backend/services/billing_notification_service.py
  - solid-backend/services/payments/split_engine.py
  - solid-backend/services/payments/providers.py
  - solid-backend/services/billing_service.py
  - solid-backend/controllers/billing.py
  - solid-backend/controllers/subscriptions.py
  - solid-backend/tasks/auto_billing_cron.py
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

> **UPDATED (2026-02-26):** Payment architecture now supports 13 active processors via the adapter registry. Clients connect their own processor via OAuth (Stripe, Square, PayPal, Toast, QuickBooks, Clover, Braintree) or API key (Authorize.net, Adyen, Worldpay, NMI, Shift4, Custom). See [PAYMENT-CONNECTIONS.md](./PAYMENT-CONNECTIONS.md) for connection flows and adapter registry.

# Unified Payment Architecture

> **RETIRED PROCESSOR:** The former "Solid Payments" / "Solid Pay" processor is retired — do not build against it; no single processor is core (see the Billing feedback in `CLAUDE.md`). Platform billing (Solid# → Company) runs on Stripe via Platform Commerce (swappable by design — see `solid-platform-commerce/ARCHITECTURE.md`). Tenant payments: every company connects its **own** processor through the adapter registry (`services/payments/registry.py`). Retired-processor material below is historical.

> Complete payment system architecture for Solid# platform.

**Last Updated:** January 4, 2026
**Status:** Production

---

## Quick Reference

### Key Principle

**Every company_id gets their own merchant account.** All payment operations are isolated by company_id.

### Platform Fee Structure

There is no native Solid# processor — the retired processor is dead (no single processor is core — see the Billing feedback in CLAUDE.md) and is not a selectable
option. Every processor below is BYOP (bring-your-own).

| Processor | Platform Fee | Collection |
|-----------|--------------|------------|
| Stripe | 0.05% | Weekly auto-billing |
| Square | 0.05% | Weekly auto-billing |
| PayPal | 0.05% | Weekly auto-billing |
| Toast | 0.05% | Weekly auto-billing |
| QuickBooks Payments | 0.05% | Weekly auto-billing |
| Clover | 0.05% | Weekly auto-billing |
| Braintree | 0.05% | Weekly auto-billing |
| Authorize.net | 0.05% | Weekly auto-billing |
| Adyen | 0.05% | Weekly auto-billing |
| Worldpay | 0.05% | Weekly auto-billing |
| NMI | 0.05% | Weekly auto-billing |
| Shift4 | 0.05% | Weekly auto-billing |
| Custom | 0.05% | Weekly auto-billing |

### Processor Setup

**URL:** `/dashboard/gateway/processors`

Each tenant admin chooses their payment processor here. Clients choose from available processors.

---

## Architecture Overview

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                     UNIFIED PAYMENT ARCHITECTURE                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  Company (Tenant)                                                           │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  company_id = 42                                                      │  │
│  │                                                                       │  │
│  │  ┌─────────────────────────────────────────────────────────────────┐  │  │
│  │  │  MerchantAccount                                                │  │  │
│  │  │  ├── processor: "STRIPE" (company's own connected processor)    │  │  │
│  │  │  ├── credentials: { stripe_account_id: "acct_xxx" }             │  │  │
│  │  │  ├── environment: "sandbox" | "production"                      │  │  │
│  │  │  └── is_default: true                                           │  │  │
│  │  └─────────────────────────────────────────────────────────────────┘  │  │
│  │                                                                       │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
│                              │                                              │
│                              ▼                                              │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  Payment Operations (ALL require company_id)                          │  │
│  │                                                                       │  │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐                │  │
│  │  │ Card Payment │  │ ACH/eCheck   │  │ Cash/Check   │                │  │
│  │  │              │  │              │  │              │                │  │
│  │  │ adapter      │  │ adapter      │  │ Manual Entry │                │  │
│  │  │ .charge()    │  │ .charge()    │  │ POS System   │                │  │
│  │  └──────────────┘  └──────────────┘  └──────────────┘                │  │
│  │                                                                       │  │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐                │  │
│  │  │ Text-to-Pay  │  │ QR Code Pay  │  │ Terminal/POS │                │  │
│  │  │              │  │              │  │              │                │  │
│  │  │ Payment Link │  │ Payment Link │  │ adapter      │                │  │
│  │  │ + SMS        │  │ + QR code    │  │ (stub today) │                │  │
│  │  └──────────────┘  └──────────────┘  └──────────────┘                │  │
│  │                                                                       │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
│                              │                                              │
│                              ▼                                              │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  Universal Transaction Table (Single Source of Truth)                 │  │
│  │                                                                       │  │
│  │  transaction_id | company_id | amount | method | processor | status   │  │
│  │  ─────────────────────────────────────────────────────────────────   │  │
│  │  STR-67890     | 42         | 75.00  | card   | stripe    | paid     │  │
│  │  SQR-88221     | 42         | 32.00  | card   | square    | paid     │  │
│  │  CASH-11111    | 42         | 50.00  | cash   | manual    | paid     │  │
│  │  ─────────────────────────────────────────────────────────────────   │  │
│  │                                                                       │  │
│  │  ALL queries filtered by company_id (RLS enforced)                   │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## Payment Types & Handlers

### All Payment Types Mapped

| Payment Type | Handler | Routing | Processor Options |
|--------------|---------|---------|-------------------|
| **Credit Card** | `adapter.charge()` via registry | `build_adapter()` | All 13 processors |
| **Debit Card** | `adapter.charge()` via registry | `build_adapter()` | All 13 processors |
| **ACH/eCheck** | `adapter.charge()` via registry | `build_adapter()` | Stripe, PayPal, Adyen, Worldpay |
| **Cash** | `orders.py` | Manual entry | N/A (recorded only) |
| **Check** | `orders.py` | Manual entry | N/A (recorded only) |
| **Terminal/POS** | Processor-specific | POS controller | Stripe, Square, Toast, Clover, Shift4 |
| **Text-to-Pay** | Payment link + SMS | Payment links | All processors via payment links |
| **QR Code** | `payment_link_service.py` | Payment Link + QR | All processors via payment links |
| **Saved Card** | `adapter.charge()` via token | `build_adapter()` | Stripe, Square, Braintree, Authorize.net |
| **Subscription** | Processor-specific | Subscription controller | Stripe, PayPal, Braintree, Adyen |
| **BNPL** | `bnpl.py` controller | Affirm/Klarna/Afterpay | External |

### Payment Method Enum

```python
# models/transaction.py
class PaymentMethod(str, Enum):
    CARD = "card"
    ACH = "ach"
    CASH = "cash"
    CHECK = "check"
    TERMINAL = "terminal"
    TEXT2PAY = "text2pay"
    QR_CODE = "qr_code"
    SAVED_CARD = "saved_card"
    BNPL = "bnpl"
    WIRE = "wire"
    CRYPTO = "crypto"
```

---

## Company Merchant Account Setup

### Flow: /gateway/processors

```
Tenant Admin → /dashboard/gateway/processors
          │
          ▼
┌─────────────────────────────────────────────────────────────────────┐
│  Choose Your Payment Processor                                       │
│                                                                      │
│  ┌────────────────────────────────────┐                              │
│  │  Stripe                            │                              │
│  │  • Connect your Stripe account    │                              │
│  │  • +0.05% platform fee            │  [ Connect Stripe ]          │
│  └────────────────────────────────────┘                              │
│                                                                      │
│  ┌────────────────────────────────────┐                              │
│  │  PayPal                            │                              │
│  │  • Connect your PayPal account    │                              │
│  │  • +0.05% platform fee            │  [ Connect PayPal ]          │
│  └────────────────────────────────────┘                              │
│                                                                      │
│  ┌────────────────────────────────────┐                              │
│  │  Square                            │                              │
│  │  • Connect your Square account    │                              │
│  │  • +0.05% platform fee            │  [ Connect Square ]          │
│  └────────────────────────────────────┘                              │
└─────────────────────────────────────────────────────────────────────┘
```

### Database Model

```python
# models/merchant_account.py
class MerchantAccount(Base):
    __tablename__ = "merchant_account"

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey("company.id"), nullable=False)
    processor = Column(String(50), nullable=False)  # SOLID_PAYMENTS, STRIPE, etc.
    environment = Column(String(20), default="sandbox")  # sandbox | production
    credentials = Column(JSONB, default={})  # Encrypted API keys
    is_default = Column(Boolean, default=True)
    status = Column(String(20), default="active")  # active, suspended, pending
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(DateTime(timezone=True), onupdate=func.now())

    # Relationship
    company = relationship("Company", back_populates="merchant_accounts")
```

### Credentials Structure by Processor

```python
# Stripe (OAuth)
{"stripe_account_id": "acct_xxxxx", "access_token": "sk_xxx", "refresh_token": "rt_xxx"}

# Square (OAuth)
{"access_token": "xxx", "refresh_token": "xxx", "merchant_id": "xxx", "location_id": "xxx"}

# PayPal (OAuth)
{"client_id": "xxx", "client_secret": "xxx", "merchant_id": "xxx"}

# Toast (OAuth)
{"access_token": "xxx", "restaurant_guid": "xxx", "management_group_guid": "xxx"}

# QuickBooks Payments (OAuth)
{"access_token": "xxx", "refresh_token": "xxx", "realm_id": "xxx", "token_expires_at": "..."}

# Clover (OAuth)
{"access_token": "xxx", "merchant_id": "xxx"}

# Braintree (OAuth)
{"merchant_id": "xxx", "public_key": "xxx", "private_key": "xxx", "access_token": "xxx"}

# Authorize.net (API Key)
{"api_login_id": "xxx", "transaction_key": "xxx"}

# Adyen (API Key)
{"api_key": "xxx", "merchant_account": "xxx", "client_key": "xxx", "hmac_key": "xxx"}

# Worldpay (API Key)
{"merchant_code": "xxx", "xml_password": "xxx", "mac_key": "xxx", "installation_id": "xxx"}

# NMI (API Key)
{"security_key": "xxx"}

# Shift4 (API Key)
{"secret_key": "xxx", "public_key": "xxx"}

# Solid Payments (retired processor) — DEAD, kept only as a historical record; do not use for new integrations
{"merchant_id": "processor-uuid-xxxx", "mcc_code": "5812", "enrolled_at": "2026-01-01T00:00:00Z"}
```

---

## processor Integration (historical — decommissioned, do not build against)

### Sandbox Configuration

| Setting | Value |
|---------|-------|
| API Base URL | `https://<processor-sandbox-host>/api` |
| Sandbox API Key | `REDACTED — decommissioned` |
| Production API Key | `REDACTED — decommissioned` (inactive) |

### processor Config Model

```python
# models/payment_processor_config.py
class PaymentProcessorConfig(Base):
    __tablename__ = "payment_processor_configs"

    id = Column(Integer, primary_key=True)
    environment = Column(String(20), nullable=False)  # sandbox | production
    api_key = Column(String(255), nullable=False)  # Master merchant API key
    parent_merchant_id = Column(String(255))
    is_active = Column(Boolean, default=True)
```

### All 24 processor API Endpoints (100% integrated when the retired processor was active — now dead, none of these run)

| Category | Endpoint | Service Method |
|----------|----------|----------------|
| **Enrollment** | `POST /enroll` | `enroll_merchant()` |
| **Charge** | `POST /charge` | `charge()` |
| **Authorize** | `POST /authorize` | `authorize()` |
| **Settle** | `POST /settle` | `settle()` |
| **Capture** | `POST /capture` | `capture()` |
| **Refund** | `POST /refund` | `refund()` |
| **Void** | `POST /void` | `void()` |
| **Tokenize** | `POST /card` | `tokenize_card()` |
| **Bank Account** | `POST /bankaccount` | via `charge()` |
| **Tip Adjust** | `POST /tipadjust` | `adjust_tip()` |
| **Text2Pay** | `POST /text2pay` | `send_text2pay()` |
| **Subscription** | `POST /subscription` | `create_subscription()` |
| **Get Subscription** | `GET /subscription` | `get_subscription()` |
| **MultiPay** | `POST /multipay` | `create_multipay()` |
| **Charge MultiPay** | `POST /charge-multipay` | `charge_multipay()` |
| **Refund MultiPay** | `POST /refund-multipay` | `refund_multipay()` |
| **STP** | `POST /stp` | `create_stp()` |
| **Terminal Status** | `GET /terminal` | `get_terminals()` |
| **Activate Terminal** | `POST /terminal/activate` | `activate_terminal()` |
| **Deactivate Terminal** | `POST /terminal/deactivate` | `deactivate_terminal()` |
| **Terminal Charge** | `POST /terminal` | `charge_terminal()` |
| **Report** | `GET /report` | `get_report()` |
| **Events** | `GET /events` | `get_events()` |
| **Payouts** | `GET /payouts` | `get_payouts()` |

---

## Company ID Isolation

### Critical Rule

**EVERY payment query MUST filter by company_id.**

### Isolation Points

| Layer | Isolation Method |
|-------|------------------|
| **Database** | Row-Level Security (RLS) on all payment tables |
| **API** | `company_id` extracted from JWT, added to all queries |
| **Service** | All service methods require `company_id` parameter |
| **Transactions** | `transactions.company_id` foreign key |
| **Orders** | `orders.company_id` foreign key |
| **Subscriptions** | `subscription.company_id` foreign key |

### Example: Payment Processing (illustrative — `solid_payments_service.py` is dead, zero live call sites; the company_id-isolation PATTERN below is still the rule everywhere)

```python
# services/payments/solid_payments_service.py — DEAD CODE, shown only to
# illustrate the isolation pattern. Live code uses StripePayments
# (platform billing) or services/payments/registry.py::build_adapter() (BYOP).

def charge(
    self,
    db: Session,
    company_id: int,  # REQUIRED - always
    amount: Decimal,
    payment_method: dict,
    **kwargs
) -> dict:
    # 1. Get merchant account for THIS company
    merchant = db.query(MerchantAccount).filter(
        MerchantAccount.company_id == company_id,
        MerchantAccount.is_default == True
    ).first()

    if not merchant:
        raise ValueError(f"No merchant account for company {company_id}")

    # 2. Process payment with merchant's credentials
    result = self._make_request(
        "POST",
        "/charge",
        merchant_credentials=merchant.credentials,
        data={...}
    )

    # 3. Record transaction with company_id
    transaction = Transaction(
        company_id=company_id,  # Always set
        amount=amount,
        processor_transaction_id=result["transaction_id"],
        ...
    )
    db.add(transaction)
    db.commit()

    return result
```

### Tables with company_id

| Table | Purpose |
|-------|---------|
| `merchant_account` | Per-company processor credentials |
| `transactions` | All payment transactions |
| `orders` | Orders with payments |
| `subscriptions` | Recurring billing |
| `payment_links` | Payment link records |
| `platform_fees` | External processor fees |
| `commission_ledger` | Commission tracking |

---

## Payouts & Disbursements (Outbound ACH)

> ⛔ **This entire split-settlement subsystem is dead — it requires the retired processor
> sub-merchant enrollment, and the retired processor is decommissioned.** Nothing below runs
> today. `SolidPaymentsService.charge_multipay()` exists in the file but has
> zero live call sites (verified 2026-08-29). Kept as a historical design
> record for whoever rebuilds split settlement on a live BYOP processor
> (e.g. Stripe Connect). Do not tell a rep or merchant this works.

### processor Payouts API (historical — dead)

The retired processor `/payouts` endpoint is **READ-ONLY** - it shows when deposits from card transactions hit the merchant's bank account. This is for reconciliation, NOT for sending money out.

```
GET /payouts
Returns: When deposits arrived in merchant's bank from card sales

Example:
{
    "deposit_id": "dep_123",
    "amount": 1000.00,
    "deposit_date": "2026-01-08",
    "status": "completed",
    "transactions": [...]  // Card transactions included in this deposit
}
```

### Split Settlement (charge-multipay)

The retired processor `charge-multipay` splits **settlement** to multiple sub-merchant accounts at the processor level. Funds go directly to each recipient's registered bank account.

```
POST /charge-multipay

Example: Customer pays $100, split at settlement:
{
  "amount": "100.00",
  "fee_assignment": "<MERCHANT_UUID>",  // Who pays processing fee
  "cc": "4111111111111111",
  "mm": "12",
  "yy": "25",
  "cvv": "123",
  "split_payments": [
    {
      "split_amount": "90.00",
      "split_amount_to_merchant_id": "<MERCHANT_UUID>"  // Merchant gets $90
    },
    {
      "split_amount": "10.00",
      "split_amount_to_merchant_id": "<SALES_REP_UUID>"  // Rep gets $10
    }
  ]
}

Result:
- $90 settles to Merchant's bank account (registered with the retired processor)
- $10 settles to Sales Rep's bank account (registered with the retired processor)
```

### The Requirement: Rep as Sub-Merchant

**For split settlement to work, the sales rep MUST be enrolled as a processor sub-merchant.**

```
ENROLLMENT HIERARCHY:
┌─────────────────────────────────────────────────────────────────────┐
│  SOLID# (Master Merchant)                                           │
│  └── Company A (Sub-Merchant) ← Enrolled at /gateway/processors    │
│      ├── Bank Account: Chase ****1234                               │
│      │                                                              │
│      └── Sales Rep John (Sub-Merchant) ← NEW: Rep enrollment needed │
│          └── Bank Account: Wells Fargo ****5678                     │
└─────────────────────────────────────────────────────────────────────┘
```

### Implementation Requirements

| Component | Status | Notes |
|-----------|--------|-------|
| Company enrollment | DEAD | `/gateway/processors` → processor enrollment; the retired processor is decommissioned |
| Rep enrollment | DEAD (blocked on the retired processor) | Model fields added, UI never finished, and the target processor is dead |
| Rep merchant_id storage | Schema only | `affiliate_promoter.processor_merchant_id` — column exists, nothing populates it via a live flow |
| Split payment logic | DEAD CODE | `SolidPaymentsService.charge_multipay()` — zero live call sites |
| Commission calculation | EXISTS (independent of the retired processor) | `CommissionService` calculates split amounts; the payout/settlement side is what's dead |

### Database Fields (Added Jan 2026)

```sql
-- affiliate_promoter table
processor_merchant_id VARCHAR(100)       -- processor sub-merchant UUID
processor_enrolled_at TIMESTAMP          -- Enrollment timestamp
bank_account_last4 VARCHAR(4)      -- "****1234" for display
split_settlement_enabled BOOLEAN   -- Use split vs accrued
```

### Rep Enrollment Flow (historical design, dead — target processor no longer exists)

```
Sales Rep → Enrollment Form → the retired processor /enroll → merchant_id
                                    │
                                    ▼
                          Store in promoter/affiliate table:
                          {
                            "user_id": 123,
                            "processor_merchant_id": "rep-uuid-xxx",
                            "bank_registered": true
                          }
```

### Split Payment Processing Flow

```
Order Placed ($100)
       │
       ▼
Calculate Commission (10% = $10)
       │
       ▼
Check: Does rep have processor_merchant_id?
       │
       ├── YES → Use charge-multipay
       │         split_payments: [
       │           {merchant: $90},
       │           {rep: $10}
       │         ]
       │
       └── NO → Regular charge
                Commission accrued (manual payout later)
```

### Key Fields for Split Settlement

```python
# ChargeMultipayRequest
{
    "amount": "100.00",
    "fee_assignment": "<MERCHANT_UUID>",  # Who pays the 2.9% + $0.30
    "split_payments": [
        {
            "split_amount": "90.00",
            "split_amount_to_merchant_id": "<MERCHANT_UUID>"
        },
        {
            "split_amount": "10.00",
            "split_amount_to_merchant_id": "<REP_UUID>"
        }
    ],
    # Plus payment details (cc, token, etc.)
}
```

### GAP: Outbound ACH Disbursements

**Use Cases Not Yet Implemented:**

| Use Case | Description | Status |
|----------|-------------|--------|
| Pay vendors | Send ACH to supplier bank accounts | GAP |
| Pay salespeople | Send commission earnings via ACH | GAP |
| Refund to bank | Return funds to customer bank (not card) | GAP |
| Affiliate payouts | Send affiliate commission earnings | GAP |

### Infrastructure Ready

| Component | Status | Location |
|-----------|--------|----------|
| `vendor_accounts` table | EXISTS | `migrations/versions/create_vendor_accounts.py` |
| Vendor bank details | Stored | `routing_number`, `bank_account_number` columns |
| Commission ledger | EXISTS | `models/commission.py` |
| Commission payout records | EXISTS | `CommissionPayout` model |
| Stripe Connect skeleton | EXISTS | `engine/w9_providers/stripe_connect.py` |

### Recommended Solutions

**Option 1: Contact the retired processor** — (dropped — processor retired)

**Option 2: Stripe Connect Payouts**
- Use existing `StripeConnectProvider` skeleton
- Onboard vendors as connected accounts
- Initiate payouts via Stripe API
- Already has W9/KYC handling

**Option 3: Dedicated ACH Provider**
- Dwolla, Plaid, or direct NACHA file processing
- More control but more complexity

### Commission Payout Flow (Current)

```
Order Placed → Commission Accrued → Ledger Entry → Manual Payout
                                                        │
                                                        ▼
                                              (GAP: No ACH send)
```

### Commission Payout Flow (Target)

```
Order Placed → Commission Accrued → Ledger Entry → Payout Threshold
                                                        │
                                                        ▼
                                              Auto ACH to Salesperson
                                                        │
                                                        ▼
                                              Transaction Recorded
```

### Key Files for Disbursement Implementation

| File | Purpose |
|------|---------|
| `services/commission_service.py` | Commission accrual and payout records |
| `models/commission.py` | CommissionPayout model |
| `migrations/versions/create_vendor_accounts.py` | Vendor bank details schema |
| `engine/w9_providers/stripe_connect.py` | Stripe Connect skeleton |

---

## Recurring Payments

### Subscriptions

```python
# Create subscription for a company's customer
create_subscription(
    db=db,
    company_id=company_id,  # The tenant
    customer_email="customer@example.com",
    amount=8900,  # cents
    interval="monthly",  # daily, weekly, monthly, yearly
    card_token="tok_xxx"  # Saved payment method
)
```

### Memberships

Memberships are a special order type (`order_type = "membership"`) that create recurring subscriptions.

### Auto-Pay

Customers can enable auto-pay on invoices:
1. Card saved on file (tokenized)
2. Invoice generated → Auto-charge triggered
3. Transaction recorded with `auto_pay = True`

### Tokenization

Cards are tokenized for security:

```python
# Tokenize card
token_result = tokenize_card(
    company_id=company_id,
    card_number="4111111111111111",
    exp_month="12",
    exp_year="2027",
    cvv="123",
    customer_id=customer_id  # Link to CRM contact
)
# Returns: {"token": "tok_xxx", "last4": "1111", "brand": "visa"}

# Charge saved card
charge_result = charge(
    company_id=company_id,
    amount=5000,
    payment_method={"token": "tok_xxx"}
)
```

---

## File Locations

### Frontend Pages

| Page | Path | Purpose |
|------|------|---------|
| Processor Setup | `/dashboard/gateway/processors` | Choose payment processor |
| processor Enrollment | `/dashboard/gateway/processors/solid` | Page still exists in the frontend tree but signs merchants up for a dead processor — do not link to or promote it |
| Payment Settings | `/dashboard/gateway/settings` | Manage payment config |
| Transactions | `/dashboard/gateway/transactions` | View all transactions |
| Text-to-Pay | `/dashboard/gateway/text-to-pay` | Send SMS payments |
| QR Pay | `/dashboard/gateway/qr-pay` | QR code payments |
| POS | `/dashboard/pos` | Point of sale system |

### Backend Controllers

| Controller | Path | Purpose |
|------------|------|---------|
| Payments | `controllers/payments.py` | Core payment operations |
| Orders | `controllers/orders.py` | Order management + refunds |
| Transactions | `controllers/transactions.py` | Transaction queries |
| Subscriptions | `controllers/subscriptions.py` | Recurring billing |
| Payment Links | `controllers/payment_links.py` | Payment links + QR |
| POS | `controllers/pos.py` | Terminal operations |
| BNPL | `controllers/bnpl.py` | Buy Now Pay Later |
| Merchant Enrollment | `controllers/merchant_enrollment.py` | processor sub-merchant enrollment — routes still exist in code but enroll into a dead processor; do not build against it |

### Backend Services

| Service | Path | Purpose |
|---------|------|---------|
| Solid Payments (dead) | `services/payments/solid_payments_service.py` | processor integration (1700+ lines) — zero live call sites, do not use |
| Platform Fee | `services/platform_fee_service.py` | External processor fees |
| Payment Link | `services/payment_link_service.py` | Payment links + QR codes |
| Commission | `services/commission_service.py` | Sales commissions |
| Billing | `services/billing_service.py` | Invoice + subscription billing |

### Backend Models

| Model | Path | Purpose |
|-------|------|---------|
| Transaction | `models/transaction.py` | Universal transaction record |
| MerchantAccount | `models/merchant_account.py` | Per-company processors |
| PaymentProcessorConfig | `models/payment_processor_config.py` | Global processor configuration — dead, the retired processor is decommissioned |
| PaymentLink | `models/payment_link.py` | Payment links |
| Subscription | `models/subscription.py` | Recurring billing |
| SplitPayment | `models/split_payment.py` | Multi-recipient payments |
| PlatformFee | `models/platform_fee.py` | External processor fees |

---

## Payment Flow Diagrams

### Card Payment Flow (Universal — All 13 Processors)

```
Customer → Checkout → Payment Form
                          │
                          ▼
              ┌───────────────────────┐
              │  Get Merchant Account │
              │  for company_id       │
              │  (default processor)  │
              └───────────┬───────────┘
                          │
                          ▼
              ┌───────────────────────┐
              │  build_adapter()      │
              │  from registry.py     │
              │  → StripeAdapter      │
              │  → SquareAdapter      │
              │  → ToastAdapter       │
              │  → (any of 13)        │
              └───────────┬───────────┘
                          │
                          ▼
              ┌───────────────────────┐
              │  adapter.charge()     │
              │  Same interface for   │
              │  ALL processors       │
              └───────────┬───────────┘
                          │
                          ▼
              ┌───────────────────────┐
              │  Create Transaction   │
              │  company_id = xxx     │
              └───────────┬───────────┘
                          │
                          ▼
              ┌───────────────────────┐
              │  Link to Order        │
              │  Update order.status  │
              └───────────────────────┘
```

### Terminal Payment Flow

> ⚠️ **Current reality (verified against `controllers/pos.py`, 2026-08-29):**
> `charge_terminal()` returns `{"success": False, "message": "Terminal charge
> not yet supported by <processor>"}` — it is a stub. The diagram below is the
> intended design once a real adapter implements terminal charging.

```
POS Cashier → Enter Amount
                   │
                   ▼
        ┌────────────────────┐
        │  Select Terminal   │
        │  (lane_id)         │
        └──────────┬─────────┘
                   │
                   ▼
        ┌────────────────────┐
        │  Customer Swipes   │
        │  Insert/Tap Card   │
        └──────────┬─────────┘
                   │
                   ▼
        ┌────────────────────┐
        │  adapter.charge_   │
        │  terminal()        │  ← stub today, see warning above
        └──────────┬─────────┘
                   │
                   ▼
        ┌────────────────────┐
        │  Card Data from    │
        │  Processor Response│
        │  → Customer Match  │
        └──────────┬─────────┘
                   │
                   ▼
        ┌────────────────────┐
        │  Create Order +    │
        │  Transaction       │
        └────────────────────┘
```

### Text-to-Pay Flow

```
Merchant → Create Payment Link
                   │
                   ▼
        ┌────────────────────┐
        │  Generate unique   │
        │  payment URL       │
        └──────────┬─────────┘
                   │
                   ▼
        ┌────────────────────┐
        │  payment_link_     │
        │  service Send SMS  │  (via Twilio, not PSP)
        └──────────┬─────────┘
                   │
                   ▼
        ┌────────────────────┐
        │  Customer receives │
        │  SMS with link     │
        └──────────┬─────────┘
                   │
                   ▼
        ┌────────────────────┐
        │  Customer pays     │
        │  on hosted page    │
        └──────────┬─────────┘
                   │
                   ▼
        ┌────────────────────┐
        │  Webhook triggers  │
        │  payment.succeeded │
        └────────────────────┘
```

---

## Testing Checklist

When implementing payment features:

- [ ] All queries include `company_id` filter
- [ ] MerchantAccount lookup uses `company_id`
- [ ] Transaction records include `company_id`
- (dropped — processor retired; no processor sandbox credentials)
- [ ] Platform fees calculated correctly (0.05% for the connected BYOP processor — there is no 0% native tier)
- [ ] Refunds use correct merchant credentials
- [ ] Subscriptions linked to correct company
- [ ] Payment links scoped to company
- [ ] Webhook handlers verify company_id
- [ ] Reports filtered by company_id

---

## See Also

- [Payment Suite Overview](PAYMENT-SUITE.md)
- processor Merchant Enrollment (removed — processor retired)
- [Dashboard Calculations](../07-Business-Logic/DASHBOARD-CALCULATIONS.md)
- PCI Compliance (removed — processor retired)

---

*Part of Owners Manual - Billing documentation*


--- FILE: 14-Security/SESSION-MANAGEMENT.md ---

---
topic: security
keywords: [security, authentication, authorization, compliance, SOC2, PCI, incident-response]
code_paths:
  - middleware/auth*.py
  - solid-backend/middleware/security.py
  - solid-backend/controllers/security.py
  - solid-backend/services/auth.py
  - solid-backend/middleware/auth.py
last_verified: 2026-08-29
status: current
priority: critical
owner: platform-team
---

# Session Management

> **Last Updated:** January 23, 2026
> **Status:** Production
> **Implementation:** Redis-based sessions with cross-port SSO + One-Time Codes
> **Compliance:** PCI DSS 8.1.8 (Session Timeout)
> **Security Update:** Secure one-time code pattern for auto-login (Jan 23, 2026)

---

## Overview

Solid# uses a **Redis-based session system** with cryptographically secure session IDs stored in HTTP-only cookies. This provides cross-port SSO (Single Sign-On) across all Solid# applications.

**Key Parameters:**
| Setting | Value | Location |
|---------|-------|----------|
| Session TTL | 7 days | `services/session_manager.py:70` |
| Redis Key Prefix | `session:` | `services/session_manager.py:121` |
| Cookie Name | `solid_session` | Auth middleware |
| Cookie Settings | HTTP-only, SameSite=Lax | Auth middleware |
| Sliding Expiration | Enabled | `services/session_manager.py:169` |

---

## Architecture

### The Shopify Model

Solid# implements enterprise-grade session management inspired by Shopify:

```
User logs in at ANY port (3000, 3001, 8090)
  ↓
Backend creates session in Redis
  ↓
Session ID returned as HTTP-only cookie (solid_session)
  ↓
Cookie works across ALL ports (.localhost or .solidnumber.com)
  ↓
Every request validates session with Redis
  ↓
User seamlessly navigates between all apps
```

### Session Flow Diagram

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                    REDIS SESSION MANAGEMENT FLOW                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  LOGIN (any port)                                                            │
│  ┌──────────────┐                                                           │
│  │ User logs in │                                                           │
│  └──────┬───────┘                                                           │
│         │                                                                    │
│         ▼                                                                    │
│  ┌──────────────────────────────────────────────────────────────┐          │
│  │ session_manager.create_session()                              │          │
│  │ ├── Generate UUID: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"    │          │
│  │ ├── Store in Redis: session:<uuid>                           │          │
│  │ │   └── {user_id, company_id, email, role, timestamps}       │          │
│  │ ├── TTL: 7 days (sliding expiration)                         │          │
│  │ └── Map user:<user_id>:sessions (for logout all devices)     │          │
│  └──────────────────────────────────────────────────────────────┘          │
│         │                                                                    │
│         ▼                                                                    │
│  ┌──────────────────────────────────────────────────────────────┐          │
│  │ Set HTTP-only cookie: solid_session=<uuid>                    │          │
│  │ ├── Domain: .localhost (dev) or .solidnumber.com (prod)      │          │
│  │ ├── HTTP-only: true (XSS protection)                         │          │
│  │ ├── SameSite: Lax (CSRF protection)                          │          │
│  │ └── Secure: true in production                               │          │
│  └──────────────────────────────────────────────────────────────┘          │
│         │                                                                    │
│         ▼                                                                    │
│  PROTECTED REQUEST (any port)                                               │
│  ┌──────────────────────────────────────────────────────────────┐          │
│  │ Auth Middleware reads solid_session cookie                    │          │
│  │ └─> session_manager.validate_session(session_id)             │          │
│  │     ├── Check Redis: exists "session:<uuid>"?                │          │
│  │     │   ├── YES → Return session data                        │          │
│  │     │   │   └── Update last_accessed timestamp               │          │
│  │     │   │   └── Refresh TTL (sliding expiration)             │          │
│  │     │   └── NO  → Return None (401 Unauthorized)             │          │
│  └──────────────────────────────────────────────────────────────┘          │
│         │                                                                    │
│         ▼                                                                    │
│  LOGOUT                                                                      │
│  ┌──────────────────────────────────────────────────────────────┐          │
│  │ session_manager.destroy_session(session_id)                   │          │
│  │ ├── Delete from Redis: session:<uuid>                        │          │
│  │ └── Remove from user:<user_id>:sessions                      │          │
│  └──────────────────────────────────────────────────────────────┘          │
│                                                                              │
│  LOGOUT ALL DEVICES                                                          │
│  ┌──────────────────────────────────────────────────────────────┐          │
│  │ session_manager.destroy_all_user_sessions(user_id)            │          │
│  │ ├── Get all: user:<user_id>:sessions                         │          │
│  │ ├── Delete each: session:<uuid>                              │          │
│  │ └── Clean up: user:<user_id>:sessions                        │          │
│  └──────────────────────────────────────────────────────────────┘          │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## One-Time Code Security (NEW - Jan 2026)

### The Problem

Session IDs in URLs are a security risk:
- Logged by browsers in history
- Captured by web proxies
- Leaked via Referrer headers
- Visible in server access logs

### The Solution

Instead of passing real session IDs through URLs, we use short-lived, single-use codes:

```
OLD (INSECURE):
  /auth/auto-login?session=abc-123-real-session-id  <-- LOGGED EVERYWHERE!

NEW (SECURE):
  /auth/auto-login?code=xYz_one_time_code_here      <-- Safe: expires in 5 min, single-use
```

### Implementation

**File:** `solid-backend/services/session_manager.py`

```python
class SessionManager:
    ONE_TIME_CODE_TTL = 300  # 5 minutes
    ONE_TIME_CODE_PREFIX = "otc:"

    def create_one_time_code(self, session_id: str) -> str:
        """Create a one-time code bound to a session (5-min expiry)."""
        code = secrets.token_urlsafe(32)
        key = f"{self.ONE_TIME_CODE_PREFIX}{code}"
        self.redis.setex(key, self.ONE_TIME_CODE_TTL, session_id)
        return code

    def claim_one_time_code(self, code: str) -> Optional[str]:
        """Claim code atomically (GETDEL) - returns session_id or None."""
        if not code:
            return None
        key = f"{self.ONE_TIME_CODE_PREFIX}{code}"
        session_id = self.redis.getdel(key)  # Atomic get + delete
        if session_id and self.validate_session(session_id):
            return session_id
        return None
```

### Security Properties

| Property | Implementation | Protection |
|----------|---------------|------------|
| **Single-use** | Redis GETDEL (atomic) | Code can't be reused |
| **Short-lived** | 5-minute TTL | Limits exposure window |
| **HttpOnly cookie** | Set by backend | XSS protection |
| **No session in URL** | Only one-time code | Prevents URL logging |
| **Rate limited** | 10/minute on /claim | Brute force protection |

### Usage in Auto-Login Flow

```python
# 1. During provisioning (backend webhook handler)
redis_session_id = session_manager.create_session(user_id=1, ...)
one_time_code = session_manager.create_one_time_code(redis_session_id)
# Pass one_time_code to frontend (NOT redis_session_id!)

# 2. Frontend redirects to: /auth/auto-login?code={one_time_code}

# 3. Frontend POSTs to /claim endpoint
# POST /api/v1/auth/session/claim {"code": "xYz..."}

# 4. Backend claims code and sets HttpOnly cookie
session_id = session_manager.claim_one_time_code(code)
response.set_cookie("solid_session", session_id, httponly=True, ...)
```

**Full Documentation:** `19-Onboarding/80-Sync-Provisioning-V2/01-ARCHITECTURE.md`

---

## Implementation

### Location

**File:** `solid-backend/services/session_manager.py`

### Session Manager API

#### 1. Create Session

```python
from services.session_manager import session_manager

session_id = session_manager.create_session(
    user_id=42,
    company_id=1,
    email="adam@solidnumber.com",
    role="admin",
    creator_store_id=None,  # Optional: for affiliate/creator links
    metadata={}  # Optional: additional session data
)
# Returns: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
```

**Called by:**
- `services/auth.py` on login
- `solid-platform-commerce` webhook on onboarding completion
- OAuth callback handlers

#### 2. Validate Session

```python
session_data = session_manager.validate_session(session_id)

if session_data:
    user_id = session_data["user_id"]
    company_id = session_data["company_id"]
    email = session_data["email"]
    role = session_data["role"]
    created_at = session_data["created_at"]
    last_accessed = session_data["last_accessed"]
else:
    # Session expired or invalid
    return 401 Unauthorized
```

**Called by:**
- Auth middleware on every protected request
- All API endpoints requiring authentication

#### 3. Destroy Session (Logout)

```python
# Single session (current device)
success = session_manager.destroy_session(session_id)

# All sessions (logout all devices)
count = session_manager.destroy_all_user_sessions(user_id)
# Returns: number of sessions destroyed
```

#### 4. Get User Sessions

```python
sessions = session_manager.get_user_sessions(user_id)
# Returns: [
#   {
#     "session_id": "uuid-1",
#     "user_id": 42,
#     "company_id": 1,
#     "created_at": "2026-01-21T12:00:00Z",
#     "last_accessed": "2026-01-21T15:30:00Z"
#   },
#   ...
# ]
```

#### 5. Refresh Session (Keep Alive)

```python
success = session_manager.refresh_session(session_id)
# Extends TTL by another 7 days
```

---

## Redis Data Structure

### Session Storage

```redis
# Main session data
Key: session:<uuid>
Type: String (JSON)
TTL: 7 days (604,800 seconds)
Value: {
  "user_id": 42,
  "company_id": 1,
  "email": "adam@solidnumber.com",
  "role": "admin",
  "creator_store_id": null,
  "created_at": "2026-01-21T12:00:00+00:00",
  "last_accessed": "2026-01-21T15:30:00+00:00",
  "metadata": {}
}

# User → Sessions mapping (for logout all devices)
Key: user:<user_id>:sessions
Type: Set
TTL: 7 days
Members: ["uuid-1", "uuid-2", "uuid-3"]
```

### Example Redis Commands

```bash
# Get session
redis-cli GET session:a1b2c3d4-e5f6-7890-abcd-ef1234567890

# List all sessions for user
redis-cli SMEMBERS user:42:sessions

# Check TTL
redis-cli TTL session:a1b2c3d4-e5f6-7890-abcd-ef1234567890

# Delete session
redis-cli DEL session:a1b2c3d4-e5f6-7890-abcd-ef1234567890
```

---

## Session Security

### Security Features

| Feature | Implementation | Protection |
|---------|---------------|------------|
| **Cryptographically Secure ID** | `uuid.uuid4()` | Unpredictable, 122-bit entropy |
| **HTTP-only Cookie** | `httponly=True` | XSS protection (JavaScript can't access) |
| **SameSite Cookie** | `SameSite=Lax` | CSRF protection |
| **Secure Cookie** | `secure=True` (prod) | HTTPS-only transmission |
| **Sliding Expiration** | TTL refreshed on access | Auto-expire inactive sessions |
| **Multi-tenant Isolation** | `company_id` in session | Tenant data isolation |
| **Redis Persistence** | AOF + RDB snapshots | Survives backend restart |

### Attack Vectors Mitigated

1. **Session Fixation:** New UUID generated on login
2. **Session Hijacking:** HTTP-only cookie prevents XSS theft
3. **CSRF:** SameSite=Lax cookie protection
4. **XSS:** Cookie not accessible via JavaScript
5. **Man-in-the-Middle:** Secure flag in production (HTTPS only)
6. **Brute Force:** 122-bit UUID (2^122 possible values)

---

## Onboarding Session Persistence

### The Bug (Fixed: 2026-01-21)

**Problem:** Sessions weren't persisting after onboarding completion.

**Flow:**
1. User completes payment at `/onboarding/complete?plan=Professional`
2. Platform Commerce webhook creates session
3. User clicks "Go to Dashboard" → navigates to `/dashboard/setup-wizard`
4. **BUG:** Gets 401 "Invalid credentials" error

**Root Cause:**
- Platform Commerce webhook created Redis session
- But didn't return `session_id` to frontend
- Frontend had no `solid_session` cookie
- Dashboard request failed authentication

### The Fix

**File:** `solid-platform-commerce/app/api/routers/onboarding.py:987`

```python
return CheckoutResponse(
    status="success",
    order=OrderInfo(...),
    transaction=TransactionInfo(...),
    tenant=TenantInfo(...),
    redirect_url=redirect_url,
    access_token=auto_login_session_id,  # ← ADDED: Return session ID
)
```

**File:** `solid-frontend/src/components/onboarding/steps/step5-activate.tsx:802`

```typescript
// Store session ID for auto-login
if (data.access_token) {
  // access_token is actually the Redis session_id
  document.cookie = `solid_session=${data.access_token}; path=/; max-age=${60 * 60 * 24 * 7}; SameSite=Lax`;
  console.log("[Onboarding] Stored session cookie for company", data.company_id);
}
```

**Documentation:** `Owners-Manual/19-Onboarding/11-SESSION-PERSISTENCE-FIX.md`

### Dual-Auth Cookie Conflict (Fixed: 2026-02-10)

**Problem:** When a logged-in user (e.g. Adam on Company 1) went through onboarding to create a new company, the old `solid_session` cookie persisted. After payment, `get_current_user_from_session` checked the cookie FIRST, found Company 1's session, and the new company's JWT was ignored. Result: user lands on Company 1's dashboard instead of their new company.

**Fix:** `solid-frontend/src/components/onboarding/steps/step5-activate.tsx` now clears ALL conflicting cookies before redirect:

```typescript
// Clear ALL cookies that could conflict with the new session
document.cookie = "solid_session=; path=/; max-age=0";
document.cookie = "onboarding_session_id=; path=/; max-age=0";
document.cookie = "onboarding_session_token=; path=/; max-age=0";
localStorage.removeItem("solid_refresh_token");
```

---

## Testing

### Unit Tests

**File:** `solid-backend/tests/test_session_minimal.py`

Tests session creation, validation, and persistence:

```python
def test_session_persistence_minimal():
    """Verify sessions persist from onboarding → dashboard."""

    # Step 1: Create session (simulates onboarding webhook)
    session_id = session_manager.create_session(
        user_id=user_id,
        company_id=company_id,
        email=email,
        role="owner"
    )
    assert session_id is not None

    # Step 2: Validate session (simulates dashboard access)
    session_data = session_manager.validate_session(session_id)
    assert session_data is not None
    assert session_data["user_id"] == user_id
    assert session_data["company_id"] == company_id
```

**Run tests:**
```bash
cd solid-backend
pytest tests/test_session_minimal.py -v
```

**Expected output:**
```
✅ Session created: c7835b52-c47c-40d7-bc95-a91189241aa3
✅ Session validated: user_id=2, company_id=2
✅ TEST PASSED: Session persists correctly from onboarding → dashboard
```

### Integration Tests

**File:** `solid-backend/tests/test_onboarding_session_persistence.py`

Full integration tests using FastAPI TestClient:

1. `test_session_persists_after_onboarding_completion`
   - Creates session via `session_manager`
   - Accesses `/api/v1/companies/me` with session cookie
   - Verifies correct company data returned

2. `test_no_session_cross_contamination`
   - Creates two users with different companies
   - Creates separate sessions
   - Verifies User A's session can't access User B's company

**Run tests:**
```bash
cd solid-backend
pytest tests/test_onboarding_session_persistence.py -v
```

---

## Cross-Port SSO

### How It Works

Sessions work across all Solid# applications because:

1. **Shared Cookie Domain**
   - Dev: `.localhost` (matches `localhost:3000`, `localhost:3001`, `localhost:8090`)
   - Prod: `.solidnumber.com` (matches `app.solidnumber.com`, `creator.solidnumber.com`, etc.)

2. **Shared Redis Instance**
   - All services connect to same Redis server
   - Session data available to all applications

3. **Consistent Cookie Name**
   - All services read `solid_session` cookie
   - All services use `session_manager.validate_session()`

### Applications Sharing Sessions

| Application | Port | Domain | Uses Sessions |
|-------------|------|--------|---------------|
| Main App | 3000 | app.solidnumber.com | ✅ |
| Creator Portal | 3001 | creator.solidnumber.com | ✅ |
| Backend API | 8090 | api.solidnumber.com | ✅ (validates) |
| Public Site | 3002 | solidnumber.com | ❌ (public) |
| Super Admin | 3003 | admin.solidnumber.com | ✅ |

---

## PCI DSS Compliance

### Requirement 8.1.8

**PCI DSS 8.1.8:** "If a session has been idle for more than 15 minutes, require the user to re-authenticate to re-activate the terminal or session."

### Our Implementation

**Session TTL:** 7 days with sliding expiration

**Risk-Based Deviation:**
- SaaS platform with long-form workflows (data import, campaign creation)
- No cardholder data in session or displayed in UI
- All payments via the retired processor [platform is processor-agnostic via the adapter registry] iframe (SAQ A)
- Session only contains: user_id, company_id, email, role

**Compensating Controls:**
1. **Sliding Expiration:** Sessions expire after 7 days of inactivity
2. **HTTP-only Cookies:** Can't be stolen via XSS
3. **Payment Isolation:** All card data handled by the payment processor's hosted iframe *(defunct — historical: the retired processor decommissioned)*
4. **Audit Logging:** All sensitive operations logged
5. **Logout All Devices:** Users can terminate all sessions

**Why 7 Days?**
- Balances security with UX
- Users don't lose work mid-session
- Inactive sessions still expire
- Follows Shopify/Stripe model

---

## Configuration

### Environment Variables

```bash
# Redis connection
REDIS_URL=redis://localhost:6379/0  # Local dev
REDIS_URL=redis://redis:6379/0      # Docker
REDIS_URL=redis://:password@host:6379/0  # Production

# Cookie domain (for cross-port SSO)
COOKIE_DOMAIN=.localhost            # Dev
COOKIE_DOMAIN=.solidnumber.com      # Prod

# Cookie security
COOKIE_SECURE=false                 # Dev (HTTP)
COOKIE_SECURE=true                  # Prod (HTTPS)
```

### Adjusting Session TTL

**File:** `services/session_manager.py:70`

```python
# Session TTL: 7 days
self.session_ttl = 60 * 60 * 24 * 7
```

**To change:**
1. Update `session_ttl` value
2. Update this documentation
3. Consider PCI compliance implications
4. Test session expiration

---

## Troubleshooting

### User Reports "Logged Out Randomly"

**Most likely cause (fixed Feb 10, 2026):** JWT token refresh chain was broken. See below.

**Check:**
1. Redis server running: `redis-cli ping` (should return `PONG`)
2. Session exists: `redis-cli GET session:<uuid>`
3. Cookie domain correct (should start with `.`)
4. Browser not blocking cookies
5. JWT refresh token in localStorage: `localStorage.getItem("solid_refresh_token")` — should be a valid JWT, NOT `"undefined"`

**Common causes:**
- Redis server down/restarted (no persistence)
- Cookie domain mismatch (port not included in domain)
- Browser privacy mode (blocks third-party cookies)
- Refresh token corrupted (stored as `"undefined"` string — see token refresh fix below)

### Session Not Persisting After Onboarding

**Verified Fix (2026-01-21):**
- Platform Commerce returns `access_token` (session_id)
- Frontend stores as `solid_session` cookie
- Session validated on dashboard access

**Verify:**
```bash
# Check Platform Commerce returns session_id
curl -X POST http://localhost:8091/api/v1/onboarding/checkout \
  -H "Content-Type: application/json" \
  -d '{"plan": "builder", ...}' | jq '.access_token'

# Should return: "uuid-of-session"
```

### Cross-Session Contamination

**Symptom:** User A sees User B's company data

**Test:**
```bash
cd solid-backend
pytest tests/test_onboarding_session_persistence.py::TestOnboardingSessionPersistence::test_no_session_cross_contamination -v
```

**Should pass:** Session A returns company_id_a, Session B returns company_id_b

### Debug Commands

```bash
# View session data
redis-cli GET session:a1b2c3d4-e5f6-7890-abcd-ef1234567890 | jq

# List all sessions for user
redis-cli SMEMBERS user:42:sessions

# Count total sessions
redis-cli KEYS "session:*" | wc -l

# Delete all sessions (DANGER!)
redis-cli KEYS "session:*" | xargs redis-cli DEL
```

---

## Migration from JWT to Redis

### Why We Switched

**Previous:** JWT tokens in localStorage
**Current:** Redis sessions with HTTP-only cookies

| Feature | JWT | Redis |
|---------|-----|-------|
| Cross-port SSO | ❌ No (localStorage per-port) | ✅ Yes (shared cookie) |
| Server-side logout | ❌ No (can't invalidate) | ✅ Yes (delete from Redis) |
| XSS protection | ❌ No (localStorage accessible) | ✅ Yes (HTTP-only cookie) |
| Session list | ❌ No | ✅ Yes (user → sessions mapping) |
| Scalability | ✅ Stateless | ⚠️ Requires Redis |
| Speed | ✅ Fast (no DB lookup) | ✅ Fast (Redis in-memory) |

### Migration Steps (Completed)

1. ✅ Created `services/session_manager.py`
2. ✅ Updated auth middleware to use Redis sessions
3. ✅ Updated login endpoint to create Redis session
4. ✅ Updated logout endpoint to destroy Redis session
5. ✅ Fixed onboarding session persistence
6. ✅ Created unit tests
7. ✅ Deployed to production

---

## JWT Token Refresh Chain (Updated Feb 10, 2026)

### Dual Auth System

Solid# uses TWO parallel auth mechanisms:

| Mechanism | Token | Storage | Used By | Lifetime |
|-----------|-------|---------|---------|----------|
| **Redis Session** | `solid_session` cookie | HTTP-only cookie + Redis | `get_current_user_from_session` | 7 days (sliding) |
| **JWT Access Token** | `solid_access_token` | localStorage + cookie | `get_current_user` | 1 hour |
| **JWT Refresh Token** | `solid_refresh_token` | localStorage + cookie | Token refresh endpoint | 7 days |

**`get_current_user_from_session`** checks Redis session FIRST, then falls back to JWT. This is the preferred auth middleware — all new controllers should use it.

**`get_current_user`** checks JWT Bearer token. When both session cookie and JWT are present and their `company_id` values disagree, **JWT wins** and the session is replaced with JWT claims (fixed 2026-03-25). Many older controllers still use this. When the 1-hour JWT expires and Redis session is unavailable, these endpoints return 401.

### Token Refresh Flow

```
Login
  ├── access_token (1h) → localStorage + cookie
  ├── refresh_token (7d) → localStorage + cookie
  └── solid_session (Redis, 7d) → HTTP-only cookie

Access token expires (1 hour)
  ├── apiClient gets 401 on any request
  ├── Calls authService.refreshToken()
  │   └── Sends refresh_token (7d JWT) to /api/auth/refresh
  │       └── Next.js proxy forwards to backend /api/v1/auth/refresh
  │           └── Backend decodes refresh_token (still valid, 7 days)
  │               ├── Verifies user still exists in DB
  │               ├── Issues NEW access_token (1h) + NEW refresh_token (7d)
  │               └── Returns both to client
  ├── apiClient rebuilds headers with fresh access token
  └── Retries the original request → success

SessionGuard (runs every 60s)
  ├── Detects expired access token via isJWTExpired()
  ├── Attempts refresh using refresh_token (same flow as above)
  ├── On success: updates localStorage, continues normally
  └── On failure: clears storage, redirects to /auth/v1/login?reason=expired
```

### Key Files

| File | Role |
|------|------|
| `solid-backend/services/auth.py` (line ~1489) | Backend refresh endpoint — accepts refresh_token from body |
| `solid-frontend/src/lib/auth.ts` | `authService.refreshToken()` — sends refresh_token, stores new tokens |
| `solid-frontend/src/lib/api-client.ts` | Catches 401, calls refresh, rebuilds headers, retries |
| `solid-frontend/src/components/session-guard.tsx` | Periodic check — tries refresh before clearing storage |
| `solid-frontend/src/app/api/auth/refresh/route.ts` | Next.js proxy — forwards refresh_token to backend |

### Previous Bugs (Fixed Feb 10, 2026)

The token refresh chain had 4 bugs that caused a 401 cascade when the access token expired:

1. **Backend** only read token from Authorization header (expired access token), ignored refresh_token in body
2. **SessionGuard** cleared ALL localStorage (including refresh_token) before apiClient could attempt refresh
3. **apiClient** retried with stale headers (expired token) after successful refresh
4. **Next.js proxy** only forwarded the expired access_token cookie, ignored refresh_token from body

All fixed — see `12-Issues-Found/KNOWN-ISSUES.md` for details.

---

## Related Documentation

- [JWT-AUTHENTICATION-SYSTEM.md](./JWT-AUTHENTICATION-SYSTEM.md) - Complete JWT technical reference
- [80-Sync-Provisioning-V2/01-ARCHITECTURE.md](../19-Onboarding/80-Sync-Provisioning-V2/01-ARCHITECTURE.md) - Checkout to Dashboard flow
- [11-SESSION-PERSISTENCE-FIX.md](../19-Onboarding/11-SESSION-PERSISTENCE-FIX.md) - Onboarding session fix
- [security-overview.md](./security-overview.md) - Overall security architecture
- [oauth-multi-tenant-architecture.md](OAUTH-MULTI-TENANT-ARCHITECTURE.md) - OAuth integration

---

## Changelog

### 2026-03-25 - Handoff JWT Override Fix (Incident Response)
- ✅ Handoff endpoint no longer uses `get_current_user` — decodes JWT directly inside function body
- ✅ JWT `company_id` always wins over stale session cookie during handoff
- ✅ `get_current_user` updated: cross-checks session vs JWT on mismatch, JWT wins
- ✅ 10 new tests in `tests/test_handoff_tenant_isolation.py` (16 assertions total)
- ✅ Fixes tenant data leak where stale `solid_session` cookie caused integrations to save to wrong company
- ✅ See: `14-Security/INCIDENT-2026-03-25-TENANT-LEAK.md`

### 2026-02-28 - Session Handoff Auth Fix
- ✅ `POST /api/v1/session/handoff` now requires JWT Bearer authentication
- ✅ Session created from JWT claims only — request body no longer trusted
- ✅ Prevents unauthenticated session creation for arbitrary users
- ✅ `HandoffRequest` body parameter removed; `current_user: User = Depends(get_current_user)` added
- ✅ Related: JWT secret unified across `mcp_auth.py`, `activity_timeout.py`, `mcp_tenant_scope.py` — all now read `JWT_SECRET` first with `JWT_SECRET_KEY` fallback

### 2026-02-10 - Token Refresh Chain Fix
- ✅ Backend refresh endpoint now accepts refresh_token from request body
- ✅ Backend verifies user still exists in DB before issuing new tokens
- ✅ Backend returns both new access_token and new refresh_token
- ✅ SessionGuard tries token refresh before clearing localStorage
- ✅ apiClient rebuilds headers with fresh token after successful refresh
- ✅ Next.js proxy forwards refresh_token from request body to backend
- ✅ Documented dual auth system (Redis sessions + JWT tokens)

### 2026-01-23 - Secure One-Time Code System
- ✅ Added `create_one_time_code()` to SessionManager (5-min TTL)
- ✅ Added `claim_one_time_code()` with atomic Redis GETDEL
- ✅ Added `POST /api/v1/auth/session/claim` endpoint with rate limiting
- ✅ Backend now sets HttpOnly cookie (instead of JavaScript)
- ✅ Auto-login uses `?code=` parameter instead of `?session=`
- ✅ JWT now includes both `sub` and `user_id` fields
- ✅ Added environment-driven cookie settings (COOKIE_DOMAIN, COOKIE_SECURE)
- ✅ Created JWT-AUTHENTICATION-SYSTEM.md documentation

### 2026-01-21 - Major Update
- ✅ Switched from JWT to Redis-based sessions
- ✅ Implemented cross-port SSO
- ✅ Fixed onboarding session persistence bug
- ✅ Created comprehensive unit tests
- ✅ Updated documentation to match implementation

### 2026-01-04 - JWT Implementation
- Previous implementation (deprecated)
- JWT tokens with auto-refresh
- Activity timeout middleware

---

**Last Updated:** March 25, 2026
**Next Review Due:** April 21, 2026
**Owner:** Platform Team
**Contact:** security@solidnumber.com


--- FILE: 19-Onboarding/27-E2E-ONBOARDING-WALKTHROUGH.md ---

---
topic: onboarding-e2e-walkthrough
keywords: [onboarding, end-to-end, walkthrough, provisioning, checkout, stripe, kb, food-agents, complete-flow]
last_verified: 2026-08-29
status: current
priority: critical
owner: platform-team
---

# End-to-End Onboarding Walkthrough

> **This is the single document that covers the entire onboarding pipeline.**
> From the user's first click on `enroll.solidnumber.com` to a fully provisioned
> company with 24 AI agents, 150+ KB entries, billing records, and a live dashboard.
>
> Every step. Every field. Every config. Every API call. Every database write.

---

## Table of Contents

1. [Architecture Overview](#1-architecture-overview)
2. [Step 0: User Arrives](#2-step-0-user-arrives)
3. [Step 1: Signup](#3-step-1-signup)
4. [Step 2: Industry Selection](#4-step-2-industry-selection)
5. [Step 3: ROI Calculator](#5-step-3-roi-calculator)
6. [Step 4: Plan Selection](#6-step-4-plan-selection)
7. [Step 5: Company Details](#7-step-5-company-details)
8. [Step 6: Checkout & Payment](#8-step-6-checkout--payment)
9. [Step 7: Synchronous Provisioning](#9-step-7-synchronous-provisioning)
10. [Step 8: Async Enrichment (Phase 2)](#10-step-8-async-enrichment-phase-2)
11. [Step 9: KB Food Team Orchestration](#11-step-9-kb-food-team-orchestration)
12. [Step 10: Dashboard Ready](#12-step-10-dashboard-ready)
13. [Database Tables Created](#13-database-tables-created)
14. [Feature Settings JSON](#14-feature-settings-json)
15. [Three-Layer Feature Gating](#15-three-layer-feature-gating)
16. [Session & Token Management](#16-session--token-management)
17. [Environment Configuration](#17-environment-configuration)
18. [Error Handling & Edge Cases](#18-error-handling--edge-cases)
19. [Verification Queries](#19-verification-queries)
20. [Key Files Reference](#20-key-files-reference)
21. [Timeline Summary](#21-timeline-summary)

---

## 1. Architecture Overview

Three services collaborate to onboard a customer:

```
┌────────────────────────────────────────────────────────────────────────────┐
│                         ONBOARDING ARCHITECTURE                           │
│                                                                           │
│  FRONTEND (solid-frontend)              Port 3000 / app.solidnumber.com   │
│  ├── Onboarding wizard UI (8 steps)                                       │
│  ├── Next.js API proxy routes → Platform Commerce                         │
│  ├── Middleware: enroll.* subdomain routing                                │
│  └── Auto-login after provisioning                                        │
│           │                                                               │
│           ▼                                                               │
│  PLATFORM COMMERCE (solid-platform-commerce)   Port 8091                  │
│  ├── Own database: solid_platform_commerce (port 5433)                    │
│  ├── Session management (onboarding_sessions table)                       │
│  ├── Steps 1-6 API endpoints                                              │
│  ├── Stripe payment processing (Customer + PM + PaymentIntent + Sub)      │
│  ├── Payment-received notification to backend (before provisioning)       │
│  └── Webhook dispatch to Main Backend                                     │
│           │                                                               │
│           │  POST /api/v1/provisioning/create-tenant (sync)               │
│           ▼                                                               │
│  MAIN BACKEND (solid-backend)                  Port 8090                  │
│  ├── Main database: solid_dev / solid_prod (port 5432)                    │
│  ├── Phase 1: Company + User + Billing (sync, 3-5s)                       │
│  ├── Phase 2: KB + Agents + Sites (async, 10-30s)                         │
│  └── KB Food Team: 24 agents across 6 phases                              │
│           │                                                               │
│           ▼                                                               │
│  STRIPE (api.stripe.com)                          Primary processor       │
│  └── Customer, PaymentMethod, PaymentIntent, Subscription                 │
│                                                                           │
│  PSP SANDBOX (<processor-sandbox-host>)          DECOMMISSIONED          │
│  └── Card charging, subscription creation, recharge tokens (DEFUNCT)      │
│                                                                           │
└────────────────────────────────────────────────────────────────────────────┘
```

**Why three services?** Platform Commerce is a separate microservice with its own database because during signup, no `company_id` exists yet. Keeping signup data isolated prevents multi-tenant contamination. The main backend only gets involved after payment succeeds.

**Key URLs:**

| Environment | Frontend | Platform Commerce | Backend API |
|------------|----------|------------------|-------------|
| Local | `http://localhost:3000` | `http://localhost:8091` | `http://localhost:8090` |
| Production | `https://app.solidnumber.com` | `https://onboarding.solidnumber.com` | `https://api.solidnumber.com` |
| Docker internal | `http://solid-frontend:3000` | `http://solid-platform-commerce:8091` | `http://solid-backend:8090` |

---

## 2. Step 0: User Arrives

### URL & Subdomain Routing

User navigates to `enroll.solidnumber.com` (production) or `enroll.localhost:3000` (local).

**File:** `solid-frontend/src/middleware.ts`

The Next.js middleware detects the `enroll.*` subdomain and applies special routing:

```
enroll.* subdomain rules:
├── /onboarding       → ALLOW (wizard page)
├── /auth/*           → ALLOW (post-checkout login)
├── /dashboard/*      → ALLOW (post-checkout redirect to setup wizard)
├── /                 → REDIRECT to /onboarding
└── anything else     → REDIRECT to /onboarding
```

**Security applied:** CSRF protection, rate limiting, security headers (X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, CSP nonce).

**Rate limits on onboarding endpoints:**
- `/api/onboarding/start`: 5 per 5 minutes
- `/api/onboarding/registration`: 3 per 5 minutes
- `/api/onboarding/checkout`: 5 per minute

### Frontend Wizard Component

**File:** `solid-frontend/src/components/onboarding/onboarding-wizard.tsx`

The wizard manages 8 steps (hardware step is HIDDEN — commented out in `page.tsx`). On mount:
1. Checks localStorage for existing `onboarding_session_token`
2. Calls `isTokenExpired()` to validate JWT expiry (24h, with 60s buffer)
3. If expired: clears localStorage, resets to step 0
4. If valid: resumes at last `current_step`

---

## 3. Step 1: Signup

### Two Paths

#### Path A: Email/Password

**Frontend:** `step1-signup.tsx`
**API:** `POST /api/onboarding/start` (proxied through Next.js to Platform Commerce)
**No auth required**

**Request:**
```json
{
  "email": "user@example.com",
  "password": "SecurePass123!",
  "full_name": "John Smith",
  "terms_accepted": true
}
```

**Validation:**
- Email: valid format, uniqueness check against existing sessions AND main backend users
- Password: minimum 8 characters
- `terms_accepted`: must be `true`
- `full_name`: required, non-empty

**Platform Commerce processing:**
1. Hash password with bcrypt
2. Create `onboarding_sessions` row:
   - `id`: UUID (auto-generated)
   - `email`: user's email
   - `full_name`: user's name
   - `password_hash`: bcrypt hash
   - `status`: `pending`
   - `current_step`: `1`
   - `terms_accepted_at`: current timestamp
3. Generate JWT session token (24h expiry, contains `session_id`)

**Response:**
```json
{
  "session_token": "eyJhbGciOiJIUzI1NiIs...",
  "session_id": "d4eb8761-3a2f-4c89-9e1a-...",
  "next_step": 2
}
```

**Frontend stores:** `onboarding_session_token` in localStorage.

#### Path B: OAuth (Google/Microsoft)

**Flow:** User clicks "Continue with Google" → NextAuth → Google OAuth → Backend `oauth_register` → Platform Commerce session created with OAuth fields instead of password.

**Key difference:** No `password_hash`. Instead, session stores:
- `oauth_provider`: "google" or "microsoft"
- `oauth_id`: provider user ID
- `oauth_access_token`: encrypted
- `oauth_refresh_token`: encrypted
- `oauth_token_expires_at`: timestamp

**After OAuth:** User returns to `/onboarding?step=2` and continues the same flow.

**No account is created during OAuth.** Account creation happens at checkout (Step 6), same as email/password path.

---

## 4. Step 2: Industry Selection

**API:** `POST /api/onboarding/industry` (Bearer token required)
**File:** `solid-platform-commerce/app/api/routers/onboarding.py`

**Request:**
```json
{
  "kb_sub_code": 500,
  "industry_key": "plumber",
  "industry_name": "Plumbing",
  "mcc_code": "1711"
}
```

**Fields explained:**
- `kb_sub_code`: Integer 100-9999. Maps to one of 52 industry templates. Determines KB content, features enabled, and industry module. See `solid-backend/constants/kb_template_mapping.py`.
- `industry_key`: Machine-readable key (e.g., "plumber", "mortgage_broker", "dentist")
- `industry_name`: Human-readable display name
- `mcc_code`: Merchant Category Code (for payment processing categorization)

**Industry ranges (kb_sub_code):**
| Range | Industry Group | Example Codes |
|-------|---------------|---------------|
| 100-199 | Charitable & Nonprofit | 101=nonprofit |
| 200-299 | Advertising & Marketing | 201=marketing_agency |
| 300-399 | Automotive | 301=auto_repair, 306=dealer_network |
| 400-499 | Computer & IT | 401=it_services, 402=software_dev |
| 500-599 | Construction & Trades | 504=construction, 508=hvac, 512=plumber |
| 600-699 | Digital & Ecommerce | 602=author, 605=ecommerce |
| 700-799 | Education | 704=education_services |
| 800-899 | Fintech & SaaS | 801=fintech, 802=saas_platform |
| 900-999 | Food & Beverage | 901=bar, 905=restaurant |
| 1000-1099 | Health & Beauty | 1001=beauty/salon, 1003=esthetician |
| 1100-1199 | Home Services | 1101=home_services |
| 1200-1299 | Hospitality & Fitness | 1200=gym, 1203=hotel |
| 1300-1399 | Marine & Boats | 1301=marine_services |
| 1400-1499 | Medical & Healthcare | 1402=chiropractor, 1404=doctor, 1406=dentist |
| 1500-1599 | Logistics & Travel | 1501=logistics, 1505=travel_agency |
| 1600-1699 | Motor & Transportation | 1603=car_wash, 1611=towing |
| 1700-1799 | Pet & Veterinary | 1702=veterinary |
| 1900-1999 | Professional Services | 1901=law_firm, 1906=accounting, 1915=real_estate |
| 2000-2099 | Retail | 2011=retail_store, 2022=interior_designer |

Full mapping: `solid-backend/constants/kb_template_mapping.py` (277 entries)

**Platform Commerce processing:**
1. Validate `kb_sub_code` is a positive integer (any value accepted — backend is sole authority, see below)
2. Look up industry benchmarks (avg_ticket, monthly_jobs, close_rate, retention_rate)
3. Update session: `kb_sub_code`, `industry_key`, `industry_name`, `mcc_code`, `current_step=2`

**kb_sub_code validation (CRITICAL — fixed 2026-02-12):**
Platform Commerce accepts **any positive integer** for `kb_sub_code`. The backend's `kb_template_mapping.py` (277 mappings) is the sole authority for resolving codes to KB templates. Previously, Platform Commerce rejected codes not in its own 45-industry dict, causing new tenants to get 0 KB entries. See [29-KB-PIPELINE-FIX.md](./29-KB-PIPELINE-FIX.md) for the full postmortem.

**Response:**
```json
{
  "status": "success",
  "next_step": 3,
  "benchmarks": {
    "avg_ticket": 350,
    "monthly_jobs": 45,
    "close_rate": 0.68,
    "retention_rate": 0.82
  }
}
```

---

## 5. Step 3: ROI Calculator

**API:** `POST /api/onboarding/roi` (Bearer token required)

**Request:**
```json
{
  "monthly_revenue": 25000,
  "software_spend": 500,
  "admin_hours": 20
}
```

**Calculation logic:**
```
revenue_growth = monthly_revenue × 0.05          (5% growth)
software_savings = software_spend × 1.0          ($1:$1 replacement)
time_savings = admin_hours × 50 × 2.0            ($50/hr × 2x multiplier)
total_monthly_savings = revenue_growth + software_savings + time_savings
roi_multiple = total_monthly_savings / plan_price  (vs $499 Professional)
```

**Example:** $25K revenue, $500 software, 20 admin hours:
- Revenue growth: $1,250
- Software savings: $500
- Time savings: $2,000
- Total: $3,750/month → 7.5x ROI vs $499/month

**Platform Commerce processing:**
1. Calculate ROI metrics
2. Update session: `monthly_revenue`, `software_spend`, `admin_hours`, `roi_multiple`, `current_step=3`

**Response:**
```json
{
  "status": "success",
  "next_step": 4,
  "roi": {
    "monthly_savings": 3750,
    "annual_savings": 45000,
    "roi_multiple": 7.5
  }
}
```

---

## 6. Step 4: Plan Selection

**API:** `POST /api/onboarding/plan` (Bearer token required)

**Request:**
```json
{
  "tier": "professional",
  "billing_cycle": "monthly"
}
```

**Valid tiers:** `starter`, `builder`, `professional`, `enterprise`

**Pricing (January 2026):**

| Tier | Monthly | Annual (per month) | AI Tokens |
|------|---------|-------------------|-----------|
| Starter | $89 | $75 | 75,000 |
| Builder | $199 | $169 | 225,000 |
| Professional | $499 | $424 | 600,000 |
| Enterprise | $1,499 | $1,274 | 1,200,000 |

**Feature access by tier:**

| Feature | Starter | Builder | Professional | Enterprise |
|---------|---------|---------|-------------|-----------|
| AI Chat | Yes | Yes | Yes | Yes |
| Payments | Yes | Yes | Yes | Yes |
| Appointments | No | Yes | Yes | Yes |
| CRM | No | No | Yes | Yes |
| Industry Modules | No | No | Yes | Yes |
| Custom Agents | No | No | No | Yes |

**Platform Commerce processing:**
1. Look up tier from `subscription_tiers` table
2. Calculate `price_cents` based on tier + billing_cycle
3. Update session: `tier`, `billing_cycle`, `price_cents`, `current_step=4`

**Response:**
```json
{
  "status": "success",
  "next_step": 5,
  "tier": "professional",
  "price_cents": 49900,
  "billing_cycle": "monthly"
}
```

---

## 7. Step 5: Company Details

**API:** `POST /api/onboarding/company-details` (Bearer token required)

**Request:**
```json
{
  "company_name": "Joe's Plumbing",
  "phone": "+15551234567",
  "support_email": "support@joesplumbing.com",
  "support_phone": "+15551234567"
}
```

**Validation:**
- `phone`: Must be E.164 format (+1XXXXXXXXXX)
- `company_name`: Optional — defaults to `full_name` for sole proprietors
- `support_email`: Valid email
- `support_phone`: E.164 format

**Platform Commerce processing:**
1. Validate phone format
2. Update session: `company_name`, `phone`, `support_email`, `support_phone`, `current_step=5`

**Response:**
```json
{
  "status": "success",
  "next_step": 6,
  "tenant_company_id": null
}
```

Note: `tenant_company_id` is null because the company doesn't exist yet. It gets created during checkout.

---

## 8. Step 6: Checkout & Payment

This is the most complex step. It creates a Stripe customer, attaches a payment method, charges via PaymentIntent, creates a subscription, provisions the tenant, and returns an access token — all synchronously in 3-9 seconds.

**API:** `POST /api/onboarding/checkout` (Bearer token required)
**Timeout:** 60 seconds
**File:** `solid-platform-commerce/app/services/checkout_service.py`

### 8.1 Frontend Request

**File:** `solid-frontend/src/components/onboarding/steps/step5-activate.tsx`

The frontend uses **Stripe Elements** to collect card data. Card numbers never touch our server (PCI compliant).

```
Browser: stripe.createPaymentMethod({type: 'card', card: cardElement}) → pm_xxx
```

```json
{
  "phone": "+15551234567",
  "business_name": "Joe's Plumbing",
  "stripe_payment_method_id": "pm_1ABC2DEF3GHI...",
  "card_last4": "4242",
  "card_brand": "visa",
  "card_exp_month": "12",
  "card_exp_year": "28",
  "billing_address": {
    "line1": "123 Main Street",
    "city": "Denver",
    "state": "CO",
    "postal": "80202",
    "country": "US"
  },
  "hardware_option": null,
  "promo_code": null
}
```

**Payment flow:** Stripe Elements renders a secure card input iframe. On submit, the frontend calls `stripe.createPaymentMethod()` which returns a `pm_xxx` token. Card data NEVER touches our server — it goes directly from the browser to Stripe. The `pm_xxx` is sent to Platform Commerce along with card metadata (last4, brand, exp) extracted from the Stripe response.

**Duplicate prevention:** Frontend sets `localStorage.checkoutInProgress = true` before calling. Blocked if already true. Cleared on success or error.

### 8.2 Frontend Proxy

**File:** `solid-frontend/src/app/api/onboarding/checkout/route.ts`

Maps frontend field names to Platform Commerce field names:
- `billing_address.address` → `billing_address.line1`
- `billing_address.zip` → `billing_address.postal`

Forwards: `stripe_payment_method_id`, `card_last4`, `card_brand`, `card_exp_month`, `card_exp_year`

Forwards to: `${PLATFORM_COMMERCE_URL}/api/v1/onboarding/checkout`

### 8.3 Stripe Payment Flow

**File:** `solid-platform-commerce/app/services/payment_service.py`

Platform Commerce orchestrates the Stripe payment in 4 steps:

#### Step 1: Create Stripe Customer
```
stripe.Customer.create(email="user@example.com", name="John Smith")
→ cus_ABC123...
```

#### Step 2: Attach PaymentMethod to Customer
```
stripe.PaymentMethod.attach(pm_xxx, customer=cus_ABC123)
stripe.Customer.modify(cus_ABC123, invoice_settings={"default_payment_method": pm_xxx})
```

#### Step 3: Create PaymentIntent (Month 1 charge)
```
stripe.PaymentIntent.create(
    amount=49900,
    currency="usd",
    customer=cus_ABC123,
    payment_method=pm_xxx,
    confirm=True,
    off_session=True
)
→ pi_XYZ789... (status: "succeeded")
```

#### Step 4: Create Subscription (Month 2+)
```
stripe.Subscription.create(
    customer=cus_ABC123,
    items=[{"price": price_id}],
    default_payment_method=pm_xxx,
    billing_cycle_anchor=now + 30_days
)
→ sub_DEF456...
```

**Key:** Month 1 is charged immediately via PaymentIntent. Month 2+ is auto-charged by Stripe via the Subscription.

**Card data NEVER touches our server.** The frontend uses Stripe Elements which submits card data directly to Stripe, returning only a `pm_xxx` token.

**Test cards (Stripe test mode):**
- `tok_visa` → Success (4242)
- `tok_mastercard` → Success (5555)
- `tok_chargeDeclined` → Decline

### 8.4 Payment-Received Notification

**Before provisioning starts**, Platform Commerce sends a payment-received notification to the backend. This ensures the admin always knows someone paid, even if provisioning subsequently fails.

```
POST http://solid-backend:8090/api/v1/webhooks/payment-received
```

This is a fire-and-forget call — it does not block checkout.

### 8.5 Platform Commerce Records

After Stripe succeeds, Platform Commerce creates:

1. **PlatformOrder** — order record with `order_number` (e.g., `ORD-2026-84902`)
2. **PlatformTransaction** — payment record linked to order, includes `stripe_customer_id`, `stripe_payment_method_id`, `stripe_subscription_id`, card metadata from Stripe response

Updates session: `status=completed`, `stripe_customer_id`, `stripe_subscription_id`, `stripe_payment_method_id`, `card_last4`, `card_brand`

### 8.6 Synchronous Provisioning Call

Platform Commerce calls the Main Backend **synchronously** (blocks the checkout response):

```
POST http://solid-backend:8090/api/v1/provisioning/create-tenant
```

**39 fields sent in the payload:**

**Group A — User Details (5):**
- `email`: "user@example.com"
- `full_name`: "John Smith"
- `phone`: "+15551234567"
- `support_email`: "support@joesplumbing.com"
- `support_phone`: "+15551234567"

**Group B — Password (1, conditional):**
- `password_hash`: bcrypt hash (omitted for OAuth users)

**Group C — Company & Subscription (4):**
- `company_name`: "Joe's Plumbing"
- `tier`: "professional"
- `billing_cycle`: "monthly"
- `price_cents`: 49900

**Group D — Industry (4, with defaults):**
- `industry_key`: "plumber" (default: "professional_services")
- `industry_name`: "Plumbing" (default: "Professional Services")
- `mcc_code`: "1711"
- `kb_sub_code`: 500

**Group E — Stripe/Payment (7, paid tiers only):**
- `stripe_customer_id`: "cus_ABC123..."
- `stripe_subscription_id`: "sub_DEF456..."
- `stripe_payment_method_id`: "pm_1ABC2DEF3GHI..."
- `card_last4`: "4242"
- `card_brand`: "visa"
- `card_exp_month`: "12"
- `card_exp_year`: "28"

**Group F — Order/Transaction References (5):**
- `order_id`: UUID
- `order_number`: "ORD-2026-84902"
- `transaction_id`: UUID
- `processor_transaction_id`: "2ca6b6ab-..."
- `onboarding_session_id`: UUID

**Group G — ROI Data (3, may be null):**
- `monthly_revenue`: 25000
- `software_spend`: 500
- `admin_hours`: 20

**Group H — Legal (1):**
- `terms_accepted_at`: "2026-02-11T15:30:00Z"

**Group I — Communication Plan (5, conditional):**
- `phone_number_type`: "shared"
- `voice_plan`: "none"
- `sms_plan`: "none"
- `communication_setup_cents`: 0
- `communication_monthly_cents`: 0

**Group J — OAuth (5, conditional):**
- `oauth_provider`: null (or "google"/"microsoft")
- `oauth_id`: null
- `oauth_access_token`: null
- `oauth_refresh_token`: null
- `oauth_token_expires_at`: null

**Idempotency:** The Platform Commerce session UUID is sent as `Idempotency-Key` header. Backend tracks this in `provisioning_requests` table. Retries return identical results.

### 8.7 Checkout Response

After provisioning succeeds, checkout returns:

```json
{
  "status": "success",
  "session_id": "d4eb8761-...",
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "tenant": {
    "company_id": 141,
    "user_id": 287,
    "email": "user@example.com"
  },
  "redirect_url": "/dashboard/setup-wizard"
}
```

**Frontend on success:**
1. Stores `access_token` in both localStorage AND sessionStorage
2. Sets `solid_just_signed_up = true` flag
3. Redirects to `/dashboard/setup-wizard`

---

## 9. Step 7: Synchronous Provisioning

This section details what happens inside the Main Backend when it receives the `create-tenant` call.

**File:** `solid-backend/services/tenant_provisioning.py`
**Also:** `solid-backend/controllers/provisioning.py` (endpoint), `solid-backend/schemas/provisioning.py` (validation)

### Phase 1: Synchronous (blocks checkout, ~3-5 seconds)

Everything in Phase 1 runs in a single database transaction. If anything fails, the entire transaction rolls back.

#### 9.1 Create Company

```python
company = Company(
    name=company_name,            # "Joe's Plumbing"
    tier=tier,                    # "professional"
    kb_sub_code=kb_sub_code,      # 500
    industry_key=industry_key,    # "plumber"
    industry_name=industry_name,  # "Plumbing"
    mcc_code=mcc_code,           # "1711"
    stripe_subscription_id=stripe_subscription_id,  # "sub_DEF456..."
    feature_settings={...},       # See Section 14
    status="active"
)
```

**Result:** `company.id` assigned (e.g., 141). This is the `company_id` used everywhere.

#### 9.2 Create User

```python
user = User(
    email=email,                  # "user@example.com"
    full_name=full_name,          # "John Smith"
    phone=phone,                  # "+15551234567"
    password_hash=password_hash,  # bcrypt hash (or None for OAuth)
    company_id=company.id,        # 141
    role="admin",
    is_active=True,
    oauth_provider=oauth_provider,     # None or "google"
    oauth_id=oauth_id,                 # None or provider user ID
)
```

#### 9.3 Create CompanyMember

Links user to company with admin role.

#### 9.4 Create Subscription

```python
subscription = CompanySubscription(
    company_id=company.id,
    tier=tier,
    billing_cycle=billing_cycle,
    current_period_start=now,
    current_period_end=now + 30_days,
    status="active"
)
```

#### 9.5 Create SubdomainMapping

Auto-generates a URL slug from company name:
```python
slug = slugify(company_name)  # "joes-plumbing"
# Check uniqueness, append number if needed: "joes-plumbing-2"
```

#### 9.6 Create Billing Records (Paid Tiers Only)

**BillingCustomer:**
```python
billing_customer = BillingCustomer(
    tenant_id=company.id,         # 141 — THIS IS THE ISOLATION KEY
    email=email,
    name=full_name,
    status="active"
)
```

**BillingPaymentMethod:**
```python
payment_method = BillingPaymentMethod(
    billing_customer_id=billing_customer.id,
    provider="stripe",
    provider_payment_method_id=stripe_payment_method_id,  # "pm_1ABC2DEF3GHI..."
    card_last4=card_last4,          # "4242"
    card_brand=card_brand,          # "visa"
    card_exp_month=card_exp_month,  # "12"
    card_exp_year=card_exp_year,    # "28"
    is_default=True,
    status="active"
)
```

**SECURITY CRITICAL:** Every query to `BillingPaymentMethod` MUST filter by `company_id` (via BillingCustomer.tenant_id). Without this, one tenant could access another's payment method.

**BillingSubscription:**
```python
billing_sub = BillingSubscription(
    company_id=company.id,
    billing_customer_id=billing_customer.id,
    tier=tier,
    amount_cents=price_cents,
    billing_cycle=billing_cycle,
    current_period_start=now,
    current_period_end=now + 30_days,
    status="active"
)
```

**BillingInvoice + BillingInvoiceLineItem:**
```python
invoice = BillingInvoice(
    company_id=company.id,
    billing_subscription_id=billing_sub.id,
    amount_cents=price_cents,
    status="paid",               # First invoice is already paid (charged at checkout)
    paid_at=now
)

line_item = BillingInvoiceLineItem(
    billing_invoice_id=invoice.id,
    description=f"{tier.title()} Plan - Monthly",
    amount_cents=price_cents,
    period_start=now,
    period_end=now + 30_days
)
```

#### 9.7 Populate feature_settings

See [Section 14](#14-feature-settings-json) for the full JSON structure.

#### 9.8 Generate JWT

```python
access_token = jwt.encode({
    "sub": str(user.id),
    "company_id": company.id,
    "email": user.email,
    "role": "admin",
    "exp": now + 1_hour
}, SECRET_KEY, algorithm="HS256")
```

#### 9.9 Phase 1 Response

```json
{
  "success": true,
  "company_id": 141,
  "user_id": 287,
  "access_token": "eyJ...",
  "message": "Tenant created successfully"
}
```

This response flows back to Platform Commerce → Frontend. User can now log in.

---

## 10. Step 8: Async Enrichment (Phase 2)

Phase 2 runs **after** Phase 1 commits, in a background Celery task. The user is already in the dashboard.

**File:** `solid-backend/tasks/provision_tenant_async.py`

### What Gets Created

| Component | Count | Details |
|-----------|-------|---------|
| AI Agents | 11 | Sarah (CS), Jake (Sales), Devon (Ops), Marcus (Growth), Alex (Finance), Jordan (Marketing), Maya (Design), Riley (Data), Taylor (HR), Morgan (Legal), ADA (Coordinator) |
| Sites | 4 | Default website configurations |
| KB Entries | ~92 | Cloned from industry template (Company 2 code, NOT database) |
| AI Budget | 1 | Token limits based on tier (e.g., 600K for Professional) |
| GPT Contexts | 3 | Personality, Identity, Knowledge contexts |
| CRM Records | 2 | Contact + Order in Company 3's CRM (Solid#'s own records) |

### Phase 2.5: Auto-Wire Defaults

**Function:** `auto_wire_defaults()` in `tenant_provisioning.py`

After KB template cloning, auto-wiring creates operational defaults:
- **Email addresses:** `hello-{slug}@solidhello.com` (inbound), `noreply-{slug}@solidhello.com` (outbound)
- **Chat widget domains:** Configured for the company's subdomain
- **Business hours:** Default 9-5 M-F schedule
- **Booking URL:** Auto-generated from slug
- **Communication settings:** Default notification preferences

### KB Template Cloning

KB content comes from **code files**, NOT from Company 2's database:
- `solid-backend/config/gpt_context_defaults.py` — Default GPT contexts
- `solid-backend/config/personalities.py` — Personality options
- `solid-backend/scripts/templates/industries/*.py` — 52 industry templates
- `solid-backend/services/kb_template_service.py` — Cloning logic

The `kb_sub_code` from Step 2 determines which template to clone.

### Onboarding Validator

**File:** `solid-backend/workers/onboarding_validator.py`

Runs 30 seconds after Phase 1. Validates:
1. BillingCustomer exists for company_id
2. BillingPaymentMethod exists with `provider_payment_method_id` (pm_xxx)
3. BillingSubscription exists and is active
4. BillingInvoice exists and is paid
5. Invoice → Subscription FK is linked
6. No duplicate charges (idempotency check)
7. `company_id` isolation verified across all billing records

If validation fails, alerts are sent to the superadmin dashboard.

---

## 11. Step 9: KB Food Team Orchestration

After Phase 2 template cloning, the KB Food Team runs. This is 24 AI agents organized into 6 sequential phases, with agents running in parallel within each phase.

**Trigger chain:**
```
tenant_provisioning.py → emit("company.provisioned")
    → events/kb_onboarding.py listens
    → calls kb_orchestrator.orchestrate_kb_onboarding(company_id, industry, company_name, user_count)
```

**File:** `solid-backend/agents/kb_orchestrator.py`

### Phase 1: APPETIZER (2 minutes, 3 agents)

**Purpose:** Industry detection and company profiling.

| Agent | Role | What It Does |
|-------|------|-------------|
| Apple | Industry Detector | Confirms/refines industry from `kb_sub_code`. Returns `industry_confirmed`. |
| Kale | Company Profiler | Analyzes company size, market position. Returns `company_size`. |
| Beet | Data Validator | Validates incoming data quality, checks for anomalies. |

**DB queries:** None (analysis only)
**KB entries created:** 0

### Phase 2: MAIN COURSE (5 minutes, 4 agents)

**Purpose:** The core KB population. Template cloning and company-specific content.

| Agent | Role | What It Does |
|-------|------|-------------|
| Meat | Template Cloner | Queries `Customer` and `Product` tables (limit 50/100), creates 150+ KB entries from template + real data |
| Potato | Customer Analyzer | Queries customers by lifecycle stage (VIP, lead, customer), creates 3 summary KB entries |
| Broccoli | Validator | Full KB scan, checks customer/product coverage, creates 1 validation report entry |
| Orange | CRM Configurator | Queries `Product` table, updates `Company.crm_dashboard_config` JSONB, creates 3-4 KB entries |

**DB queries:**
```sql
-- Meat
SELECT * FROM customers WHERE company_id = :cid LIMIT 50;
SELECT * FROM products WHERE company_id = :cid LIMIT 100;

-- Potato
SELECT * FROM customers WHERE company_id = :cid
  AND lifecycle_stage IN ('customer', 'vip', 'lead') LIMIT 100;

-- Orange
SELECT * FROM products WHERE company_id = :cid LIMIT 100;
UPDATE companies SET crm_dashboard_config = :config WHERE id = :cid;
```

**KB entries created:** 150-250

### Phase 3: SIDES (10 minutes, 4 agents)

**Purpose:** Company-specific knowledge extraction from CRM data.

| Agent | Role | What It Does |
|-------|------|-------------|
| French Fries | Deal Analyzer | Queries `Deal` table, creates pipeline/won/lost analysis KB entries |
| Carrot | Contact Mapper | Queries `Contact` table, creates relationship map KB entries |
| Radish | Aggregate Calculator | Runs aggregate queries (revenue, counts), creates summary entries |
| Pepper | Feature Gater | Queries `Company` for tier + `kb_sub_code`, updates `Company.feature_config`, creates 1 KB entry |

**DB queries:**
```sql
-- French Fries
SELECT * FROM deals WHERE tenant_company_id = :cid LIMIT 100;

-- Carrot
SELECT * FROM contacts WHERE company_id = :cid LIMIT 100;

-- Pepper
SELECT * FROM companies WHERE id = :cid;
UPDATE companies SET feature_config = :config WHERE id = :cid;
```

**Pepper's gating logic:** `allowed_features = industry_features ∩ tier_features`

**KB entries created:** 9-12

### Phase 4: DRINKS (3 minutes, 4 agents)

**Purpose:** Quality checks and security audit.

| Agent | Role | What It Does |
|-------|------|-------------|
| Coffee | Security Checker | Verifies data encryption, access controls. Returns `security_passed`. |
| Juice | Health Monitor | Checks API health, service connectivity. Returns `health_check_passed`. |
| Tea | Completeness Scorer | Full KB scan, calculates coverage percentage. Returns `completeness_score` (0-100). |
| Bubble Tea | Tenant Isolation Auditor | **SECURITY GATE** — audits ALL queries for `company_id` filtering. Returns `audit_passed`, `security_score`. |

**DB queries:** Full KB scan, all tables checked for isolation
**KB entries created:** 4

### Phase 5: DESSERTS (5 minutes, 4 agents)

**Purpose:** User experience creation.

| Agent | Role | What It Does |
|-------|------|-------------|
| Cake | Welcome Creator | Creates welcome message, getting started checklist, dashboard guide, workflow suggestions (4 KB entries) |
| Cupcake | Quick Wins | Creates "quick win" tutorials and tips (3 KB entries) |
| Cookie | Personalization | Creates personalized recommendations based on industry (3 KB entries) |
| Ice Cream | Delight | Creates surprise/delight content, Easter eggs for the user (2 KB entries) |

**IMPORTANT:** Cake requires `company_name` to be non-null. Was crashing with None before fix (2026-02-11).

**KB entries created:** 12

### Phase 6: TOYS (no timeout, async)

**Purpose:** Experimental features, runs in background forever.

| Agent | Role | What It Does |
|-------|------|-------------|
| Dice | A/B Tester | Randomly enables experimental features |
| Target | Goal Setter | Creates industry-specific goals and milestones |
| Game | Gamification | Sets up achievement/badge system |
| Easter Egg | Surprises | Hides fun content throughout the platform |

**Runs via:** `asyncio.create_task()` — non-blocking, no timeout

**KB entries created:** 10-11

### Session Management

Each agent gets its own DB session because agents run in parallel via `asyncio.gather`:

```python
async def _execute_agent(self, agent_name, phase, **kwargs):
    from services.database import get_session
    db = get_session()
    agent.db = db
    try:
        result = await agent.execute(
            phase=phase.value,
            company_id=kwargs.get("company_id"),
            company_name=kwargs.get("company_name"),
            industry=kwargs.get("industry"),
            user_count=kwargs.get("user_count", 1),
            context=self.phase_results
        )
        return result
    except Exception as e:
        db.rollback()
        return {"agent": agent_name, "phase": phase.value, "status": "failed", "error": str(e)}
    finally:
        db.close()
        agent.db = None
```

### Result Extraction

Agent handlers return data wrapped by `base_food_agent.py` under a `"result"` key:
```json
{"agent": "Apple", "status": "completed", "result": {"industry_confirmed": "plumber"}}
```

The orchestrator's `_extract_from_results()` and `_sum_from_results()` check both top-level keys and nested `"result"` dicts.

### Final Report

```json
{
  "company_id": 141,
  "company_name": "Joe's Plumbing",
  "industry": "plumber",
  "kb_entries_created": 207,
  "completeness_score": 78.0,
  "security_audit_passed": true,
  "time_elapsed_seconds": 12,
  "time_elapsed_formatted": "0 minutes 12 seconds",
  "agents_deployed": 24,
  "phases_completed": 6,
  "status": "KB Feast Complete!"
}
```

---

## 12. Step 10: Dashboard Ready

After checkout, the user is redirected to `/dashboard/setup-wizard`.

**Frontend redirect flow (sync path):**
1. Checkout returns `access_token` in response
2. Frontend stores token: `localStorage.solid_access_token = token`
3. Sets flag: `sessionStorage.solid_just_signed_up = true`
4. 500ms delay, then: `window.location.href = "/dashboard/setup-wizard"`

**No polling.** The sync provisioning path returns the token directly. The old async polling flow (`/onboarding/complete` page) is NOT used for sync users.

**Middleware allows it:** The `enroll.*` subdomain middleware allows `/dashboard/*` paths (fix applied 2026-02-11).

### Setup Wizard

The setup wizard is **decoupled** from provisioning — it is a separate post-login page that does NOT create company, billing, or KB records. It only updates existing records. Safe to modify independently.

The setup wizard guides the user through initial configuration:
1. Company branding (logo, colors)
2. Agent personalities
3. Communication preferences
4. First AI interaction

While the user does the setup wizard, Phase 2 + KB Food Team run in the background. By the time the user finishes the wizard, KB is fully populated.

---

## 13. Database Tables Created

### Platform Commerce DB (solid_platform_commerce)

| Table | Purpose | Key Fields |
|-------|---------|-----------|
| `onboarding_sessions` | All wizard state | id, email, full_name, password_hash, tier, kb_sub_code, industry_key, status, current_step, stripe_customer_id, stripe_subscription_id, stripe_payment_method_id |
| `platform_orders` | Order records | id, order_number, session_id, total_cents, status |
| `platform_transactions` | Payment records | id, order_id, processor_transaction_id, amount_cents, status |

### Main Backend DB (solid_dev / solid_prod)

| Table | Phase | Count | Purpose |
|-------|-------|-------|---------|
| `companies` | 1 | 1 | Tenant record (tier, industry, feature_settings, stripe_subscription_id) |
| `users` | 1 | 1 | Admin user (password_hash or OAuth) |
| `company_members` | 1 | 1 | User ↔ Company link |
| `company_subscriptions` | 1 | 1 | Subscription state (tier, period) |
| `subdomain_mappings` | 1 | 1 | Slug → company routing |
| `billing_customers` | 1 | 1 | Billing account (tenant_id = company_id) |
| `billing_payment_methods` | 1 | 1 | Payment method (provider="stripe", provider_payment_method_id=pm_xxx) |
| `billing_subscriptions` | 1 | 1 | Recurring billing state |
| `billing_invoices` | 1 | 1 | First invoice (status="paid") |
| `billing_invoice_line_items` | 1 | 1 | Line item for first invoice |
| `provisioning_requests` | 1 | 1 | Idempotency tracking |
| `agents` | 2 | 11 | AI agents (Sarah, Jake, Devon, etc.) |
| `sites` | 2 | 4 | Default websites |
| `company_knowledge_base` | 2+ | ~92-207 | KB entries (template + food team) |
| `company_ai_budgets` | 2 | 1 | Token budget by tier |
| `gpt_contexts` | 2 | 3 | Personality, Identity, Knowledge |

---

## 14. Feature Settings JSON

Stored in `companies.feature_settings` (JSONB column). Populated during Phase 1.

```json
{
  "subscription": {
    "tier": "professional",
    "billing_cycle": "monthly",
    "price_cents": 49900
  },
  "owner": {
    "full_name": "John Smith",
    "email": "user@example.com",
    "phone": "+15551234567"
  },
  "onboarding_roi": {
    "monthly_revenue": 25000,
    "software_spend": 500,
    "admin_hours": 20
  },
  "platform_commerce": {
    "order_id": "d4eb8761-...",
    "order_number": "ORD-2026-84902",
    "order_total_cents": 49900,
    "transaction_id": "5c27bf99-...",
    "provisioned_at": "2026-02-11T15:30:00Z",
    "has_auto_billing": true
  },
  "signup": {
    "date": "2026-02-11T15:30:00Z"
  },
  "communication_plan": {
    "phone_number_type": "shared",
    "voice_plan": "none",
    "sms_plan": "none",
    "setup_cents": 0,
    "monthly_cents": 0
  }
}
```

**21 keys total** across 6 groups.

---

## 15. Three-Layer Feature Gating

After onboarding, features are gated by three layers that intersect:

```
LAYER 1: Subscription Tier      → What they PAID for (Starter → Enterprise)
LAYER 2: Industry Type           → What's RELEVANT (kb_sub_code determines modules)
LAYER 3: Feature Settings        → What's ENABLED/DISABLED (company.feature_settings)

FINAL VISIBILITY = Tier ∩ Industry ∩ Settings
```

**File:** `solid-backend/constants/feature_tiers.py` — `get_tier_features_for_company()`

**Example:** A Professional-tier plumber (kb_sub_code=500):
- Tier allows: CRM, Appointments, Industry Modules, AI Chat, Payments
- Industry allows: Service Trades module (500-599 range)
- Result: All features including service-trades-specific tools

**Example:** A Starter-tier dentist (kb_sub_code=1400):
- Tier allows: AI Chat, Payments (no CRM, no Industry Modules)
- Industry would allow: Healthcare module, but tier blocks it
- Result: Only AI Chat and Payments

---

## 16. Session & Token Management

### Onboarding Session Token (Platform Commerce)

- **Issued by:** `POST /api/v1/onboarding/start`
- **Algorithm:** HS256
- **Expiry:** 24 hours
- **Payload:** `{ "session_id": "uuid", "exp": timestamp }`
- **Storage:** Frontend localStorage as `onboarding_session_token`
- **Validation:** Frontend calls `isTokenExpired()` before each API call

### Access Token (Main Backend, post-provisioning)

- **Issued by:** `tenant_provisioning.py` during Phase 1
- **Algorithm:** HS256
- **Expiry:** 1 hour
- **Payload:** `{ "sub": "user_id", "company_id": 141, "email": "...", "role": "admin" }`
- **Storage:** Frontend localStorage + sessionStorage as `solid_access_token`

### Refresh Token (post-login)

- **Endpoint:** `POST /api/v1/auth/refresh`
- **Expiry:** 7 days
- **Storage:** `solid_refresh_token` in localStorage
- **Auto-refresh:** SessionGuard runs every 60s, apiClient retries on 401

### Session Cookie (post-login)

- **Name:** `solid_session`
- **Storage:** Redis (server-side)
- **Expiry:** 7 days
- **Purpose:** Preferred auth method (checked before JWT)

### Expired Token Recovery

If user returns to wizard after 24h:
1. `isTokenExpired()` detects expired JWT (60s buffer)
2. Clears all localStorage onboarding keys
3. Resets wizard to step 0
4. User must start fresh (backend retains session data for 30 days)

---

## 17. Environment Configuration

### Environment Variables (Critical)

```env
# Docker network (service-to-service) — Use container names!
MAIN_BACKEND_URL=http://solid-backend:8090
BACKEND_URL=http://solid-backend:8090
PLATFORM_COMMERCE_URL=http://solid-platform-commerce:8091
SOLID_BACKEND_WEBHOOK_URL=http://solid-backend:8090/api/v1/webhooks/inbound

# Browser (client-side)
NEXT_PUBLIC_BACKEND_URL=http://localhost:8090
NEXT_PUBLIC_PLATFORM_COMMERCE_URL=http://localhost:8091

# Stripe (primary payment processor)
PAYMENT_PROCESSOR=stripe
STRIPE_SECRET_KEY=sk_test_... (or sk_live_... in production)
STRIPE_PUBLISHABLE_KEY=pk_test_... (or pk_live_... in production)

# processor Sandbox (DECOMMISSIONED — do not use)
# <PROCESSOR>_API_URL=https://<processor-sandbox-host>
# <PROCESSOR>_API_KEY=REDACTED — decommissioned

# Platform Commerce → Backend service secret
PLATFORM_COMMERCE_SERVICE_SECRET=<shared_secret>
SOLID_BACKEND_SERVICE_SECRET=<must_match_above>

# Session
SESSION_EXPIRE_HOURS=24
ALLOW_PUBLIC_REGISTRATION=false  # MUST be false in production

# SMS — Shared platform number for starter-tier tenants (no dedicated number)
SHARED_PLATFORM_NUMBER=+13852207607

# Twilio — MUST be "prod" in production (user uses real Twilio everywhere)
TWILIO_MODE=prod
```

**CRITICAL:** Platform Commerce resolves `solid-backend` (container name), NOT `backend` (service name) or `localhost`. Using the wrong hostname causes "All connection attempts failed" during provisioning.

### Ports

| Service | Container Port | Host Port |
|---------|---------------|-----------|
| Frontend | 3000 | 3000 |
| Backend | 8090 | 8090 |
| Platform Commerce | 8091 | 8091 |
| PostgreSQL (main) | 5432 | 5432 |
| PostgreSQL (commerce) | 5432 | 5433 |
| Redis | 6379 | 6379 |

---

## 18. Error Handling & Edge Cases

### Validation Error (422)

```json
{
  "detail": [
    {"loc": ["body", "email"], "msg": "value is not a valid email address", "type": "value_error.email"}
  ]
}
```

### Account Already Exists (409)

```json
{
  "detail": {
    "error": "account_exists",
    "message": "An account with this email already exists.",
    "support_email": "support@solidnumber.com"
  }
}
```

### Payment Declined (400)

```json
{
  "status": "error",
  "error_code": "payment_declined",
  "error_message": "Your card was declined. Please try a different payment method.",
  "decline_code": "insufficient_funds"
}
```

### Session Already Completed (400)

```json
{
  "detail": {
    "error": "session_already_completed",
    "message": "This session has already completed checkout."
  }
}
```

### Provisioning Timeout / Failure

If sync provisioning takes > 10 seconds, Platform Commerce falls back to async mode:
1. Returns `access_token: null` in checkout response
2. Frontend shows `/onboarding/complete` polling page
3. Polls `GET /api/v1/onboarding/status/{session_id}` every 2 seconds
4. States: pending → creating_company → ... → complete (with JWT)

**No auto-refund:** If provisioning fails entirely, the payment is KEPT (not refunded). The session is marked as `manual_provisioning` and the admin is alerted. The payment-received notification (Section 8.4) ensures the admin always knows someone paid, even if provisioning never completes. Manual intervention resolves these cases.

### Duplicate Checkout Prevention

Three layers:
1. **Frontend:** `localStorage.checkoutInProgress` flag
2. **Platform Commerce:** Session status check (rejects if already `completed`)
3. **Backend:** Idempotency key (session UUID in `provisioning_requests` table)

### Webhook Signature Verification

Platform Commerce → Backend webhook uses HMAC-SHA256:
```python
message = f"{timestamp}.{payload}"
expected = hmac.sha256(secret.encode(), message.encode()).hexdigest()
verified = hmac.compare_digest(signature, f"sha256={expected}")
```

---

## 19. Verification Queries

After a successful onboarding, verify everything was created:

```sql
-- Set the company ID
SET @CID = 141;

-- Phase 1: Core records
SELECT 'Company' as what, COUNT(*) as cnt FROM companies WHERE id = @CID
UNION ALL SELECT 'User', COUNT(*) FROM users WHERE company_id = @CID
UNION ALL SELECT 'CompanyMember', COUNT(*) FROM company_members WHERE company_id = @CID
UNION ALL SELECT 'Subscription', COUNT(*) FROM company_subscriptions WHERE company_id = @CID
UNION ALL SELECT 'SubdomainMapping', COUNT(*) FROM subdomain_mappings WHERE company_id = @CID;

-- Phase 1: Billing records (paid tiers only)
SELECT 'BillingCustomer' as what, COUNT(*) as cnt
  FROM billing_customers WHERE tenant_id = @CID
UNION ALL SELECT 'PaymentMethod', COUNT(*)
  FROM billing_payment_methods
  WHERE billing_customer_id IN (SELECT id FROM billing_customers WHERE tenant_id = @CID)
UNION ALL SELECT 'BillingSub', COUNT(*)
  FROM billing_subscriptions WHERE company_id = @CID AND status = 'active'
UNION ALL SELECT 'Invoice', COUNT(*)
  FROM billing_invoices WHERE company_id = @CID AND status = 'paid';

-- Phase 2: Enrichment
SELECT 'Agents' as what, COUNT(*) as cnt FROM agents WHERE company_id = @CID
UNION ALL SELECT 'Sites', COUNT(*) FROM sites WHERE company_id = @CID
UNION ALL SELECT 'KB Entries', COUNT(*) FROM company_knowledge_base WHERE company_id = @CID
UNION ALL SELECT 'AI Budget', COUNT(*) FROM company_ai_budgets WHERE company_id = @CID
UNION ALL SELECT 'GPT Contexts', COUNT(*) FROM gpt_contexts WHERE company_id = @CID;

-- Feature settings
SELECT feature_settings->'subscription'->>'tier' as tier,
       feature_settings->'platform_commerce'->>'order_number' as order_num,
       feature_settings->'platform_commerce'->>'has_auto_billing' as auto_billing
FROM companies WHERE id = @CID;

-- Payment method integrity (Stripe)
SELECT bpm.provider, bpm.provider_payment_method_id, bpm.card_last4, bpm.card_brand
FROM billing_payment_methods bpm
JOIN billing_customers bc ON bpm.billing_customer_id = bc.id
WHERE bc.tenant_id = @CID;
```

**Expected counts for a Professional-tier signup:**
- Company: 1, User: 1, CompanyMember: 1, Subscription: 1, SubdomainMapping: 1
- BillingCustomer: 1, PaymentMethod: 1, BillingSub: 1, Invoice: 1
- Agents: 11, Sites: 4, KB Entries: 92-207, AI Budget: 1, GPT Contexts: 3

---

## 20. Key Files Reference

### Frontend (solid-frontend)

| File | Purpose |
|------|---------|
| `src/middleware.ts` | Subdomain routing (enroll.*, cms.*), security headers, rate limiting |
| `src/components/onboarding/onboarding-wizard.tsx` | Wizard orchestrator, step management, token validation |
| `src/components/onboarding/steps/step1-signup.tsx` | Email/password + OAuth signup |
| `src/components/onboarding/steps/step2-industry.tsx` | Industry selection with kb_sub_code |
| `src/components/onboarding/steps/step3-roi.tsx` | ROI calculator |
| `src/components/onboarding/steps/step4-plan.tsx` | Plan/tier selection |
| `src/components/onboarding/steps/step5-activate.tsx` | Checkout with payment (duplicate prevention) |
| `src/app/api/onboarding/checkout/route.ts` | Proxy: Frontend → Platform Commerce |
| `src/app/api/onboarding/start/route.ts` | Proxy: Frontend → Platform Commerce |
| `src/lib/api-config.ts` | `getPlatformCommerceUrl()` — resolves Platform Commerce URL |
| `src/data/industry-benchmarks.ts` | 45 industries with kb_sub_code mappings |

### Platform Commerce (solid-platform-commerce)

| File | Purpose |
|------|---------|
| `app/api/routers/onboarding.py` | All step endpoints (start, industry, roi, plan, company-details, checkout) |
| `app/services/checkout_service.py` | Checkout orchestration: Stripe Customer → PM → PaymentIntent → Subscription → provisioning call |
| `app/services/payment_service.py` | Stripe API integration (customer, payment method, payment intent, subscription) |
| `app/services/provisioning_service.py` | Calls main backend `/api/v1/provisioning/create-tenant` |
| `app/services/webhook_service.py` | Webhook dispatch with HMAC signing |
| `app/models/session.py` | OnboardingSession SQLAlchemy model |

### Main Backend (solid-backend)

| File | Purpose |
|------|---------|
| `controllers/provisioning.py` | `POST /api/v1/provisioning/create-tenant` endpoint |
| `schemas/provisioning.py` | Pydantic validation for 39-field provisioning payload |
| `services/tenant_provisioning.py` | Phase 1: Creates company, user, billing, feature_settings |
| `tasks/provision_tenant_async.py` | Phase 2: KB, agents, sites, AI budget, GPT contexts |
| `workers/onboarding_validator.py` | Post-provisioning validation (30s delay) |
| `agents/kb_orchestrator.py` | KB Food Team: 24 agents, 6 phases |
| `agents/food/base_food_agent.py` | Base class for all food agents |
| `agents/food/*.py` | Individual food agent implementations |
| `events/kb_onboarding.py` | Event listener for `company.provisioned` |
| `constants/feature_tiers.py` | Tier definitions, `get_tier_features_for_company()` |
| `constants/kb_template_mapping.py` | 258 business types → KB templates |
| `services/kb_template_service.py` | KB cloning logic |
| `config/gpt_context_defaults.py` | Default GPT contexts |
| `scripts/templates/industries/*.py` | 52 industry template files |
| `models/company.py` | Company model (kb_sub_code, stripe_subscription_id, feature_settings) |
| `models/billing_customer.py` | BillingCustomer model (tenant_id = company_id) |
| `models/billing_payment_method.py` | BillingPaymentMethod model (provider, provider_payment_method_id) |

---

## 21. Timeline Summary

```
0s ─────── User clicks "Sign Up" ──────────────────────────
           │
           ├── Step 1: Signup (session created)              ~1s
           ├── Step 2: Industry selection                    ~1s
           ├── Step 3: ROI calculator                        ~1s
           ├── Step 4: Plan selection                        ~1s
           ├── Step 5: Company details                       ~1s
           │
~5s ────── User clicks "Complete Purchase" ─────────────────
           │
           ├── Stripe Customer + PM + PaymentIntent           ~3s
           ├── Stripe Subscription creation                  ~2s
           ├── Payment-received notification to backend      ~0s (async)
           ├── Phase 1 provisioning (sync)                   ~3-5s
           │   ├── Company created
           │   ├── User created
           │   ├── Billing records created
           │   ├── Feature settings populated
           │   └── JWT generated
           │
~14s ───── User redirected to /dashboard/setup-wizard ──────
           │
           ├── Phase 2 (async, background)                   ~10-30s
           │   ├── 11 AI agents created
           │   ├── 4 sites created
           │   ├── ~92 KB entries cloned
           │   ├── AI budget set
           │   └── GPT contexts created
           │
           ├── KB Food Team (async, background)              ~25min target
           │   ├── APPETIZER: Industry detection             ~2min
           │   ├── MAIN COURSE: Template + data              ~5min
           │   ├── SIDES: CRM knowledge                     ~10min
           │   ├── DRINKS: Quality checks                   ~3min
           │   ├── DESSERTS: UX content                     ~5min
           │   └── TOYS: Experiments                        (ongoing)
           │
           └── Onboarding validator (30s after Phase 1)
               └── Billing records verified

~15-20s ── User is in dashboard, working ──────────────────
           KB populates in background, user doesn't wait
```

**Total user wait time:** ~14 seconds (from signup start to dashboard access)
**Total background time:** ~25 minutes (KB Food Team, non-blocking)

---

## Related Documentation

For deep dives into specific areas, see:

| Area | Document |
|------|----------|
| Full index | [00-INDEX.md](./00-INDEX.md) |
| Zero-drift API spec | [03-ONBOARDING-STEPS-SPEC.md](./03-ONBOARDING-STEPS-SPEC.md) |
| Three-path OAuth map | [17-E2E-THREE-PATH-MAP.md](./17-E2E-THREE-PATH-MAP.md) |
| OAuth session architecture | [18-OAUTH-SESSION-ARCHITECTURE.md](./18-OAUTH-SESSION-ARCHITECTURE.md) |
| Sync provisioning V2 | [80-Sync-Provisioning-V2/00-INDEX.md](./80-Sync-Provisioning-V2/00-INDEX.md) |
| Provisioning contract | [80-Sync-Provisioning-V2/11-PROVISIONING-CONTRACT.md](./80-Sync-Provisioning-V2/11-PROVISIONING-CONTRACT.md) |
| E2E field trace | [80-Sync-Provisioning-V2/14-E2E-ONBOARDING-MAP.md](./80-Sync-Provisioning-V2/14-E2E-ONBOARDING-MAP.md) |
| KB food team details | [26-KB-FOOD-TEAM-ORCHESTRATION.md](./26-KB-FOOD-TEAM-ORCHESTRATION.md) |
| Payment integration | (removed — processor retired) |
| Billing security | (removed — processor retired) |
| Industry feature gating | [24-INDUSTRY-FEATURE-GATING.md](./24-INDUSTRY-FEATURE-GATING.md) |
| Verification checklist | [50-ONBOARDING-VERIFICATION-CHECKLIST.md](./50-ONBOARDING-VERIFICATION-CHECKLIST.md) |
| Session expiry fix | [12-WIZARD-SESSION-EXPIRY-FIX.md](./12-WIZARD-SESSION-EXPIRY-FIX.md) |
| KB pipeline fix (0 entries bug) | [29-KB-PIPELINE-FIX.md](./29-KB-PIPELINE-FIX.md) |
| Day-1 starter UX | [28-DAY1-STARTER-EXPERIENCE.md](./28-DAY1-STARTER-EXPERIENCE.md) |

---

*This document is the single source of truth for the complete onboarding pipeline. Update it when any step changes.*


--- FILE: 19-Onboarding/00-INDEX.md ---

---
topic: 19-onboarding-index
keywords: [activation, day-1, diagnostic, jwt, knowledge-base, locked, provisioning, success-matrix, v2, website]
last_verified: 2026-08-29
status: current
owner: platform-team
---

# Onboarding

> Documentation for Onboarding.

**54 documents** | **21 in subdirectories**

---

<!-- CURATED:START -->
> Documentation for Onboarding.

- [`09-PROCESSOR-INTEGRATION.md`](09-PROCESSOR-INTEGRATION.md) — Processor Integration
---

## Start Here

- **[17-E2E-THREE-PATH-MAP.md](17-E2E-THREE-PATH-MAP.md)** — E2E Three-Path Onboarding Map
- **[18-OAUTH-SESSION-ARCHITECTURE.md](18-OAUTH-SESSION-ARCHITECTURE.md)** — OAuth Session Architecture
- **[26-KB-FOOD-TEAM-ORCHESTRATION.md](26-KB-FOOD-TEAM-ORCHESTRATION.md)** — KB Food Team Orchestration
- **[27-E2E-ONBOARDING-WALKTHROUGH.md](27-E2E-ONBOARDING-WALKTHROUGH.md)** — End-to-End Onboarding Walkthrough
- **[90-ONBOARDING-VERSIONING.md](90-ONBOARDING-VERSIONING.md)** — Onboarding Versioning — V1 (Sacred) / V2 (Experimental)
- **[ONBOARDING-ARCHITECTURE.md](ONBOARDING-ARCHITECTURE.md)** — Onboarding Architecture — From Super-Flow to Focused Flows
- **[00-BILLING-CRITICAL-INDEX.md](00-BILLING-CRITICAL-INDEX.md)** — 🚨 CRITICAL: Billing Documentation Index
- **[01-OVERVIEW.md](01-OVERVIEW.md)** — Onboarding Sprint - December 2025
- **[02-SYSTEM-MAP.md](02-SYSTEM-MAP.md)** — Onboarding System Complete Map
- **[03-INDUSTRY-MODEL.md](03-INDUSTRY-MODEL.md)** — Solid# Industry-First Model
- **[03-ONBOARDING-STEPS-SPEC.md](03-ONBOARDING-STEPS-SPEC.md)** — Onboarding Steps - Platform Commerce API Specification
- **[04-UNIFIED-FLOW.md](04-UNIFIED-FLOW.md)** — Solid# Unified Onboarding Flow
- **[05-MENU-SUBSCRIPTION-MAP.md](05-MENU-SUBSCRIPTION-MAP.md)** — Solid# Menu → Subscription → Industry Map
- **[06-JOURNEY-TO-MENU.md](06-JOURNEY-TO-MENU.md)** — Solid# Journey → Menu Complete Map
- **[07-INDUSTRY-COMPLETE.md](07-INDUSTRY-COMPLETE.md)** — Solid# Industry & Onboarding Complete Map
- **[08-BILLING-SYSTEM.md](08-BILLING-SYSTEM.md)** — AI Billing System Map
- **[10-CLIENT-CHECKLIST.md](10-CLIENT-CHECKLIST.md)** — New Client Onboarding Checklist
- **[11-BILLING-GAPS.md](11-BILLING-GAPS.md)** — Billing & Account System Gaps
- **[11-SESSION-PERSISTENCE-FIX.md](11-SESSION-PERSISTENCE-FIX.md)** — Onboarding Session Persistence Fix
- **[12-UNIFIED-SPEC.md](12-UNIFIED-SPEC.md)** — Unified Billing & Onboarding System Specification
- **[12-WIZARD-SESSION-EXPIRY-FIX.md](12-WIZARD-SESSION-EXPIRY-FIX.md)** — Onboarding Wizard Session Expiry Fix
- **[13-AI-BILLING-ENDPOINTS.md](13-AI-BILLING-ENDPOINTS.md)** — AI Billing API Endpoints
- **[14-AI-USAGE-MATRIX.md](14-AI-USAGE-MATRIX.md)** — AI Usage Matrix - Included in Subscription Tiers
- **[15-SIGNUP-CONFIG-SPEC.md](15-SIGNUP-CONFIG-SPEC.md)** — Signup Config Spec — Required Artifacts for a Provisioned Company
- **[15-VALIDATION-CHECKLIST.md](15-VALIDATION-CHECKLIST.md)** — Onboarding Validation Checklist
- **[16-OAUTH-ONBOARDING-FLOW.md](16-OAUTH-ONBOARDING-FLOW.md)** — OAuth Onboarding Flow
- **[16-SIGNUP-DEFAULTS-AND-OVERRIDES.md](16-SIGNUP-DEFAULTS-AND-OVERRIDES.md)** — Signup Defaults, Overrides & Fallbacks
- **[20-DEDICATED-ONBOARDING-SERVER-PROPOSAL.md](20-DEDICATED-ONBOARDING-SERVER-PROPOSAL.md)** — Proposal: Dedicated Onboarding Server
- **[21-ORDER-OWNERSHIP-ARCHITECTURE.md](21-ORDER-OWNERSHIP-ARCHITECTURE.md)** — Order Ownership Architecture
- **[22-ORDER-ISOLATION.md](22-ORDER-ISOLATION.md)** — Order & Transaction Isolation
- **[23-LEAD-CAPTURE.md](23-LEAD-CAPTURE.md)** — Lead Capture During Onboarding
- **[24-INDUSTRY-FEATURE-GATING.md](24-INDUSTRY-FEATURE-GATING.md)** — Industry-Based Feature Gating
- **[25-COMPREHENSIVE-SYSTEM-MAP.md](25-COMPREHENSIVE-SYSTEM-MAP.md)** — Comprehensive Onboarding System Map
- **[29-KB-PIPELINE-FIX.md](29-KB-PIPELINE-FIX.md)** — KB Pipeline Fix — 0 Knowledge Base Entries (Postmortem)
- **[30-ONBOARDING-SERVICE-SPEC.md](30-ONBOARDING-SERVICE-SPEC.md)** — Solid# Platform Commerce Service
- **[31-PLATFORM-COMMERCE-IMPLEMENTATION.md](31-PLATFORM-COMMERCE-IMPLEMENTATION.md)** — Platform Commerce Service - Implementation Complete
- **[35-PLATFORM-COMMERCE-SERVICE.md](35-PLATFORM-COMMERCE-SERVICE.md)** — Platform Commerce Service
- **[40-ONBOARDING-ARCHITECTURE-MAP.md](40-ONBOARDING-ARCHITECTURE-MAP.md)** — Onboarding Architecture Map
- **[50-ONBOARDING-VERIFICATION-CHECKLIST.md](50-ONBOARDING-VERIFICATION-CHECKLIST.md)** — Onboarding Verification Checklist
- **[60-ONBOARDING-TO-OPERATIONAL.md](60-ONBOARDING-TO-OPERATIONAL.md)** — Complete Journey: Signup to Fully Operational
- **[70-ONBOARDING-CODE-AUDIT.md](70-ONBOARDING-CODE-AUDIT.md)** — Onboarding Flow - End-to-End Code Breakdown
- **[71-ONBOARDING-VERIFICATION-RESULTS.md](71-ONBOARDING-VERIFICATION-RESULTS.md)** — Onboarding & Setup Wizard Verification Results
- **[75-WEBSITE-TEMPLATE-MAPPING.md](75-WEBSITE-TEMPLATE-MAPPING.md)** — Website Template Mapping — 213 kb_sub_codes → industry-specific sites
- **[99-PROVISIONING-SPEC-LOCKED.md](99-PROVISIONING-SPEC-LOCKED.md)** — Provisioning Specification (LOCKED)
- **[ADMIN-NOTIFICATION-GAP.md](ADMIN-NOTIFICATION-GAP.md)** — Admin Notification — Onboarding Events
- ~~[NEW-CLIENT-ONBOARDING-CHECKLIST.md](NEW-CLIENT-ONBOARDING-CHECKLIST.md)~~ — deprecated duplicate → use 10-CLIENT-CHECKLIST.md
- **[ONBOARDING-VALIDATOR-ZERO-COST.md](ONBOARDING-VALIDATOR-ZERO-COST.md)** — Onboarding Validator - Zero-Cost Architecture
- **[SESSION-FLOW-MAPPING.md](SESSION-FLOW-MAPPING.md)** — Critical Session Flow Mapping
- **[ONBOARDING-V2-FEATURE-MAP.md](ONBOARDING-V2-FEATURE-MAP.md)** — V2 Onboarding Feature Map

## Documents

## Subdirectories

- **80-Sync-Provisioning-V2/** — 14 files
- **V1-Current/** — 3 files
- **V2-Redesign/** — 4 files

> User signup, company provisioning, and industry configuration.

---

## Key Documents

| Document | Purpose |
|----------|---------|
| [00-BILLING-CRITICAL-INDEX.md](./00-BILLING-CRITICAL-INDEX.md) | Critical billing docs |
| [01-OVERVIEW.md](./01-OVERVIEW.md) | Onboarding flow overview |
| [02-SYSTEM-MAP.md](./02-SYSTEM-MAP.md) | System architecture |
| [03-INDUSTRY-MODEL.md](./03-INDUSTRY-MODEL.md) | Industry/MCC mapping |

---

## Onboarding Flow

```
Signup → Industry Selection → MCC Assignment → KB Provisioning → Billing Setup → Dashboard
```

**Note:** The retired processor is decommissioned. Platform billing (Solid# → Company) runs on Stripe via Platform Commerce (swappable by design — see `solid-platform-commerce/ARCHITECTURE.md`); tenant payments use each merchant's own processor via the adapter registry (`services/payments/registry.py`). (Billing-security reference removed — processor retired.)

---
<!-- CURATED:END -->

---

## Start Here

- **[17-E2E-THREE-PATH-MAP.md](17-E2E-THREE-PATH-MAP.md)** — E2E Three-Path Onboarding Map
- **[18-OAUTH-SESSION-ARCHITECTURE.md](18-OAUTH-SESSION-ARCHITECTURE.md)** — OAuth Session Architecture
- **[26-KB-FOOD-TEAM-ORCHESTRATION.md](26-KB-FOOD-TEAM-ORCHESTRATION.md)** — KB Food Team Orchestration
- **[27-E2E-ONBOARDING-WALKTHROUGH.md](27-E2E-ONBOARDING-WALKTHROUGH.md)** — End-to-End Onboarding Walkthrough
- **[90-ONBOARDING-VERSIONING.md](90-ONBOARDING-VERSIONING.md)** — Onboarding Versioning — V1 (Sacred) / V2 (Free-to-Paid Sales Funnel)
- **[ONBOARDING-ARCHITECTURE.md](ONBOARDING-ARCHITECTURE.md)** — Onboarding Architecture — From Super-Flow to Focused Flows
- **[00-BILLING-CRITICAL-INDEX.md](00-BILLING-CRITICAL-INDEX.md)** — 🚨 CRITICAL: Billing Documentation Index
- **[01-OVERVIEW.md](01-OVERVIEW.md)** — Onboarding Sprint - December 2025
- **[02-SYSTEM-MAP.md](02-SYSTEM-MAP.md)** — Onboarding System Complete Map
- **[03-INDUSTRY-MODEL.md](03-INDUSTRY-MODEL.md)** — Solid# Industry-First Model
- **[03-ONBOARDING-STEPS-SPEC.md](03-ONBOARDING-STEPS-SPEC.md)** — Onboarding Steps - Platform Commerce API Specification
- **[04-UNIFIED-FLOW.md](04-UNIFIED-FLOW.md)** — Solid# Unified Onboarding Flow
- **[05-MENU-SUBSCRIPTION-MAP.md](05-MENU-SUBSCRIPTION-MAP.md)** — Solid# Menu → Subscription → Industry Map
- **[06-JOURNEY-TO-MENU.md](06-JOURNEY-TO-MENU.md)** — Solid# Journey → Menu Complete Map
- **[07-INDUSTRY-COMPLETE.md](07-INDUSTRY-COMPLETE.md)** — Solid# Industry & Onboarding Complete Map
- **[08-BILLING-SYSTEM.md](08-BILLING-SYSTEM.md)** — AI Billing System Map
- **[10-CLIENT-CHECKLIST.md](10-CLIENT-CHECKLIST.md)** — New Client Onboarding Checklist
- **[11-BILLING-GAPS.md](11-BILLING-GAPS.md)** — Billing & Account System Gaps
- **[11-SESSION-PERSISTENCE-FIX.md](11-SESSION-PERSISTENCE-FIX.md)** — Onboarding Session Persistence Fix
- **[12-UNIFIED-SPEC.md](12-UNIFIED-SPEC.md)** — Unified Billing & Onboarding System Specification
- **[12-WIZARD-SESSION-EXPIRY-FIX.md](12-WIZARD-SESSION-EXPIRY-FIX.md)** — Onboarding Wizard Session Expiry Fix
- **[13-AI-BILLING-ENDPOINTS.md](13-AI-BILLING-ENDPOINTS.md)** — AI Billing API Endpoints
- **[14-AI-USAGE-MATRIX.md](14-AI-USAGE-MATRIX.md)** — AI Usage Matrix - Included in Subscription Tiers
- **[15-SIGNUP-CONFIG-SPEC.md](15-SIGNUP-CONFIG-SPEC.md)** — Signup Config Spec — Required Artifacts for a Provisioned Company
- **[15-VALIDATION-CHECKLIST.md](15-VALIDATION-CHECKLIST.md)** — Onboarding Validation Checklist
- **[16-OAUTH-ONBOARDING-FLOW.md](16-OAUTH-ONBOARDING-FLOW.md)** — OAuth Onboarding Flow
- **[16-SIGNUP-DEFAULTS-AND-OVERRIDES.md](16-SIGNUP-DEFAULTS-AND-OVERRIDES.md)** — Signup Defaults, Overrides & Fallbacks
- **[20-DEDICATED-ONBOARDING-SERVER-PROPOSAL.md](20-DEDICATED-ONBOARDING-SERVER-PROPOSAL.md)** — Proposal: Dedicated Onboarding Server
- **[21-ORDER-OWNERSHIP-ARCHITECTURE.md](21-ORDER-OWNERSHIP-ARCHITECTURE.md)** — Order Ownership Architecture
- **[22-ORDER-ISOLATION.md](22-ORDER-ISOLATION.md)** — Order & Transaction Isolation
- **[23-LEAD-CAPTURE.md](23-LEAD-CAPTURE.md)** — Lead Capture During Onboarding
- **[24-INDUSTRY-FEATURE-GATING.md](24-INDUSTRY-FEATURE-GATING.md)** — Industry-Based Feature Gating
- **[25-COMPREHENSIVE-SYSTEM-MAP.md](25-COMPREHENSIVE-SYSTEM-MAP.md)** — Comprehensive Onboarding System Map
- **[29-KB-PIPELINE-FIX.md](29-KB-PIPELINE-FIX.md)** — KB Pipeline Fix — 0 Knowledge Base Entries (Postmortem)
- **[30-ONBOARDING-SERVICE-SPEC.md](30-ONBOARDING-SERVICE-SPEC.md)** — Solid# Platform Commerce Service
- **[31-PLATFORM-COMMERCE-IMPLEMENTATION.md](31-PLATFORM-COMMERCE-IMPLEMENTATION.md)** — Platform Commerce Service - Implementation Complete
- **[35-PLATFORM-COMMERCE-SERVICE.md](35-PLATFORM-COMMERCE-SERVICE.md)** — Platform Commerce Service
- **[40-ONBOARDING-ARCHITECTURE-MAP.md](40-ONBOARDING-ARCHITECTURE-MAP.md)** — Onboarding Architecture Map
- **[50-ONBOARDING-VERIFICATION-CHECKLIST.md](50-ONBOARDING-VERIFICATION-CHECKLIST.md)** — Onboarding Verification Checklist
- **[60-ONBOARDING-TO-OPERATIONAL.md](60-ONBOARDING-TO-OPERATIONAL.md)** — Complete Journey: Signup to Fully Operational
- **[70-ONBOARDING-CODE-AUDIT.md](70-ONBOARDING-CODE-AUDIT.md)** — Onboarding Flow - End-to-End Code Breakdown
- **[71-ONBOARDING-VERIFICATION-RESULTS.md](71-ONBOARDING-VERIFICATION-RESULTS.md)** — Onboarding & Setup Wizard Verification Results
- **[99-PROVISIONING-SPEC-LOCKED.md](99-PROVISIONING-SPEC-LOCKED.md)** — Provisioning Specification (LOCKED)
- **[ADMIN-NOTIFICATION-GAP.md](ADMIN-NOTIFICATION-GAP.md)** — Admin Notification — Onboarding Events
- **[NEW-CLIENT-ONBOARDING-CHECKLIST.md](NEW-CLIENT-ONBOARDING-CHECKLIST.md)** — New Client Onboarding Checklist (moved)
- **[ONBOARDING-VALIDATOR-ZERO-COST.md](ONBOARDING-VALIDATOR-ZERO-COST.md)** — Onboarding Validator - Zero-Cost Architecture
- **[SESSION-FLOW-MAPPING.md](SESSION-FLOW-MAPPING.md)** — Critical Session Flow Mapping

## Documents

| File | Title | Priority | Last Verified |
|------|-------|----------|---------------|
| [00-BILLING-CRITICAL-INDEX.md](00-BILLING-CRITICAL-INDEX.md) | 🚨 CRITICAL: Billing Documentation Index | high | 2026-08-29 |
| [01-OVERVIEW.md](01-OVERVIEW.md) | Onboarding Sprint - December 2025 | high | 2026-08-29 |
| [02-SYSTEM-MAP.md](02-SYSTEM-MAP.md) | Onboarding System Complete Map | high | 2026-08-29 |
| [03-INDUSTRY-MODEL.md](03-INDUSTRY-MODEL.md) | Solid# Industry-First Model | high | 2026-08-29 |
| [03-ONBOARDING-STEPS-SPEC.md](03-ONBOARDING-STEPS-SPEC.md) | Onboarding Steps - Platform Commerce API Specification | high | 2026-08-29 |
| [04-UNIFIED-FLOW.md](04-UNIFIED-FLOW.md) | Solid# Unified Onboarding Flow | high | 2026-08-29 |
| [05-MENU-SUBSCRIPTION-MAP.md](05-MENU-SUBSCRIPTION-MAP.md) | Solid# Menu → Subscription → Industry Map | high | 2026-01-22 |
| [06-JOURNEY-TO-MENU.md](06-JOURNEY-TO-MENU.md) | Solid# Journey → Menu Complete Map | high | 2026-01-22 |
| [07-INDUSTRY-COMPLETE.md](07-INDUSTRY-COMPLETE.md) | Solid# Industry & Onboarding Complete Map | high | 2026-01-22 |
| [08-BILLING-SYSTEM.md](08-BILLING-SYSTEM.md) | AI Billing System Map | high | 2026-08-29 |
| [09-PROCESSOR-INTEGRATION.md](09-PROCESSOR-INTEGRATION.md) | Processor Integration — no single processor is core | — | 2026-08-29 |
| [10-CLIENT-CHECKLIST.md](10-CLIENT-CHECKLIST.md) | New Client Onboarding Checklist | high | 2026-08-29 |
| [11-BILLING-GAPS.md](11-BILLING-GAPS.md) | Billing & Account System Gaps | high | 2026-08-29 |
| [11-SESSION-PERSISTENCE-FIX.md](11-SESSION-PERSISTENCE-FIX.md) | Onboarding Session Persistence Fix | high | 2026-08-29 |
| [12-UNIFIED-SPEC.md](12-UNIFIED-SPEC.md) | Unified Billing & Onboarding System Specification | high | 2026-08-29 |
| [12-WIZARD-SESSION-EXPIRY-FIX.md](12-WIZARD-SESSION-EXPIRY-FIX.md) | Onboarding Wizard Session Expiry Fix | high | 2026-08-29 |
| [13-AI-BILLING-ENDPOINTS.md](13-AI-BILLING-ENDPOINTS.md) | AI Billing API Endpoints | high | 2026-08-29 |
| [14-AI-USAGE-MATRIX.md](14-AI-USAGE-MATRIX.md) | AI Usage Matrix - Included in Subscription Tiers | high | 2026-08-29 |
| [15-SIGNUP-CONFIG-SPEC.md](15-SIGNUP-CONFIG-SPEC.md) | Signup Config Spec — Required Artifacts for a Provisioned Company | high | 2026-08-29 |
| [15-VALIDATION-CHECKLIST.md](15-VALIDATION-CHECKLIST.md) | Onboarding Validation Checklist | high | 2026-08-29 |
| [16-OAUTH-ONBOARDING-FLOW.md](16-OAUTH-ONBOARDING-FLOW.md) | OAuth Onboarding Flow | high | 2026-08-29 |
| [16-SIGNUP-DEFAULTS-AND-OVERRIDES.md](16-SIGNUP-DEFAULTS-AND-OVERRIDES.md) | Signup Defaults, Overrides & Fallbacks | high | 2026-08-29 |
| [17-E2E-THREE-PATH-MAP.md](17-E2E-THREE-PATH-MAP.md) | E2E Three-Path Onboarding Map | critical | 2026-08-29 |
| [18-OAUTH-SESSION-ARCHITECTURE.md](18-OAUTH-SESSION-ARCHITECTURE.md) | OAuth Session Architecture | critical | 2026-08-29 |
| [20-DEDICATED-ONBOARDING-SERVER-PROPOSAL.md](20-DEDICATED-ONBOARDING-SERVER-PROPOSAL.md) | Proposal: Dedicated Onboarding Server | high | 2026-08-29 |
| [21-ORDER-OWNERSHIP-ARCHITECTURE.md](21-ORDER-OWNERSHIP-ARCHITECTURE.md) | Order Ownership Architecture | high | 2026-08-29 |
| [22-ORDER-ISOLATION.md](22-ORDER-ISOLATION.md) | Order & Transaction Isolation | high | 2026-08-29 |
| [23-LEAD-CAPTURE.md](23-LEAD-CAPTURE.md) | Lead Capture During Onboarding | high | 2026-08-29 |
| [24-INDUSTRY-FEATURE-GATING.md](24-INDUSTRY-FEATURE-GATING.md) | Industry-Based Feature Gating | high | 2026-08-29 |
| [25-COMPREHENSIVE-SYSTEM-MAP.md](25-COMPREHENSIVE-SYSTEM-MAP.md) | Comprehensive Onboarding System Map | high | 2026-08-29 |
| [26-KB-FOOD-TEAM-ORCHESTRATION.md](26-KB-FOOD-TEAM-ORCHESTRATION.md) | KB Food Team Orchestration | critical | 2026-08-29 |
| [27-E2E-ONBOARDING-WALKTHROUGH.md](27-E2E-ONBOARDING-WALKTHROUGH.md) | End-to-End Onboarding Walkthrough | critical | 2026-08-29 |
| [28-DAY1-STARTER-EXPERIENCE.md](28-DAY1-STARTER-EXPERIENCE.md) | Day-1 Starter Tier Experience | — | 2026-02-12 |
| [29-KB-PIPELINE-FIX.md](29-KB-PIPELINE-FIX.md) | KB Pipeline Fix — 0 Knowledge Base Entries (Postmortem) | high | 2026-08-29 |
| [30-E2E-CHECKOUT-TEST-PLAN.md](30-E2E-CHECKOUT-TEST-PLAN.md) | End-to-End Checkout Test Plan | — | 2026-03-05 |
| [30-ONBOARDING-SERVICE-SPEC.md](30-ONBOARDING-SERVICE-SPEC.md) | Solid# Platform Commerce Service | high | 2026-08-29 |
| [31-PLATFORM-COMMERCE-IMPLEMENTATION.md](31-PLATFORM-COMMERCE-IMPLEMENTATION.md) | Platform Commerce Service - Implementation Complete | high | 2026-08-29 |
| [35-PLATFORM-COMMERCE-SERVICE.md](35-PLATFORM-COMMERCE-SERVICE.md) | Platform Commerce Service | high | 2026-08-29 |
| [40-ONBOARDING-ARCHITECTURE-MAP.md](40-ONBOARDING-ARCHITECTURE-MAP.md) | Onboarding Architecture Map | high | 2026-08-29 |
| [50-ONBOARDING-VERIFICATION-CHECKLIST.md](50-ONBOARDING-VERIFICATION-CHECKLIST.md) | Onboarding Verification Checklist | high | 2026-08-29 |
| [60-ONBOARDING-TO-OPERATIONAL.md](60-ONBOARDING-TO-OPERATIONAL.md) | Complete Journey: Signup to Fully Operational | high | 2026-08-29 |
| [70-ONBOARDING-CODE-AUDIT.md](70-ONBOARDING-CODE-AUDIT.md) | Onboarding Flow - End-to-End Code Breakdown | high | 2026-08-29 |
| [71-ONBOARDING-VERIFICATION-RESULTS.md](71-ONBOARDING-VERIFICATION-RESULTS.md) | Onboarding & Setup Wizard Verification Results | high | 2026-01-27 |
| [75-WEBSITE-TEMPLATE-MAPPING.md](75-WEBSITE-TEMPLATE-MAPPING.md) | Website Template Mapping — Industry-Specific Sites | — | 2026-03-27 |
| [90-CUSTOMER-SUCCESS-MATRIX.md](90-CUSTOMER-SUCCESS-MATRIX.md) | Customer Success Matrix — ADA-Powered Activation & Retention | P1 | 2026-03-13 |
| [90-ONBOARDING-VERSIONING.md](90-ONBOARDING-VERSIONING.md) | Onboarding Versioning — V1 (Sacred) / V2 (Free-to-Paid Sales Funnel) | critical | 2026-04-12 |
| [99-PROVISIONING-SPEC-LOCKED.md](99-PROVISIONING-SPEC-LOCKED.md) | Provisioning Specification (LOCKED) | high | 2026-08-29 |
| [ADMIN-NOTIFICATION-GAP.md](ADMIN-NOTIFICATION-GAP.md) | Admin Notification — Onboarding Events | high | 2026-08-29 |
| [NEW-CLIENT-ONBOARDING-CHECKLIST.md](NEW-CLIENT-ONBOARDING-CHECKLIST.md) | New Client Onboarding Checklist (moved) | high | 2026-08-20 |
| [ONBOARDING-ARCHITECTURE.md](ONBOARDING-ARCHITECTURE.md) | Onboarding Architecture — From Super-Flow to Focused Flows | critical | 2026-08-29 |
| [ONBOARDING-DATA-VERIFICATION.md](ONBOARDING-DATA-VERIFICATION.md) | Onboarding Data Verification Guide | — | 2026-03-01 |
| [ONBOARDING-V2-FEATURE-MAP.md](ONBOARDING-V2-FEATURE-MAP.md) | Onboarding V2 — Complete Feature Map | — | 2026-04-01 |
| [ONBOARDING-VALIDATOR-ZERO-COST.md](ONBOARDING-VALIDATOR-ZERO-COST.md) | Onboarding Validator - Zero-Cost Architecture | high | 2026-08-29 |
| [SESSION-FLOW-MAPPING.md](SESSION-FLOW-MAPPING.md) | Critical Session Flow Mapping | high | 2026-08-29 |

## Subdirectories

### 80-Sync-Provisioning-V2/ — 14 files

- [80-Sync-Provisioning-V2/01-ARCHITECTURE.md](80-Sync-Provisioning-V2/01-ARCHITECTURE.md) — Sync Provisioning V2 - Architecture
- [80-Sync-Provisioning-V2/02-API-SPEC.md](80-Sync-Provisioning-V2/02-API-SPEC.md) — Sync Provisioning V2 - API Specification
- [80-Sync-Provisioning-V2/03-IMPLEMENTATION-PLAN.md](80-Sync-Provisioning-V2/03-IMPLEMENTATION-PLAN.md) — Sync Provisioning V2 - Implementation Plan
- [80-Sync-Provisioning-V2/04-BACKEND-CHANGES.md](80-Sync-Provisioning-V2/04-BACKEND-CHANGES.md) — Sync Provisioning V2 - Backend Changes
- [80-Sync-Provisioning-V2/05-PLATFORM-COMMERCE-CHANGES.md](80-Sync-Provisioning-V2/05-PLATFORM-COMMERCE-CHANGES.md) — Sync Provisioning V2 - Platform Commerce Changes
- [80-Sync-Provisioning-V2/06-FRONTEND-CHANGES.md](80-Sync-Provisioning-V2/06-FRONTEND-CHANGES.md) — Sync Provisioning V2 - Frontend Changes
- [80-Sync-Provisioning-V2/07-TESTING-CHECKLIST.md](80-Sync-Provisioning-V2/07-TESTING-CHECKLIST.md) — Sync Provisioning V2 - Testing Checklist
- [80-Sync-Provisioning-V2/08-ROLLBACK-PLAN.md](80-Sync-Provisioning-V2/08-ROLLBACK-PLAN.md) — Sync Provisioning V2 - Rollback Plan
- [80-Sync-Provisioning-V2/09-PHANTOM-PROCESS-BUG.md](80-Sync-Provisioning-V2/09-PHANTOM-PROCESS-BUG.md) — The Phantom Process Bug
- [80-Sync-Provisioning-V2/10-SYNC-ONLY-ARCHITECTURE.md](80-Sync-Provisioning-V2/10-SYNC-ONLY-ARCHITECTURE.md) — Sync Provisioning Only - Enterprise Architecture
- [80-Sync-Provisioning-V2/11-PROVISIONING-CONTRACT.md](80-Sync-Provisioning-V2/11-PROVISIONING-CONTRACT.md) — Provisioning Contract v1
- [80-Sync-Provisioning-V2/12-DEPRECATED-CONTROLLERS.md](80-Sync-Provisioning-V2/12-DEPRECATED-CONTROLLERS.md) — Deprecated Backend Onboarding Controllers
- [80-Sync-Provisioning-V2/13-COMPLETE-SYSTEM-MAP.md](80-Sync-Provisioning-V2/13-COMPLETE-SYSTEM-MAP.md) — Complete Onboarding System Map
- [80-Sync-Provisioning-V2/14-E2E-ONBOARDING-MAP.md](80-Sync-Provisioning-V2/14-E2E-ONBOARDING-MAP.md) — Complete End-to-End Onboarding Flow

### 81-Setup-Wizard/V1-Current/ — 3 files

- [81-Setup-Wizard/V1-Current/01-ARCHITECTURE.md](81-Setup-Wizard/V1-Current/01-ARCHITECTURE.md) — V1 Setup Wizard — Architecture
- [81-Setup-Wizard/V1-Current/02-STEP-FLOW.md](81-Setup-Wizard/V1-Current/02-STEP-FLOW.md) — V1 Setup Wizard — Step Flow
- [81-Setup-Wizard/V1-Current/03-AGENT-PERSONAS.md](81-Setup-Wizard/V1-Current/03-AGENT-PERSONAS.md) — V1 Setup Wizard — Agent Personas

### 81-Setup-Wizard/V2-Redesign/ — 4 files

- [81-Setup-Wizard/V2-Redesign/01-VISION.md](81-Setup-Wizard/V2-Redesign/01-VISION.md) — V2 Setup Wizard — Vision
- [81-Setup-Wizard/V2-Redesign/02-STEP-FLOW.md](81-Setup-Wizard/V2-Redesign/02-STEP-FLOW.md) — V2 Setup Wizard — Step Flow
- [81-Setup-Wizard/V2-Redesign/03-VIBE-WEBSITE-STEP.md](81-Setup-Wizard/V2-Redesign/03-VIBE-WEBSITE-STEP.md) — V2 Vibe-Powered Website Step
- [81-Setup-Wizard/V2-Redesign/04-DASHBOARD-NUDGES.md](81-Setup-Wizard/V2-Redesign/04-DASHBOARD-NUDGES.md) — V2 Dashboard Nudges — Deferred Steps

## Keywords

401, ADA, KB, account-creation, activation, ada, adapter, admin, api, apple, architecture, authentication, auto-login, b2b, banners, bubble-tea, bug, business-logic, business-name, byop, categories, checklist, checkout, churn, code-audit, coffee, communication, company-name, company_id, complete-flow, config, cookies, data-verification, day-1, defaults, diagnostic, doctor, domain, droplets, e2e, email, end-to-end, experiment, expiry, fallback, features, flows, food-agents, free, gaps, google, horizontal, industry, industry-gating, isolation, jwt, kb, kb_sub_code, knowledge-base, localStorage, locked, mcc, meat, microsoft, multi-tenant, no-single-processor, noreply, notifications, oauth, onboarding, orchestration, orders, overrides, password, payment-processor, payment_processor_configs, phone, pipeline, placeholder-email, platform-commerce, postmortem, potato, processor-neutral, provisioning, registry, requirements, retention, sacred, scale, security-audit, seeding, sendgrid, service-to-service, session, setup-completion, setup-wizard, shared-number, signup, signup-config, spec, starter, steps, stripe, success-matrix, template-mapping, templates, testing, three-paths, tier, tiers, toast, token, two-level-commerce, upgrade, ux, v1, v2, validation, verification, versioning, walkthrough, website, wizard


--- FILE: 06-Operations/DOCKER-ARCHITECTURE.md ---

---
topic: operations
keywords: [docker, architecture, compose, containers, services, volumes, ports, env-vars, local, production]
code_paths:
  - solid-backend/docker-compose.base.yml
  - solid-backend/docker-compose.local.yml
  - solid-backend/docker-compose.prod.yml
  - solid-backend/docker-compose.yml
  - deploy.sh
  - dev.sh
  - Caddyfile
last_verified: 2026-08-29
status: historical
priority: critical
owner: platform-team
---
> ## ⛔ HISTORICAL — SFO-era. Production moved 2026-08-30.
> Production is the **`solid-production` cell** (DOKS, nyc1). `solidnumber.com`'s DNS
> points at the app load balancer **`134.199.179.65`**; the SFO droplet
> `<production-host>` is no longer in the request path for it and survives only because
> two apex customer domains still resolve to its native IP.
> Live state: **`06-Operations/00-INFRA-TRUTH.md`** (generated). How to deploy:
> **`06-Operations/00-DEPLOY-START-HERE.md`**. Anything below describing an SSH-to-a-droplet
> deploy, `docker-compose` on the box, or `./deploy.sh` is history, not instruction.


> ⛔ **HISTORICAL** — superseded 2026-08-30 by the cutover to the `solid-production` cell.
> Live state: [`00-INFRA-TRUTH.md`](00-INFRA-TRUTH.md); plan + record:
> [`99-Active-Sprints/SPRINT-INFRA-MASTER-ONE-CELL.md`](../99-Active-Sprints/SPRINT-INFRA-MASTER-ONE-CELL.md).
> **Nothing below describes the running estate.**

# Docker Architecture — Complete Reference

> **Single source of truth** for how the Solid# platform runs in Docker.
> Covers all 14 services, compose file hierarchy, container names, ports, volumes, env vars, and startup sequence.

**Last Updated:** 2026-02-05

---

## Compose File Hierarchy

```
docker-compose.base.yml     ← Shared: 14 service definitions, healthchecks, depends_on
docker-compose.local.yml    ← Local:  Dockerfile.dev, hot-reload, dev env vars, exposed ports
docker-compose.prod.yml     ← Prod:   Dockerfile, secrets from .env, resource limits, 127.0.0.1 binding
docker-compose.yml          ← Docker Desktop convenience wrapper (includes base+local)
```

### How They're Used

| Context | Command | Compose Files |
|---------|---------|---------------|
| **Local dev** | `./dev.sh` | `base.yml` + `local.yml` |
| **Docker Desktop** | Click "Start" | `docker-compose.yml` (includes base+local) |
| **Production** | `./deploy.sh deploy` | `base.yml` + `prod.yml` |

### Precedence Rules

Docker Compose environment variables override in this order (highest wins):

1. Inline `environment:` in compose file
2. `env_file:` references (e.g., `./solid-backend/.env.local`)
3. Shell environment variables
4. `.env` file in project root

**Production** `docker-compose.prod.yml` inline vars override everything in `.env`.
This is intentional — the `.env` file contains secrets, the compose file contains architecture.

---

## All 14 Services

### Service Matrix

| # | Service | Container Name | Local Port | Prod Port | Dockerfile |
|---|---------|---------------|-----------|-----------|------------|
| 1 | postgres | solid-postgres | 5432 | 127.0.0.1:5432 | image: postgres:16-alpine |
| 2 | redis | solid-redis | 6379 | 127.0.0.1:6379 | image: redis:7-alpine |
| 3 | backend | solid-backend | 8090 | 127.0.0.1:8090 | Dockerfile.dev / Dockerfile |
| 4 | celery-worker | solid-celery-worker | — | — | Dockerfile.dev / Dockerfile |
| 5 | celery-beat | solid-celery-beat | — | — | **Prod only** / Dockerfile |
| 6 | flower | solid-flower | 5555 | 127.0.0.1:5555 | Dockerfile.dev / Dockerfile |
| 7 | frontend | solid-frontend | 3000 | 127.0.0.1:3000 | Dockerfile.dev / Dockerfile |
| 8 | public | solid-public | 3001 | 127.0.0.1:3001 | Dockerfile.dev / Dockerfile |
| 9 | superadmin | solid-superadmin | 8080 | 127.0.0.1:8080 | Dockerfile.dev / Dockerfile |
| 10 | platform-commerce | solid-platform-commerce | 8091 | 127.0.0.1:8091 | Dockerfile (cmd override) |
| 11 | platform-commerce-db | solid-platform-commerce-db | 5433 | 127.0.0.1:5433 | image: postgres:15-alpine |
| 12 | mcp-server | solid-mcp-server | 8092 | 127.0.0.1:8092 | Dockerfile (cmd override) |
| 13 | ai-creator-server | solid-ai-creator | 8093 | 127.0.0.1:8093 | Dockerfile (cmd override) |
| 14 | caddy | solid-caddy | **Not in local** | 80, 443 | image: caddy:2.7-alpine |

### Local-Only vs Prod-Only Services

- **celery-beat**: Production only (scheduled billing, cron jobs)
- **caddy**: Production only (reverse proxy, HTTPS, SSL)
- All other 12 services run in both environments

### Image Consolidation (Production — 2026-04-10)

**CRITICAL**: backend, celery-worker, celery-beat, and flower all run from the **same image** in production.

- `backend` is the sole builder: `image: solid-backend:latest` + `build: ./solid-backend`
- `celery-worker`, `celery-beat`, `flower` declare `image: solid-backend:latest` (no `build:`) and `depends_on: backend`
- Docker Compose builds backend once, tags as `solid-backend:latest`, then reuses it for the 3 celery services

**Why:** Before 2026-04-10, each service built its own copy of the same Dockerfile. Result: 4× 7.74GB = ~31GB of duplicated images on the 77GB production disk. Caused recurring `no space left on device` failures during deploy.

**After consolidation:** One 7.74GB backend image shared across 4 services. Future deploys build ONE image instead of four. Reclaimed ~23GB permanently.

**Local dev** still uses 3 separate builds (Dockerfile.dev, volume-mounted source for hot-reload) — the disk issue is prod-specific.

**If you add a new backend-based service:**
```yaml
new-service:
  image: solid-backend:latest  # Reuse — do NOT add build:
  depends_on:
    - backend
  command: python -m new_service
```

---

## Network & DNS

**Network name:** `solid-network` (bridge driver, shared across all services)

Docker creates two DNS entries per service:
- **Service name**: `backend`, `frontend`, `redis`, etc.
- **Container name**: `solid-backend`, `solid-frontend`, `solid-redis`, etc.

Both resolve on the `solid-network`. Internal service-to-service communication uses these names (never `localhost`).

### Internal URL Pattern

| From → To | Local | Production |
|-----------|-------|------------|
| Any service → backend | `http://solid-backend:8090` | `http://backend:8090` |
| Any service → redis | `redis://redis:6379/0` | `redis://:PASSWORD@redis:6379/0` |
| Any service → postgres | `postgresql://...@postgres:5432/...` | Same pattern, secrets from .env |
| Any service → platform-commerce-db | `postgresql://...@platform-commerce-db:5432/platform_commerce` | Same |

**Note:** Local compose uses `solid-backend` (container name) in env vars. Production uses `backend` (service name). Both resolve correctly because Docker registers both on the network.

---

## Volumes

### Local Development

| Volume Name | Purpose |
|-------------|---------|
| `solid-postgres-local` | Main database data |
| `solid-redis-local` | Redis AOF persistence |
| `solid-platform-commerce-local` | Commerce database data |

### Production

| Volume Name | Purpose | Critical? |
|-------------|---------|-----------|
| `solid-postgres-prod` | Main database data | **YES — all tenant data** |
| `solid-redis-prod` | Redis AOF persistence | **YES — session cache** |
| `solid-platform-commerce-prod` | Commerce database data | **YES — billing data** |
| `solid-caddy-data` | SSL certificates (Let's Encrypt) | Yes |
| `solid-caddy-config` | Caddy configuration | Yes |

**Never run `docker volume prune` without checking named volumes first.**

---

## Startup Sequence

Services start in dependency order (defined by `depends_on` + `service_healthy`):

```
1. postgres          ← healthcheck: pg_isready (5s interval)
2. redis             ← healthcheck: redis-cli ping (5s interval)
3. platform-commerce-db  ← healthcheck: pg_isready (5s interval)
   │
   ├─ 4. backend          ← waits for postgres + redis healthy
   ├─ 5. celery-worker    ← waits for postgres + redis healthy
   ├─ 6. celery-beat      ← prod only, waits for postgres + redis
   ├─ 7. flower           ← waits for redis healthy
   ├─ 8. mcp-server       ← waits for postgres + redis healthy
   ├─ 9. ai-creator-server ← waits for postgres + redis healthy
   └─ 10. platform-commerce ← waits for platform-commerce-db healthy
      │
      ├─ 11. frontend      ← waits for backend healthy
      ├─ 12. public        ← waits for backend healthy
      ├─ 13. superadmin    ← waits for backend + platform-commerce-db
      └─ 14. caddy         ← prod only, waits for backend + frontend + public
```

**Backend startup takes 30-60s** (loads 116+ AI agents, Redis subscriptions).
**Total stack startup: 60-90s.**

---

## Production Routing (Caddy)

| Domain | Service | Port | Notes |
|--------|---------|------|-------|
| `api.solidnumber.com` | backend | 8090 | Health check at `/api/v1/_health` |
| `app.solidnumber.com` | frontend | 3000 | Customer portal |
| `solidnumber.com` / `www.` | public | 3001 | Marketing site, injects `X-Tenant-ID: 3` |
| `onboarding.solidnumber.com` | platform-commerce | 8091 | Health check at `/health` |
| `enroll.solidnumber.com` | — | — | Redirects to `app.solidnumber.com/onboarding` |
| `:80` catch-all | — | — | Aborts (blocks IP scanning) |

All traffic goes through Caddy. Services bind to `127.0.0.1` only.
SSL is auto-provisioned via Let's Encrypt.

---

## Resource Limits (Production Only)

| Service | CPU | Memory | Logging |
|---------|-----|--------|---------|
| postgres | 2 | 1.5 GB | json-file, 50MB x 5 |
| redis | 1 | 512 MB | json-file, 50MB x 5 |
| backend | 2 | 2 GB | json-file, 50MB x 5 |
| celery-worker | 2 | 1 GB | json-file, 50MB x 5 |
| celery-beat | 0.5 | 128 MB | json-file, 50MB x 5 |
| flower | 0.5 | 512 MB | json-file, 50MB x 5 |
| frontend | 1 | 512 MB | json-file, 50MB x 5 |
| public | 1 | 512 MB | json-file, 50MB x 5 |
| superadmin | 1 | 512 MB | json-file, 50MB x 5 |
| mcp-server | 1 | 512 MB | json-file, 50MB x 5 |
| ai-creator-server | 2 | 1 GB | json-file, 50MB x 5 |
| platform-commerce | 1 | 512 MB | json-file, 50MB x 5 |
| platform-commerce-db | 0.5 | 256 MB | json-file, 50MB x 5 |
| caddy | 0.5 | 128 MB | json-file, 50MB x 5 |

**Server:** DigitalOcean 8GB RAM + 4GB swap (`/swapfile`)
**No resource limits in local dev** — Docker Desktop manages allocation. Set Docker Desktop memory to 12+ GB (see [Performance Tuning](#performance-tuning-updated-2026-02-05) above).

---

## Dockerfile Inventory

| Service | Dockerfile | Dockerfile.dev | .dockerignore | Base Image |
|---------|-----------|----------------|---------------|------------|
| solid-backend | Multi-stage (builder + final) | Single stage (`development`) | Yes | python:3.11-slim |
| solid-frontend | Multi-stage (deps + builder + runner) | Single stage (`development`) | Yes | node:20-alpine |
| solid-public | Multi-stage (deps + builder + runner) | Single stage (`development`) | No | node:20-alpine |
| solid-superadmin | Multi-stage (deps + builder + runner) | Multi-stage (base + development) | No | node:20-alpine |
| solid-mcp-server | Single stage + tini | **None** (cmd override) | No | node:20-alpine |
| ai-creator-server | Single stage | Single stage (`development`) | No | python:3.13-slim |
| solid-platform-commerce | Single stage | **None** (cmd override) | No | python:3.11-slim |

### Build Pattern

- **Backend, Frontend, Public, Superadmin**: Use `Dockerfile.dev` locally, `Dockerfile` in production
- **MCP Server, Platform Commerce**: Use production `Dockerfile` with command override (`--reload` / `nodemon`) for local dev
- **AI Creator**: Has `Dockerfile.dev` but local compose uses production Dockerfile with `--reload`

### Frontend OOM Prevention

Production `Dockerfile` includes:
```dockerfile
ENV NODE_OPTIONS="--max-old-space-size=4096"
```
This prevents JavaScript heap OOM during `next build` on the 8GB server.

---

## Environment Variable Architecture

### Where Secrets Live

| Environment | Source | Example |
|-------------|--------|---------|
| **Local** | Inline in `docker-compose.yml` / `docker-compose.local.yml` | `JWT_SECRET: dev_only_do_not_use_in_prod_9a0f3b71e3` |
| **Local** | `env_file:` references | `./solid-backend/.env.local` (47 vars) |
| **Production** | `.env` on production server | `JWT_SECRET: ${JWT_SECRET:?must be set}` |
| **Production** | Inline in `docker-compose.prod.yml` | Architecture vars like `COOKIE_SECURE: "true"` |

### 17 Required Production Secrets (in `.env`)

These are validated by `deploy.sh` before deployment:

1. `POSTGRES_USER` / `POSTGRES_PASSWORD`
2. `REDIS_PASSWORD`
3. `JWT_SECRET` / `JWT_SECRET_KEY`
4. `MCP_API_KEY`
5. `NEXTAUTH_SECRET`
6. `LLM_KEY_ENCRYPTION_SECRET`
7. `OAUTH_TOKEN_ENCRYPTION_KEY`
8. `ACCOUNTING_ENCRYPTION_KEY`
9. `PLATFORM_COMMERCE_WEBHOOK_SECRET`
10. `PLATFORM_COMMERCE_SERVICE_SECRET`
11. `PLATFORM_COMMERCE_DB_PASSWORD`
12. `PLATFORM_COMMERCE_JWT_SECRET`
13. `INTERNAL_API_KEY`
14. `FLOWER_BASIC_AUTH`
15. `<PROCESSOR>_API_KEY`

If any are missing, `docker compose up` fails with `variable not set` error.

### Key Differences: Local vs Production

| Setting | Local | Production |
|---------|-------|------------|
| CORS | `localhost:3000,3001,8080` | `solidnumber.com` domains |
| Cookies | `SECURE=false`, no domain | `SECURE=true`, `.solidnumber.com` |
| Redis | No password | Password required |
| Ports | `0.0.0.0` (open) | `127.0.0.1` (localhost only) |
| Registration | Defaults to enabled | `ALLOW_PUBLIC_REGISTRATION=false` |
| JWT | Weak dev secret | Strong secret from `.env` |
| Restart | None | `unless-stopped` |
| Logging | Console (stdout) | json-file (50MB x 5 per service) |
| SHARED_PLATFORM_NUMBER | `+13852207607` | `+13852207607` |
| TWILIO_MODE | `test` | `prod` |

---

## Local Development

### Performance Tuning (Updated 2026-02-05)

Running 12 Docker containers on a development Mac requires careful resource management.

#### Turbopack Compatibility

**Superadmin** uses Turbopack (`--turbopack` flag) for faster local dev:

```yaml
# docker-compose.local.yml
superadmin: npx next dev --port 8080 --turbopack
```

**Frontend and Public do NOT use Turbopack** — they use `npm run dev` (Webpack):

```yaml
frontend:   npm run dev   # next dev --port 3000
public:     npm run dev   # next dev --port 3001
```

**Why not Turbopack everywhere?** All three apps use Tailwind CSS v4 with `@tailwindcss/postcss`. Turbopack has compatibility issues with this PostCSS plugin — CSS fails to load, rendering raw HTML. The superadmin works with Turbopack (needs investigation), but frontend and public break.

**Production uses standard `next build`** (Webpack) for all three apps.

#### Native File Watchers (No Polling)

All file watcher polling is **disabled** — services use native macOS FSEvents instead:

| Service | Variable | Value | Purpose |
|---------|----------|-------|---------|
| backend | `WATCHFILES_FORCE_POLLING` | `false` | Python uvicorn --reload |
| celery-worker | `WATCHFILES_FORCE_POLLING` | `false` | Celery watchfiles |
| frontend | `WATCHPACK_POLLING` | `false` | Next.js file watcher |
| frontend | `CHOKIDAR_USEPOLLING` | `false` | Node.js file watcher |
| public | `WATCHPACK_POLLING` | `false` | Next.js file watcher |
| public | `CHOKIDAR_USEPOLLING` | `false` | Node.js file watcher |
| superadmin | `WATCHPACK_POLLING` | `false` | Next.js file watcher |
| superadmin | `CHOKIDAR_USEPOLLING` | `false` | Node.js file watcher |

**Why:** Polling burns 5-15% CPU per service continuously. Native FSEvents is zero-CPU until a file actually changes. Only enable polling if running Docker on a remote filesystem (e.g., NFS) where FSEvents isn't available.

#### Docker Desktop Memory Allocation

**Required: Set Docker Desktop memory to at least 12 GB** (on a 24 GB Mac).

Docker Desktop → Settings → Resources → Memory slider → 12+ GB

Adam's Mac (24 GB RAM) is configured with ~16 GB for Docker, leaving ~8 GB for macOS + IDE. This gives **11+ GB of headroom** above the ~4 GB containers use at rest.

| Setting | Value | Why |
|---------|-------|-----|
| Memory | 12-16 GB | 12 containers use ~4 GB at rest, spikes during builds |
| Swap | 2 GB | Default is fine |
| CPU | 6 cores | Leave 2 cores for macOS + IDE |

**Measured container memory at rest (with native file watchers, Webpack):**

| Service | Memory |
|---------|--------|
| frontend | ~1.3 GB |
| backend | ~700 MB |
| superadmin | ~600 MB |
| public | ~580 MB |
| celery-worker | ~240 MB |
| flower | ~230 MB |
| ai-creator | ~140 MB |
| platform-commerce | ~120 MB |
| mcp-server | ~100 MB |
| postgres | ~65 MB |
| platform-commerce-db | ~47 MB |
| redis | ~22 MB |
| **Total** | **~4.1 GB** |

---

### Starting the Stack

```bash
./dev.sh              # Start all 12 services (background)
./dev.sh watch        # Start with file sync + hot rebuild
./dev.sh down         # Stop everything
./dev.sh logs backend # Tail backend logs
./dev.sh status       # Container health status
./dev.sh shell backend # Shell into container
./dev.sh rebuild      # Force rebuild (--no-cache)
```

### Local URLs

| Service | URL |
|---------|-----|
| Frontend | http://localhost:3000 |
| Backend API | http://localhost:8090 |
| Backend Docs | http://localhost:8090/docs |
| Public Site | http://localhost:3001 |
| SuperAdmin | http://localhost:8080 |
| Platform Commerce | http://localhost:8091 |
| MCP Server | http://localhost:8092 |
| AI Creator | http://localhost:8093 |
| Flower | http://localhost:5555 (admin:changeme) |

### Local Database Access

```bash
# Main database
psql postgresql://solidnumber:solid_dev_password@localhost:5432/solid_dev

# Commerce database
psql postgresql://postgres:postgres@localhost:5433/platform_commerce

# Redis
redis-cli -h localhost -p 6379
```

---

## Production Deployment

### Deploy Commands

```bash
./deploy.sh deploy              # Deploy ALL services + AUTO-QA
./deploy.sh deploy backend      # Deploy backend only
./deploy.sh deploy frontend     # Deploy frontend only
./deploy.sh rollback            # Rollback last deploy
./deploy.sh rollback 3          # Rollback 3 commits
./deploy.sh status              # Container status
./deploy.sh logs backend        # View logs
./deploy.sh health              # Health checks (exponential backoff)
./deploy.sh qa                  # QA scanner on prod endpoints
./deploy.sh stats               # CPU, memory, disk usage
./deploy.sh backup              # Database backup
./deploy.sh validate            # Pre-push validation
```

### Deployment Flow

```
1. ./deploy.sh validate          ← Pre-push checks
2. git commit + push
3. ./deploy.sh deploy backend    ← SSH to <production-host>
   ├─ git pull + submodule update
   ├─ docker compose build
   ├─ alembic upgrade head       ← Migrations BEFORE container swap
   ├─ docker compose up -d       ← Swap containers
   ├─ health checks (150s max)
   └─ AUTO-QA scanner
4. If broken: ./deploy.sh rollback
```

### Health Check Endpoints (Production)

```
https://api.solidnumber.com/api/v1/health
https://app.solidnumber.com
https://solidnumber.com
https://onboarding.solidnumber.com/health
```

Retries: 8 with exponential backoff (2, 4, 8, 16, 30, 30, 30, 30 seconds).

---

## Critical Rules

### 1. Never Use Submodule Compose Files on Production

```bash
# WRONG — crashes production (missing network, volumes, dependencies)
cd /root/solid/solid-backend && docker-compose up -d

# CORRECT — always use base+overlay from parent directory
cd /root/solid
docker compose -f docker-compose.base.yml -f docker-compose.prod.yml up -d
```

### 2. Migrations Before Container Swap

`deploy.sh` runs `alembic upgrade head` BEFORE `docker compose up -d`.
If migration fails, deployment aborts and no containers are swapped.

### 3. Production Ports Are Localhost-Only

All services bind to `127.0.0.1` in production. Only Caddy (port 80/443) is internet-facing.
Never change port bindings in `docker-compose.prod.yml` to `0.0.0.0`.

### 4. Submodule Compose Files Exist but Are Not Used

These exist for isolated testing only:
- `solid-backend/docker-compose.yml`
- `solid-frontend/docker-compose.yml`
- `solid-mcp-server/docker-compose.yml`
- `solid-platform-commerce/docker-compose.yml`

They are **never** used by `dev.sh` or `deploy.sh`.

---

## Troubleshooting

### Container Won't Start

```bash
# Check which containers are running
docker compose -f docker-compose.base.yml -f docker-compose.local.yml ps

# Check logs for a specific service
./dev.sh logs backend

# Force rebuild
./dev.sh rebuild backend
```

### Port Already in Use

```bash
# Find what's using the port
lsof -i :3000

# Kill it (replace PID)
kill <PID>

# Or change port mapping in docker-compose.local.yml
```

### Orphan Containers

```bash
# Remove containers from old project names
docker rm -f $(docker ps -aq --filter "name=solid-")

# Recreate from scratch
./dev.sh down && ./dev.sh
```

### Database Connection Refused

```bash
# Verify postgres is healthy
docker exec solid-postgres pg_isready -U solidnumber

# Check the connection string uses Docker service name (not localhost)
# Inside container: postgresql://...@postgres:5432/solid_dev
# Outside container: postgresql://...@localhost:5432/solid_dev
```

---

## Wildcard Subdomain Routing (Caddy On-Demand TLS)

**Added:** 2026-02-11

All tenant subdomains (`*.solidnumber.com`) are routed through Caddy's on-demand TLS with a `forward_auth` check to the backend.

### How It Works

```
Request: acme.solidnumber.com/dashboard
    ↓
Caddy receives *.solidnumber.com (wildcard cert via on-demand TLS)
    ↓
forward_auth → GET http://backend:8090/_internal/resolve-tenant
    (sends X-Forwarded-Host: acme.solidnumber.com)
    ↓
Backend checks: CustomDomain → SubdomainMapping → Company.slug
    ↓
Returns 200 + headers:
    X-Tenant-ID: 42
    X-Tenant-Slug: acme
    X-Tenant-Domain-Type: website
    ↓
Caddy copies headers → proxies to solid-public:3001
    ↓
solid-public reads X-Tenant-ID header for tenant-scoped rendering
```

### Internal Endpoints

| Endpoint | Purpose | Called By |
|----------|---------|----------|
| `/_internal/resolve-tenant` | Resolve hostname → tenant headers | Caddy `forward_auth` |
| `/_internal/tls-check` | Validate domain for on-demand TLS cert | Caddy `on_demand` policy |

**File:** `solid-backend/controllers/internal.py`

### TLS Check

Before issuing a certificate for a new subdomain, Caddy calls `/_internal/tls-check?domain=acme.solidnumber.com`. The backend checks if the domain exists as an active `SubdomainMapping` or `CustomDomain` (with `is_verified=True`). Returns 200 (issue cert) or 404 (reject).

---

## Custom Domain Hosting (Caddy On-Demand TLS)

**Added:** 2026-02-15

Customers can connect their own domain (e.g., `<customer-domain>` or `shop.mybusiness.com`) via the setup wizard. Caddy provisions SSL automatically.

### How It Works

```
Customer visits <customer-domain>
    ↓
Caddy :443 catch-all block (on-demand TLS)
    ↓
Caddy calls /_internal/tls-check?domain=<customer-domain>
    ↓
Backend checks: CustomDomain.domain='<customer-domain>' AND is_verified=True AND is_active=True
    ↓
✅ Returns 200 → Caddy provisions Let's Encrypt cert (or uses cached)
    ↓
Caddy calls /_internal/resolve-tenant (forward_auth)
    ↓
Backend returns X-Tenant-ID, X-Tenant-Slug, X-Tenant-Name, X-Tenant-Site-ID
    ↓
Caddy proxies to solid-public:3001 with tenant headers
    ↓
solid-public renders tenant CMS content (or coming-soon page)
```

### Caddyfile Blocks (order matters)

```
1. api.solidnumber.com       → backend:8090
2. app.solidnumber.com       → frontend:3000
3. solidnumber.com (+ www)   → public:3001 (company 3)
4. admin.solidnumber.com     → superadmin:8080
5. onboarding.solidnumber.com → platform-commerce:8091
6. *.solidnumber.com         → public:3001 (tenant subdomains, wildcard cert)
7. :443 catch-all            → public:3001 (custom domains, on-demand TLS)
8. :80 catch-all             → abort (blocks IP scanners)
```

### DNS Verification Flow

Custom domains require `is_verified=True` before SSL works:

1. User adds domain in wizard → `CustomDomain` created with `is_verified=False`
2. Wizard shows DNS A record: point domain to `SERVER_IP` (<production-host>)
3. User clicks "Verify" → `POST /api/v1/setup-wizard/website/verify-domain`
4. Backend does `dns.resolver.resolve(domain, "A")` → checks if IP matches `SERVER_IP`
5. If match → `is_verified=True`, `verified_at` set, `ssl_status='pending'`
6. On first visitor → Caddy `tls-check` returns 200 → cert provisioned

**Future:** `SERVER_IP` env var supports per-customer droplets (set in `cloud-init.sh`).

### Subdomain vs Root Domain DNS

| Input | Type | A Record Name | CNAME needed? |
|-------|------|---------------|---------------|
| `mybusiness.com` | Root domain | `@` | Optional `www` |
| `shop.mybusiness.com` | Subdomain | `shop` | No |

Frontend auto-detects the type and shows correct instructions.

### Tenant Header Flow

After `forward_auth` succeeds, Caddy copies these headers into the upstream request:

- `X-Tenant-ID` — Company ID (integer)
- `X-Tenant-Slug` — Company slug (for URL construction)
- `X-Tenant-Domain-Type` — Domain type (website, landing, etc.)
- `X-Tenant-Site-ID` — Optional site ID (for site-level attribution)

The frontend reads `X-Tenant-ID` via `headers()` in server components.

---

## Related Documentation

- **[LOCAL-PRODUCTION-PARITY.md](LOCAL-PRODUCTION-PARITY.md)** — Why the base+overlay pattern exists
- **[LOCAL-VS-PRODUCTION-MAP.md](LOCAL-VS-PRODUCTION-MAP.md)** — URL and port comparison
- **[TROUBLESHOOTING.md](TROUBLESHOOTING.md)** — Production recovery procedures
- **[DEPLOYMENT.md](DEPLOYMENT.md)** — Detailed deployment procedures
- **[FLOWER-MONITORING.md](FLOWER-MONITORING.md)** — Celery monitoring setup
- **[ENVIRONMENT-CONFIGURATION.md](ENVIRONMENT-CONFIGURATION.md)** — Env var details
- **[SECRETS-CONFIGURATION.md](SECRETS-CONFIGURATION.md)** — Secret management

---

*Last updated: February 15, 2026*
*Maintainer: Platform Team*


--- FILE: 06-Operations/TROUBLESHOOTING.md ---

---
topic: operations
keywords: [operations, accessible, active, actual, after, also, always, applied, auth]
code_paths:
  - solid-backend/scripts/health_check_sequences.py
  - solid-backend/scripts/sync_sequences.py
last_verified: 2026-08-29
status: historical
priority: critical
owner: platform-team
---
> ## ⛔ HISTORICAL — SFO-era. Production moved 2026-08-30.
> Production is the **`solid-production` cell** (DOKS, nyc1). `solidnumber.com`'s DNS
> points at the app load balancer **`134.199.179.65`**; the SFO droplet
> `<production-host>` is no longer in the request path for it and survives only because
> two apex customer domains still resolve to its native IP.
> Live state: **`06-Operations/00-INFRA-TRUTH.md`** (generated). How to deploy:
> **`06-Operations/00-DEPLOY-START-HERE.md`**. Anything below describing an SSH-to-a-droplet
> deploy, `docker-compose` on the box, or `./deploy.sh` is history, not instruction.


> ⛔ **HISTORICAL** — superseded 2026-08-30 by the cutover to the `solid-production` cell.
> Live state: [`00-INFRA-TRUTH.md`](00-INFRA-TRUTH.md); plan + record:
> [`99-Active-Sprints/SPRINT-INFRA-MASTER-ONE-CELL.md`](../99-Active-Sprints/SPRINT-INFRA-MASTER-ONE-CELL.md).
> **Nothing below describes the running estate.**

# Troubleshooting Guide

> **Last Updated:** February 25, 2026 · **Re-verified:** August 29, 2026 (corrections marked ⛔ inline — Caddy container, auth/health/payments/webhook endpoint paths)
> **Status:** Essential Reference
> **Philosophy:** Every error has a solution. This guide has most of them.

---

## 🚨 CRITICAL: Production Docker Compose Pattern

> **STOP!** Before running ANY docker compose commands on production, read this.

### The #1 Cause of Production Crashes

**WRONG** - Using individual service docker compose files:
```bash
# ❌ NEVER DO THIS ON PRODUCTION - WILL CRASH THE SERVER
cd /root/solid/solid-backend && docker compose up -d
cd /root/solid/solid-frontend && docker compose up -d
```

**CORRECT** - Using the base+overlay pattern:
```bash
# ✅ ALWAYS USE THIS PATTERN ON PRODUCTION
cd /root/solid
docker compose -f docker-compose.base.yml -f docker-compose.prod.yml up -d
```

### Why This Matters

- Individual service `docker compose.yml` files are for **local development only**
- They have different network configs, missing env vars, and wrong dependencies
- Using them on production will crash ALL containers
- The base+overlay pattern is the **ONLY** supported production deployment method

### Full Production Recovery (If All Containers Are Down)

```bash
# 1. SSH to server
ssh <operator>@<production-host>

# 2. Navigate to project root (NOT a submodule!)
cd /root/solid

# 3. Pull latest code
git pull origin main
git submodule update --init --recursive

# 4. Start all services with correct compose files
docker compose -f docker-compose.base.yml -f docker-compose.prod.yml up -d

# 5. Verify everything is healthy
docker ps
```

### Full Rebuild with Latest Code

```bash
ssh <operator>@<production-host>
cd /root/solid
git pull origin main
git submodule update --init --recursive
docker compose -f docker-compose.base.yml -f docker-compose.prod.yml build --no-cache
docker compose -f docker-compose.base.yml -f docker-compose.prod.yml up -d
```

### Quick Health Check

```bash
# Check all containers running
ssh <operator>@<production-host> "docker ps --format 'table {{.Names}}\t{{.Status}}'"

# Verify site is accessible
curl -sI https://app.solidnumber.com/login | head -5
curl -sL https://api.solidnumber.com/api/v1/health | head -1
```

> **Re-verified 2026-08-29:** `/api/v1/health` is real — `@router.get("/health", ...)` in `solid-backend/controllers/health.py:369` ("Comprehensive system health check": DB/Redis/socket checks, 30s cache), mounted at prefix `/api/v1` via `app.include_router(health_router, prefix="/api/v1")` (`app.py:1309`ish). A prior pass in this doc incorrectly flagged this path as nonexistent and swapped it for `/api/v1/_health` — that path is also real (`health.py:236`, lightweight internal/liveness check) but is a *different, lighter* endpoint, not a fix. Both exist; this quick check keeps the comprehensive one. Bare `/health` (no `/api/v1`) also exists and 307-redirects to `/api/v1/health` (`app.py:2593`).

---

## deploy.sh Quick Reference

All production operations should use `deploy.sh` from the project root:

```bash
./deploy.sh deploy [service]     # Pull, build, migrate, deploy + auto-QA
./deploy.sh deploy [service] --fresh  # Full rebuild (--no-cache)
./deploy.sh rollback [N|hash]    # Rollback N commits or to specific hash
./deploy.sh backup               # Create timestamped database backup
./deploy.sh restore              # Restore from backup (includes sequence sync)
./deploy.sh validate             # Pre-push syntax + multi-tenant check
./deploy.sh health               # Health checks with exponential backoff
./deploy.sh qa                   # Run QA scanner on production
./deploy.sh status               # Container status
./deploy.sh stats                # Memory/CPU/disk usage
./deploy.sh logs [service]       # View logs
./deploy.sh doctor [prod|local]  # Environment diagnostic
./deploy.sh stripe [test|live|status]  # Swap Stripe keys (~30 sec, no rebuild)
```

Services: `backend`, `frontend`, `public`, `mcp`, `ai`, `celery`, `flower`, `platform-commerce`

---

## Quick Diagnostics

```bash
# Is everything running?
ssh <operator>@<production-host> "docker ps"

# Check logs for errors
ssh <operator>@<production-host> "docker logs solid-backend --tail 100 | grep -i error"

# Check disk space
ssh <operator>@<production-host> "df -h"

# Check memory
ssh <operator>@<production-host> "free -h"

# Check CPU
ssh <operator>@<production-host> "top -bn1 | head -20"
```

---

## Common Issues & Solutions

### 1. API Returns 500 Error

**Symptoms:**
- Frontend shows "Something went wrong"
- API responses have status 500
- Generic error messages

**Diagnosis:**
```bash
# Check backend logs
ssh <operator>@<production-host> "docker logs solid-backend --tail 200"

# Look for the actual error
ssh <operator>@<production-host> "docker logs solid-backend --tail 500 | grep -A 5 'Traceback'"
```

**Common Causes:**

| Error in Logs | Solution |
|---------------|----------|
| `Connection refused` to database | Restart postgres: `docker compose restart postgres` |
| `Connection refused` to Redis | Restart redis: `docker compose restart redis` |
| `ImportError` or `ModuleNotFoundError` | Rebuild: `docker compose up -d --build backend` |
| `KeyError` in config | Check `.env` file has all required variables |
| `OperationalError: database does not exist` | Run migrations: `docker exec solid-backend alembic upgrade head` |

---

### 2. Frontend Won't Load

**Symptoms:**
- Blank page or loading forever
- 404 on app.solidnumber.com
- JS errors in browser console

**Diagnosis:**
```bash
# Check frontend container
ssh <operator>@<production-host> "docker logs solid-frontend --tail 100"

# Check if it's running
ssh <operator>@<production-host> "docker ps | grep frontend"

# Check Caddy (⛔ NOT a container on production — see below)
ssh <operator>@<production-host> "systemctl status caddy"
ssh <operator>@<production-host> "journalctl -u caddy --tail 50"
```

> **⛔ CORRECTED 2026-08-29:** This section previously told you to check `docker logs solid-caddy` / `docker exec solid-caddy caddy reload`. **That container is not the production reverse proxy and has never run on the box** — production Caddy is a **host systemd service** (`systemctl status caddy`) reading `/etc/caddy/Caddyfile`, deployed from `deploy/caddy/Caddyfile` via `./deploy.sh deploy caddy` (`docker-compose.prod.yml:1074-1109`). The `caddy` entry in `docker-compose.prod.yml` is a pre-migration leftover now gated behind `profiles: ["legacy-container-proxy"]` (added 2026-08-11) specifically so a bare `docker compose up -d` — including the "Full Production Recovery" and "Nuclear Option" commands later in this doc — does **not** start it and bind :80/:443 with the wrong (523-line root) Caddyfile. Do not `docker exec solid-caddy` anything; it isn't running.

**Common Causes:**

| Symptom | Solution |
|---------|----------|
| Container not running | `docker compose up -d frontend` |
| Build failed | `docker compose up -d --build frontend` |
| Caddy misconfigured | `ssh <operator>@<production-host> "systemctl reload caddy"` |
| SSL cert issue | Check `/etc/caddy/Caddyfile` (host), then `systemctl reload caddy` |
| Wrong NEXT_PUBLIC_API_URL | Check `.env` in frontend, rebuild |

---

### 3. Authentication Failing

**Symptoms:**
- Can't log in
- "Invalid token" errors
- Redirected to login repeatedly

**Diagnosis:**
```bash
# Check auth endpoints
# Main app (staff/team) login is RPC-based, not OTP:
curl -X POST https://api.solidnumber.com/api/v1/rpc/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","password":"..."}'

# Customer portal OTP (separate system — only path with OTP today):
curl -X POST https://api.solidnumber.com/api/portal/auth/otp/request \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com"}'

# Check Redis (token storage)
ssh <operator>@<production-host> "docker exec solid-redis redis-cli ping"
```

> **⛔ CORRECTED 2026-08-29:** `/api/v1/auth/request-otp` does not exist. Main-app login is an RPC handler at `/api/v1/rpc/auth/login` (`solid-backend/controllers/api.py:81,257`, email/password — not OTP). OTP-based auth exists only for the customer portal, at `/api/portal/auth/otp/request` (`solid-backend/controllers/customer_portal_auth_controller.py:223`, mounted at `app.py:2066`).

**Common Causes:**

| Error | Solution |
|-------|----------|
| "Token expired" | Normal - user needs to re-login |
| "Invalid token" on all requests | Check SECRET_KEY matches in `.env` |
| OTP not arriving | Check SendGrid API key, check spam |
| Redis connection refused | `docker compose restart redis` |
| Clock skew | Sync server time: `timedatectl set-ntp true` |

---

### 4. Database Connection Issues

**Symptoms:**
- "Connection refused" errors
- Slow API responses
- Timeouts on data endpoints

**Diagnosis:**
```bash
# Check PostgreSQL container
ssh <operator>@<production-host> "docker logs solid-postgres --tail 50"

# Check connections
ssh <operator>@<production-host> "docker exec solid-postgres psql -U solidnumber -c 'SELECT count(*) FROM pg_stat_activity;'"

# Check if database exists
ssh <operator>@<production-host> "docker exec solid-postgres psql -U solidnumber -l"
```

**Common Causes:**

| Error | Solution |
|-------|----------|
| Container not running | `docker compose up -d postgres` |
| Too many connections | Restart backend (releases connections) |
| Out of disk space | Clean Docker: `docker system prune -f` |
| Corrupted data | Restore from backup (see Emergency Runbook) |
| Wrong DATABASE_URL | Check `.env` format: `postgresql://user:pass@host:5432/db` |

---

### 5. Celery/Background Jobs Not Running

**Symptoms:**
- Scheduled tasks not executing
- Emails not sending
- Reports not generating

**Diagnosis:**
```bash
# Check Celery container (container is solid-celery-worker, not solid-celery)
ssh <operator>@<production-host> "docker logs solid-celery-worker --tail 100"

# Check Redis broker
ssh <operator>@<production-host> "docker exec solid-redis redis-cli LLEN celery"

# Check Flower (if enabled)
# http://localhost:5555
```

> **⛔ CORRECTED 2026-08-29:** The container is named `solid-celery-worker` (`docker-compose.base.yml:63`) — `docker logs solid-celery` matches nothing on production.

**Common Causes:**

| Error | Solution |
|-------|----------|
| Worker not starting | Check Redis URL in `.env` |
| Tasks queued but not processing | `docker compose restart celery` |
| "Task not registered" | Rebuild Celery: `docker compose up -d --build celery` |
| Memory exceeded | Increase container memory limit |

---

### 5b. Database Sequence Drift (After Restore)

**Symptoms:**
- `UniqueViolation: duplicate key value violates unique constraint "X_pkey"`
- Provisioning fails randomly
- Some companies create, others fail
- Error mentions `Key (id)=(X) already exists`

**Root Cause:**

When you restore a database from backup (pg_dump/pg_restore), the data is inserted with explicit IDs, but PostgreSQL sequences are NOT updated. The next INSERT tries to use an ID that already exists.

**Example:** Sequence thinks next ID is 128, but restored data has IDs up to 154. Next insert tries ID 128 → conflict.

**Diagnosis:**
```bash
# Check if sequences are out of sync
cd solid-backend
python scripts/health_check_sequences.py
```

**Fix:**
```bash
# Sync all sequences to match actual data
cd solid-backend
python scripts/sync_sequences.py
```

**Prevention:**

**ALWAYS run sequence sync after any database restore:**
```bash
# After restoring from backup
docker exec solid-backend python scripts/sync_sequences.py

# Or locally
cd solid-backend && python scripts/sync_sequences.py
```

**Add to deploy.sh for production restores:**
```bash
# After pg_restore
docker exec solid-backend python scripts/sync_sequences.py
```

---

### 5c. Docker Build OOM (Frontend Heap Out of Memory)

**Symptoms:**
- `./deploy.sh deploy` fails during frontend build
- Error: `FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`
- GC logs show memory at ~2GB before crash

**Root Cause:**
The Next.js frontend build (`next build`) can exceed the default Node.js heap limit (~2GB). The production server has 8GB RAM but runs 14 containers, leaving limited free memory for builds.

**Fixes Applied (2026-01-31):**

1. **Dockerfile** — `solid-frontend/Dockerfile` includes:
   ```dockerfile
   ENV NODE_OPTIONS="--max-old-space-size=4096"
   ```
   This gives Node.js up to 4GB heap during `npm run build`.

2. **Swap space** — 4GB swap file on production:
   ```bash
   # Already configured and persisted in /etc/fstab
   # Verify: ssh <operator>@<production-host> "free -h"
   # Should show: Swap: 4.0Gi
   ```

**If OOM still occurs:**
```bash
# 1. Clean Docker build cache (can grow to 10-20GB)
ssh <operator>@<production-host> "docker builder prune -af"

# 2. Verify swap is active
ssh <operator>@<production-host> "free -h"

# 3. If swap is missing, recreate it:
ssh <operator>@<production-host> "fallocate -l 4G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile"

# 4. Retry deploy
./deploy.sh deploy
```

**Prevention:**
- Run `docker builder prune -af` periodically or after failed builds
- Monitor disk usage: `./deploy.sh status` shows disk %
- The Dockerfile `NODE_OPTIONS` setting should not be removed

---

### 6. Deployment Failed

**Symptoms:**
- `git pull` fails
- `docker compose up` errors
- New code not reflected

**Diagnosis:**
```bash
# Check git status
ssh <operator>@<production-host> "cd /root/solid && git status"

# Check for merge conflicts
ssh <operator>@<production-host> "cd /root/solid && git diff"

# Check Docker build
ssh <operator>@<production-host> "cd /root/solid && docker compose -f docker-compose.base.yml -f docker-compose.prod.yml logs --tail 50"
```

**Common Causes:**

| Error | Solution |
|-------|----------|
| Git authentication failed | Update token in remote URL |
| Merge conflict | Resolve manually or `git reset --hard origin/main` |
| Build fails on npm install | Clear cache: `docker system prune -f`, rebuild |
| Out of disk space | `docker system prune -a` (removes unused images) |
| Port already in use | Find process: `lsof -i :8090`, kill it |

---

### 6a. AUTO-QA Failed After Deploy

**Symptoms:**
- Deploy completes but AUTO-QA shows failures
- Message: "Deploy succeeded but QA found issues"
- Endpoints returning 5xx errors

**Diagnosis:**
```bash
# Run QA manually for details
./deploy.sh qa

# Check backend logs
./deploy.sh logs backend

# Check health endpoints
curl https://api.solidnumber.com/api/v1/_health
curl https://api.solidnumber.com/api/v1/platform/discover
```

**Common Causes:**

| Error | Solution |
|-------|----------|
| Endpoint 500 errors | Check backend logs for traceback, fix code |
| Missing company_id filter | Run `./deploy.sh validate` locally first |
| Database migration issue | Check migration ran: `docker exec solid-backend alembic current` |
| Syntax error in deployed code | Rollback: `./deploy.sh rollback backend` |
| Missing environment variable | Check production `.env` file |

**Quick Fix:**
```bash
# Rollback to previous working version
./deploy.sh rollback backend

# Then fix locally and redeploy
./deploy.sh validate
git add . && git commit -m "fix: ..." && git push
./deploy.sh deploy backend
```

---

### 6b. Pre-Push Validation Failed

**Symptoms:**
- `./deploy.sh validate` reports errors
- Syntax errors in Python files
- Multi-tenant linter warnings

**Diagnosis:**
```bash
# Run validation
./deploy.sh validate

# Check specific file syntax
cd solid-backend && python3 -m py_compile controllers/your_file.py
```

**Common Causes:**

| Error | Solution |
|-------|----------|
| Python syntax error | Fix the syntax error in the reported file |
| Multi-tenant violation | Add `company_id` filter to database query |
| Uncommitted changes | Commit or stash changes before deploy |

**Important:** Always run `./deploy.sh validate` BEFORE `git push` to catch these issues early.

---

### 6c. Database Migration Failures

**Symptoms:**
- Deploy fails with "DuplicateTable" or "relation already exists"
- Migration trying to create tables that already exist
- Alembic revision mismatch between local and production

**Diagnosis:**
```bash
# Check current migration version on production
ssh <operator>@<production-host> "docker exec solid-backend alembic current"

# Check what head revision should be
ssh <operator>@<production-host> "docker exec solid-backend alembic heads"

# See migration history
ssh <operator>@<production-host> "docker exec solid-backend alembic history --verbose"
```

**Common Causes & Solutions:**

| Error | Cause | Solution |
|-------|-------|----------|
| `DuplicateTable: relation "X" already exists` | Table was created manually or by previous partial migration | Stamp the migration as applied (see below) |
| `Target database is not up to date` | Migrations were run out of order | Run `alembic upgrade head` |
| `Can't locate revision` | Migration file missing | Check git status, ensure file was pushed |

**Stamping Migrations (Skip Already-Applied Changes):**

If production already has a table that a migration tries to create:
```bash
# Mark migration as applied without running it
ssh <operator>@<production-host> "docker exec solid-backend alembic stamp <revision_id>"

# Then continue with remaining migrations
ssh <operator>@<production-host> "docker exec solid-backend alembic upgrade head"

# Verify current state
ssh <operator>@<production-host> "docker exec solid-backend alembic current"
```

**Best Practices for Migrations:**

1. **Always test locally first:** `docker exec solid-backend alembic upgrade head`
2. **Check for existing tables:** Before creating tables, verify they don't exist
3. **Use IF NOT EXISTS:** When safe, add `IF NOT EXISTS` to CREATE statements
4. **Backup before migrating:** Production data is precious

**Creating Safe Migrations:**

```python
# In migration file, check if table exists first
from alembic import op
from sqlalchemy import text

def upgrade():
    conn = op.get_bind()
    result = conn.execute(text(
        "SELECT EXISTS (SELECT FROM pg_tables WHERE tablename = 'my_table')"
    ))
    if not result.scalar():
        op.create_table('my_table', ...)
```

---

### 7. AI Chat Not Working

**Symptoms:**
- Chat returns errors
- "AI service unavailable"
- Responses timeout

**Diagnosis:**
```bash
# Check AI service logs
ssh <operator>@<production-host> "docker logs solid-backend --tail 200 | grep -i ai"

# Test OpenAI connection
ssh <operator>@<production-host> "docker exec solid-backend python -c \"
import openai
openai.api_key = 'your-key'
print(openai.Model.list())
\""
```

**Common Causes:**

| Error | Solution |
|-------|----------|
| API key invalid | Check OPENAI_API_KEY or ANTHROPIC_API_KEY in `.env` |
| Rate limited | Wait, or upgrade API plan |
| Timeout | Check network, increase timeout setting |
| Context too long | KB might be too large - check token limits |

---

### 8. Payments Failing

**Symptoms:**
- Checkout fails
- "Payment declined" errors
- Webhooks not processing

**Diagnosis:**
```bash
# Check Stripe webhook logs
ssh <operator>@<production-host> "docker logs solid-backend | grep -i stripe"

# Test Stripe connection (capture-methods discovery endpoint)
curl https://api.solidnumber.com/api/v1/payments/capture-methods

# Check webhook endpoint
curl -I https://api.solidnumber.com/api/v1/webhooks/billing/stripe
```

> **⛔ CORRECTED 2026-08-29:** `/api/v1/payments/status` does not exist. The webhook path is `/api/v1/webhooks/billing/stripe` (`solid-backend/controllers/billing_webhooks.py:45,63`), not `/api/v1/webhooks/stripe` — the doc was missing the `/billing` segment.

**Common Causes:**

| Error | Solution |
|-------|----------|
| Invalid API key | Check STRIPE_SECRET_KEY in `.env` |
| Webhook signature failed | Check STRIPE_WEBHOOK_SECRET |
| Endpoint not receiving | Update webhook URL in Stripe Dashboard |
| Test vs Live mode mismatch | Run `./deploy.sh stripe status` to check, then `./deploy.sh stripe test` or `./deploy.sh stripe live` to swap |

**Fast Key Swap:** Use `./deploy.sh stripe test|live` to swap all 3 containers in ~3 minutes instead of manually editing .env files. See [SECRETS-CONFIGURATION.md](./SECRETS-CONFIGURATION.md#stripe-key-swap) for details.

---

### 9. Slow Performance

**Symptoms:**
- Pages load slowly
- API responses > 2 seconds
- Timeouts on large operations

**Diagnosis:**
```bash
# Check container resources
ssh <operator>@<production-host> "docker stats --no-stream"

# Check slow queries
ssh <operator>@<production-host> "docker exec solid-postgres psql -U solidnumber -c \"
SELECT pid, now() - pg_stat_activity.query_start AS duration, query
FROM pg_stat_activity
WHERE state = 'active'
ORDER BY duration DESC
LIMIT 5;
\""

# Check Redis memory
ssh <operator>@<production-host> "docker exec solid-redis redis-cli INFO memory"
```

**Common Causes:**

| Symptom | Solution |
|---------|----------|
| High CPU | Scale up server or optimize code |
| High memory | Restart containers, check for leaks |
| Slow queries | Add database indexes |
| Redis full | Increase maxmemory or clear cache |
| Too many connections | Implement connection pooling |

---

### 10. Local Development Issues

**Symptoms:**
- `./dev.sh` fails
- Containers won't start locally
- Can't connect to local services

**Diagnosis:**
```bash
# Check Docker is running
docker ps

# Check dev.sh logs
./dev.sh logs         # View all logs
./dev.sh logs backend # View specific service

# Check status
./dev.sh status

# Check port conflicts
lsof -i :8090
lsof -i :3000
lsof -i :5432
```

**Common Causes:**

| Error | Solution |
|-------|----------|
| Docker not running | Start Docker Desktop |
| Port in use | Kill process or change port in docker compose |
| Out of disk (Docker) | Docker Desktop → Settings → Resources → Increase |
| Network issues | `docker network prune`, restart Docker |
| M1/M2 Mac issues | Use `platform: linux/amd64` in docker compose |

---

## Error Message Reference

| Error Message | Meaning | Solution |
|--------------|---------|----------|
| `ECONNREFUSED` | Service not running | Start the service |
| `ETIMEDOUT` | Network/service unreachable | Check network, increase timeout |
| `ENOTFOUND` | DNS resolution failed | Check hostname spelling |
| `EPERM` / `EACCES` | Permission denied | Check file permissions |
| `ENOSPC` | Disk full | Free disk space |
| `OOMKilled` | Out of memory | Increase container memory |
| `connection reset` | Server closed connection | Check server logs |
| `SSL_ERROR` | Certificate issue | Check SSL config, restart Caddy |

---

## When All Else Fails

### Nuclear Option 1: Restart Everything
```bash
ssh <operator>@<production-host> "cd /root/solid && docker compose -f docker-compose.base.yml -f docker-compose.prod.yml down && docker compose -f docker-compose.base.yml -f docker-compose.prod.yml up -d"
```

### Nuclear Option 2: Full Rebuild
```bash
ssh <operator>@<production-host> "cd /root/solid && docker compose -f docker-compose.base.yml -f docker-compose.prod.yml down && docker system prune -f && docker compose -f docker-compose.base.yml -f docker-compose.prod.yml up -d --build"
```

### Nuclear Option 3: Restore from Backup
```bash
# Preferred — uses deploy.sh (includes automatic sequence sync)
./deploy.sh restore
# Prompts for backup file path, stops services, restores, syncs sequences, health checks

# Manual alternative:
ssh <operator>@<production-host> "cd /root/solid && docker compose -f docker-compose.base.yml -f docker-compose.prod.yml down"
ssh <operator>@<production-host> "docker exec solid-postgres psql -U solidnumber solid_prod < /root/backup.sql"
ssh <operator>@<production-host> "cd /root/solid && docker compose -f docker-compose.base.yml -f docker-compose.prod.yml up -d"
# CRITICAL: Always sync sequences after restore
ssh <operator>@<production-host> "docker exec solid-backend python scripts/sync_sequences.py"
```

---

## Getting Help

1. **Check logs first** - 90% of issues are in the logs
2. **Search this doc** - Most common issues are here
3. **Check known issues** - See [12-Issues-Found/known-issues.md](../12-Issues-Found/known-issues.md)
4. **Ask in Slack** - Team can help with unusual issues
5. **Document new issues** - Add to this guide if you solve something new

---

## See Also

- [00-Introduction/production-reality.md](../00-Introduction/production-reality.md) - Emergency Runbook
- [deployment.md](./deployment.md) - Deployment procedures
- [environment-configuration.md](./environment-configuration.md) - Environment variables
- [12-Issues-Found/known-issues.md](../12-Issues-Found/known-issues.md) - Known bugs

---

**Remember:** Every error is a learning opportunity. Document what you find.

## Phantom FK violations / lookups that miss rows on text keys → corrupt btree indexes

**Seen 2026-08-29 on SFO `solid_prod`.** A seeder inserting a `conversations` row and then a
`messages` row in the *same transaction* failed randomly with
`ForeignKeyViolation … Key is not present in table "conversations"`. Nothing in the
application was wrong. `amcheck` found **23 physically corrupt collatable btree indexes** —
`ix_users_email`, `conversations_pkey`, the billing customer / subscription / invoice /
payment-method ID indexes, `ix_password_reset_tokens_token`, `ix_contacts_email` and
more. Cause: the data directory was built under an older glibc than the running
`pgvector/pgvector:pg16` image (glibc 2.36) and `pg_database.datcollversion` was NULL,
so Postgres never warned. Random uuid / email keys land in mis-ordered pages, so the
same query passes one minute and fails the next.

**Symptoms that should send you here first, before touching application code:**
- FK violation for a parent row you can `SELECT` in the same transaction
- a login / billing / token lookup by email or ID returns nothing for a row that exists
- a unique index that let a duplicate through
- a count that is a "false zero" only when the planner uses an index

**Check (read-only, seconds):**
```bash
docker exec -i solid-postgres psql -U "$(docker exec solid-postgres printenv POSTGRES_USER)" -d solid_prod \
  -f - < solid-backend/scripts/sql/index_integrity_check.sql
```
It prints the recorded vs actual collation version and one `BAD … on …` line per corrupt
index, then `checked N collatable btree indexes, M corrupt`.

**Repair (online, per index):**
```sql
REINDEX INDEX CONCURRENTLY public.<index_name>;   -- one statement per BAD line, outside a transaction block
```
Re-run the check until it prints `0 corrupt`. Then record the collation version so the
next glibc change *does* warn (superuser; `ALTER DATABASE … REFRESH COLLATION VERSION`
refuses when the stored value is NULL):
```sql
UPDATE pg_database SET datcollversion = pg_database_collation_actual_version(oid)
 WHERE datname = 'solid_prod' AND datcollversion IS NULL;
```
Before rebuilding a **unique** index, confirm no duplicate slipped in
(`SET enable_indexscan=off; SET enable_bitmapscan=off;` then `GROUP BY … HAVING count(*)>1`) —
a duplicate makes the rebuild fail and needs a data decision first.

**Status:** SFO repaired 2026-08-29 (23 rebuilt, 873/873 verified clean). `datcollversion`
was still NULL at time of writing — the UPDATE above is the one open step. NYC
`<voice-database>` (Postgres 17, DO managed) checked the same day: collation version is
**recorded and matches** (`2.41` = `2.41`), so the silent-mismatch path cannot have
happened there; `bt_index_check` itself needs the `doadmin` role (the app role gets
`permission denied to create extension "amcheck"`), so run the SQL file from the DO
console as `doadmin` if you want the physical sweep too.


--- FILE: 16-Platform-Commerce/LOCAL-DEV-SETUP.md ---

---
topic: platform-commerce
keywords: [platform-commerce, local-dev, database, migrations, alembic]
code_paths:
  - solid-platform-commerce/app/main.py
  - solid-platform-commerce/app/database.py
  - solid-platform-commerce/.env
last_verified: 2026-08-29
status: current
priority: critical
owner: platform-team
---

# Platform Commerce — Local Development Setup

---

## Prerequisites

- Docker container running: `solid-platform-commerce-db` (host port 5433 → container 5432) — its own dedicated Postgres, separate from `solid-postgres`. [Corrected 2026-08-29: doc previously said Platform Commerce shared `solid-postgres` on port 5432; verified against `docker-compose.base.yml:177-183` (`container_name: solid-platform-commerce-db`) and `docker-compose.local.yml:422-426` (`ports: "5433:5432"`) — it has always had its own container in the current compose files.]
- Python 3.11+ with Platform Commerce deps installed globally or in venv

```bash
# Start the Platform Commerce DB (from repo root, base+local overlay)
cd /Users/adamcampbell/Desktop/Solid
docker compose -f docker-compose.base.yml -f docker-compose.local.yml up -d platform-commerce-db
```

---

## Database Setup

### Create Database (First Time)

[Corrected 2026-08-29: doc previously said to run `CREATE DATABASE solid_platform_commerce` inside `solid-postgres`. Verified against `docker-compose.base.yml:186-188` — the `platform-commerce-db` service sets `POSTGRES_DB: platform_commerce` (not `solid_platform_commerce`) and auto-creates it on first container start; no manual `CREATE DATABASE` step is needed.]

```bash
docker compose -f docker-compose.base.yml -f docker-compose.local.yml up -d platform-commerce-db
# DB "platform_commerce" is created automatically by the postgres:15-alpine image
```

### Known Issue: Alembic Migrations Are Broken for Fresh DBs

The Platform Commerce alembic migration chain has issues:
- `kb_sub_code` column: migration tries `VARCHAR(50)` → `Integer` cast without `USING` clause
- `status` column: migration references `sessionstatus` enum that doesn't exist yet
- Multiple column type mismatches between migration files and current models

### Workaround: Use SQLAlchemy `create_all`

Platform Commerce's `main.py` auto-creates tables on startup via `Base.metadata.create_all()`. For fresh local databases:

```bash
cd /Users/adamcampbell/Desktop/Solid/solid-platform-commerce

# Option 1: Just start the service — tables are auto-created
python3 -m uvicorn app.main:app --port 8091

# Option 2: Manual create + stamp
python3 -c "
from app.database import engine, Base
from app.models import session, order, transaction, lead, webhook, promo_code
Base.metadata.create_all(bind=engine)
print('Tables created')
"

# Then stamp alembic to mark as current
alembic stamp head
```

### Verify Tables

```bash
docker exec solid-platform-commerce-db psql -U postgres -d platform_commerce -c "\dt"
```

[Corrected 2026-08-29: doc previously listed 9 tables and pointed at `solid-postgres`/`solid_platform_commerce`. Verified `__tablename__` in every `solid-platform-commerce/app/models/*.py` file — there are now 11 tables (12 with `alembic_version`); three were added by the 2026-04-07 billing-consolidation migration (`pc_outbound_events`, `billing_accounts`, `platform_billing_events`) that postdates this doc's last verification.]

Expected 12 tables:
- `alembic_version`
- `onboarding_sessions` — `app/models/session.py:33`
- `order_line_items` — `app/models/order.py:159`
- `platform_leads` — `app/models/lead.py:39`
- `platform_orders` — `app/models/order.py:55`
- `platform_transactions` — `app/models/transaction.py:41`
- `promo_codes` — `app/models/promo_code.py:27`
- `promo_usage_logs` — `app/models/promo_code.py:123`
- `webhook_deliveries` — `app/models/webhook.py:30`
- `pc_outbound_events` — `app/models/pc_outbound_event.py:62`
- `billing_accounts` — `app/models/billing_account.py:83`
- `platform_billing_events` — `app/models/platform_billing_event.py:44`

---

## Running the Service

```bash
cd /Users/adamcampbell/Desktop/Solid/solid-platform-commerce
python3 -m uvicorn app.main:app --host 0.0.0.0 --port 8091 --reload
```

**Important:** Must run from the `solid-platform-commerce/` directory. Running from another directory will fail with "Could not import module app.main".

### Health Check

```bash
curl http://localhost:8091/health
# {"status":"healthy","service":"Solid Platform Commerce","version":"1.0.0"}
```

---

## Environment Configuration

**File:** `solid-platform-commerce/.env`

Key settings (verified against `solid-platform-commerce/.env` and `app/config.py:42` 2026-08-29 — [corrected: doc previously showed `solidnumber:solid_dev_password@localhost:5432/solid_platform_commerce`, the wrong container/port/db-name combo]):
```bash
DATABASE_URL=postgresql://postgres:postgres@localhost:5433/platform_commerce
JWT_SECRET=dev-jwt-secret-change-in-prod
SESSION_EXPIRE_HOURS=24
PAYMENT_PROCESSOR=stripe  # only valid value — the retired processor is dead (no single processor is core — see the Billing feedback in CLAUDE.md), do not use
# <PROCESSOR>_API_URL=https://<processor-sandbox-host>  # decommissioned — do not use (historical)
```
Note: `app/config.py:42`'s hardcoded fallback default still reads `.../solid_platform_commerce` (the old DB name) — this is dead code since the checked-in `.env` always overrides it with `platform_commerce`, but it means a run with no `.env` present will silently point at a nonexistent database.

---

## Full Local Stack

All three services needed for end-to-end onboarding testing:

| Service | Command | Port | Directory |
|---------|---------|------|-----------|
| Backend | `python3 -m uvicorn app:app --port 8090 --reload` | 8090 | `solid-backend/` |
| Platform Commerce | `python3 -m uvicorn app.main:app --port 8091 --reload` | 8091 | `solid-platform-commerce/` |
| Frontend | `npm run dev` | 3000 | `solid-frontend/` |

### Test E2E Flow

```bash
# Step 1: Start session
curl -s -X POST http://localhost:3000/api/onboarding/start \
  -H 'Content-Type: application/json' \
  -d '{"email":"test@example.com","full_name":"Test","company_name":"TestCo","password":"TestPass123"}'

# Step 2: Select industry (use session_token from step 1)
curl -s -X POST http://localhost:3000/api/onboarding/industry \
  -H 'Content-Type: application/json' \
  -d '{"session_token":"<TOKEN>","industry_key":"plumber","industry_name":"Plumbing","kb_sub_code":101,"mcc_code":"7251"}'

# Step 3: Select plan
curl -s -X POST http://localhost:3000/api/onboarding/plan \
  -H 'Content-Type: application/json' \
  -d '{"session_token":"<TOKEN>","plan":"professional","billing_cycle":"monthly"}'
```

**Note:** Frontend uses `plan` field which maps to `tier` in Platform Commerce. Valid tiers: `starter`, `builder`, `professional`, `enterprise`. [Verified 2026-08-29: field mapping confirmed at `solid-frontend/src/app/api/onboarding/plan/route.ts:13` (`fieldMapping: { plan: "tier" }`); tier keys confirmed against `solid-platform-commerce/app/constants/tiers.py:9,61,124,197`; endpoint paths (`/api/v1/onboarding/start`, `/industry`, `/plan`) confirmed against `solid-frontend/src/app/api/onboarding/{start,industry,plan}/route.ts` and `solid-platform-commerce/app/api/routers/onboarding.py:529`; port 8090 backend / 8091 Platform Commerce / 3000 frontend confirmed against `docker-compose.local.yml:63,56` and `solid-platform-commerce/app/main.py:83` and `solid-frontend/package.json` `dev` script.]

---

## Migration Chain Status: FIXED (Feb 5, 2026)

Migration `20260205_fix_schema_sync.py` repairs the chain. `alembic upgrade head` now works on fresh databases.

**What it fixed:**
1. `kb_sub_code` VARCHAR(50) → INTEGER (with `USING kb_sub_code::integer`)
2. `status` VARCHAR(50) → `sessionstatus` ENUM (creates type first, then alters)
3. `oauth_token_expires_at` INTEGER → BIGINT
4. 13 missing columns added (ROI, setup, business details, shipping, etc.)

All checks are idempotent — safe to run on databases created via `create_all` + `stamp head`.

[Corrected 2026-08-29: `fix_schema_sync` is no longer HEAD. Verified `revision`/`down_revision` in every file under `solid-platform-commerce/alembic/versions/` — two more migrations landed after this doc's last verification, both adding the billing-consolidation tables listed above.]

**Full chain (10 migrations):**
```
001 → 002 → 003_fix_recharge_token_length → 004_add_provisioning_status → 005_add_onboarding_security
    → add_terms_accepted_at_pc → add_oauth_fields → fix_schema_sync
    → add_stripe_fields (2026-02-20) → billing_account_and_events (2026-04-07, HEAD)
```

---

**Last Updated:** February 5, 2026 — re-verified 2026-08-29, corrections above; DB container topology, table list, and migration chain updated to match code.


--- FILE: 41-Token-Management/GAPS-AND-ROADMAP.md ---

---
topic: token-gaps-roadmap
keywords: [gaps, roadmap, TODO, missing, improvements, token-tracking, voice, SMS, auto-refill]
code_paths:
  - solid-backend/tasks/billing_tasks.py
  - solid-backend/tasks/auto_billing_cron.py
  - solid-backend/services/ai/token_gate.py
  - solid-backend/services/kb_vector_service.py
  - solid-backend/constants/pricing_model.py
  - solid-backend/constants/feature_tiers.py
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# Gaps and Roadmap — What's Missing, What's Next

> **Known gaps in the token management system and the plan to close them.**

---

## Critical Gaps (Revenue Impact)

### ~~Gap 1: kb_vector_service.py Embeddings Not Tracked~~ FIXED (2026-02-09)

**Status:** RESOLVED. `generate_embedding()` now accepts optional `company_id` and records via `token_gate.record_sync()` (upgraded from `record_to_db` on 2026-02-09). Company KB embed/search calls pass `company_id`; industry/platform calls (system-level) remain untracked.

### ~~Gap 2: Cost Matrix Discrepancy~~ FIXED (2026-02-09)

**Status:** RESOLVED. `pricing_model.py` now defines `TOKEN_OVERAGE_RATE = 0.02` ($0.02/1K tokens), matching `feature_tiers.py AI_OVERAGE_RATES`. Also fixed a latent `NameError` — `TOKEN_OVERAGE_RATE` was referenced at line 369 but never defined. Additionally:
- `TIER_PRICING` token limits aligned with `TIER_AI_BUDGETS` (were 5x lower)
- "Elite" renamed to "Enterprise" across `pricing_model.py` and `ai_usage_limits.py` (legacy alias kept)
- `ai_usage_limits.py` `TIER_INCLUDED_TOKENS` and `TIER_FEATURES` updated to match
- `OVERAGE_RATE_PER_1K` updated from $0.01 to $0.02

### ~~Gap 2b: Voice Overage Below Cost~~ FIXED (2026-02-09)

**Status:** RESOLVED. `AI_OVERAGE_RATES['voice_per_minute_cents']` was 12 ($0.12/min) — below the $0.314/min wholesale cost ((real-time voice infrastructure)). Every minute of voice overage was a $0.194 loss. Fixed to 150 ($1.50/min) — 4.8x markup, 79% margin. Also updated hardcoded value in `controllers/ai_billing.py`.

### ~~Gap 3: Auto-Refill the retired processor Charging Not Implemented~~ VERIFIED WORKING (2026-02-09)

**Status:** RESOLVED. The retired processor charging was already implemented — `daily_auto_billing()` in `auto_billing_cron.py` (line 215) processes ALL `BillingQueue` items with `status='pending'`, including `billing_type='auto_refill'` items created by `process_auto_refill()`. Full flow:
1. `process_auto_refill()` runs hourly → checks `CompanyAIBudget` thresholds → creates `BillingQueue` item
2. `daily_auto_billing()` runs daily at 9AM UTC → picks up pending items → calls `processor_adapter.charge()` with recharge_token
3. Duplicate prevention: 24h cooldown (`last_refill_at`) + checks for existing pending items for today
4. Notification: emails sent on both threshold trigger and payment success/failure

---

## High-Priority Gaps

### ~~Gap 4: Voice/SMS Overage Billing~~ PARTIALLY FIXED (2026-02-09)

**Status:** MONTHLY BILLING WIRED. `tasks/billing_tasks.py:process_ai_calling_billing()` now:
- Queries `phone_usage` table for voice minutes and SMS counts per company
- Compares against `TIER_AI_BUDGETS[tier]` allocations
- Charges overage via the retired processor [platform is processor-agnostic via the adapter registry] at `AI_OVERAGE_RATES` ($1.50/min voice, $0.05/SMS)
- Creates `BillingInvoice` + `BillingInvoiceLineItem` for each charge type

**Real-time gating DONE (2026-02-09).** ⚠️ **Corrected 2026-08-29:**
`services/voice_call_handler.py` was DELETED 2026-08-19 (9,544 lines) — the
two bullets below citing it are stale file references. CognitiveLimiter
itself is still real and still gates voice/SMS in real time
(`services/ai/cognitive_limiter.py::check_voice_budget()` /
`check_sms_budget()`, confirmed present, same Redis key scheme):
- `check_voice_budget()` — pre-flight check against `TIER_AI_BUDGETS[tier]['voice_minutes_included']` via Redis counter `monthly_voice:{company_id}:{YYYY-MM}`. Confirmed called from `workers/voice_outbound_worker.py` for outbound calls; the current inbound-call call site (successor to `voice_call_handler.py:start()`) was not pinned down in this pass — verify against `controllers/voice_engine_v2.py` / `services/voice/` before relying on the exact line.
- `sms_service.py:send()` — pre-flight check against `TIER_AI_BUDGETS[tier]['sms_included']` via Redis counter `monthly_sms:{company_id}:{YYYY-MM}` (confirmed current, line ~242). Blocks SMS if budget exceeded and overage not enabled.
- Both counters auto-expire at month boundary (TTL = seconds until 1st of next month).
- Voice minute recording now happens in `services/voice/persistence.py::_record_ai_usage()` → `CognitiveLimiter().record_usage()` — the successor to `voice_call_handler.py:_end_call()`.
- `sms_service.py:_track_usage()` increments SMS counter in Redis (confirmed current, line ~783).

### ~~Gap 5: Token Usage API Returns Mock Data~~ FIXED (2026-02-09)

**Status:** RESOLVED. All mock data removed:
- Deleted test endpoint `GET /ai-billing/usage-status/test` (returned hardcoded demo data)
- Fixed `GET /ai-billing/tokens/budget` — was `used_cents = 0` TODO, now queries `token_usage` table
- Fixed `GET /billing/payment-methods` — was returning fake card numbers (4242, 8888), now returns empty list if no real cards
- Fixed `GET /billing/overview` — monthly budget was hardcoded $100, now queries `CompanyAIBudget.max_monthly_cost_cents`
- Fixed voice plan fallback overage rates (12→150 cents/min to match `AI_OVERAGE_RATES`)
- Deleted dead `controllers/token_usage_controller.py` (referenced non-existent `TokenOrchestratorRequest` model, was never registered in app)

### ~~Gap 6: Real-Time Alert Delivery~~ FIXED (2026-02-09)

**Status:** RESOLVED. `AIUsageMonitor.check_and_send_alerts()` now:
- Creates `AIUsageAlert` rows for budget_warning (75%, 90%) and budget_exceeded (100%)
- Deduplicates: won't re-alert for the same threshold within 24 hours
- Sends email via `notification_service.send_email()` to `CompanyAIBudget.alert_emails` (JSON array or comma-separated) or falls back to company owner email
- Sends Slack webhook to `CompanyAIBudget.alert_slack_webhook` (if configured) via `httpx.post()`
- Triggered automatically from `GET /ai-billing/usage-status` endpoint

---

## Low-Priority Gaps

### ~~Gap 7: ElevenLabs Costs Not Tracked~~ N/A (2026-02-09)

**Status:** NOT APPLICABLE. ElevenLabs TTS is not implemented — `voice_ai_provider.py` raises `NotImplementedError` for the ElevenLabs provider type (line 335). All production voice uses OpenAI Realtime API (tracked via Token Gate/CognitiveLimiter in `services/voice/persistence.py` and `services/ai/cognitive_limiter.py` — corrected 2026-08-29, `voice_call_handler.py` was deleted 2026-08-19). ElevenLabs API key is configured in superadmin for subscription monitoring (`fetch_elevenlabs_usage()`) but no TTS calls are made. Will need tracking when ElevenLabs provider is implemented.

### ~~Gap 8: S3 Storage Costs Not Tracked~~ FIXED (2026-02-09)

**Status:** RESOLVED. Added `tasks/s3_usage_tracker.py` — Celery task that runs weekly (Sunday 3AM UTC) to scan S3 buckets and record per-company storage usage. Implementation:
- Lists all S3 objects, aggregates size by company_id prefix
- Records to `company_ai_budgets.storage_bytes` (new column tracked via existing model)
- Stores cost estimate at $0.023/GB/month (S3 Standard pricing)
- Logs summary to `token_usage` table with `agent_name='s3_storage'` and `channel='storage'`
- Falls back gracefully if S3 credentials unavailable

### ~~Gap 9: Batch Job company_id Threading~~ FIXED (2026-02-09)

**Status:** RESOLVED. All batch jobs now have company_id threaded and record via Token Gate:
- `auto_faq_generator.py` — uses `company_id` parameter, records via `record_sync()`
- `tasks/import_analysis.py` — threads `staged.company_id` to `identify_important_columns_gpt()`, records via `record()`
- `services/kb_ai_service.py` — both OpenAI calls now recorded via `record_sync()`
- `controllers/ada.py` — ADA chat call recorded via `record_sync()`
- `integrations/ai_kb_middleware.py` — KB middleware call recorded via `record_sync()`
- `services/ai/llm_sentiment.py` — company_id threaded to `_llm_analyze()`, recorded via `record()`
- `services/mcp_ai_bridge.py` — Grok path now recorded via `record()` (matching OpenAI/Anthropic paths)

### ~~Gap 10: Bridge.py Dual Recording~~ FIXED (2026-02-09)

**Status:** RESOLVED. `bridge.py._record_token_usage()` now delegates to `token_gate.record_sync()` instead of its own hardcoded cost calculation + DB write. Also removed the separate CognitiveLimiter recording blocks (lines 1114-1136, 1240-1262) since `record_sync()` handles both DB + Redis. Benefits:
- Consistent cost calculation using Token Gate's model-based lookup (not hardcoded Sonnet/GPT-4o rates)
- Single recording path (no more DB with one cost + Redis with a different cost)
- CognitiveLimiter sees bridge.py calls through the same path as all other callers

---

## Roadmap

| Priority | Gap | Work | Status |
|----------|-----|------|--------|
| P0 | Cost matrix standardization (#2) | Align token tables, fix overage rates, rename elite→enterprise | DONE |
| P0 | Voice overage below cost (#2b) | $0.12→$1.50/min (was losing $0.194/min) | DONE |
| P0 | kb_vector_service embeddings (#1) | Thread company_id, add recording | DONE |
| P0 | Token billing pipeline (#2c) | Tier-aware `_calculate_token_cost()`, invoice line items | DONE |
| P0 | Voice/SMS billing pipeline (#4) | Monthly overage billing from `phone_usage` | DONE |
| P0 | Auto-refill dedup (#3b) | Remove duplicate `process_auto_refill()` from billing_tasks.py | DONE |
| P1 | ~~Auto-refill the retired processor charging (#3)~~ | ~~Wire BillingQueue → processor charge~~ (was already working via daily_auto_billing) | DONE |
| P1 | ~~Voice/SMS real-time gating (#4b)~~ | ~~Pre-flight budget check in voice_call_handler + sms_service~~ | DONE |
| P1 | ~~Token usage API real data (#5)~~ | ~~Remove mock data, query real tables~~ | DONE |
| P2 | ~~Alert delivery (#6)~~ | ~~Wire to notification service + Slack~~ | DONE |
| P2 | ~~Batch job threading (#9)~~ | ~~Add company_id to Celery tasks~~ | DONE |
| P2 | ~~Bridge.py dedup (#10)~~ | ~~Delegate to token_gate.record_sync~~ | DONE |
| P3 | ~~ElevenLabs tracking (#7)~~ | N/A — provider not implemented yet | N/A |
| P3 | ~~S3 storage tracking (#8)~~ | ~~Weekly scan task~~ | DONE |
| — | ~~Gemini hybrid billing (#11)~~ | N/A — Gemini is just a connected tool, doesn't affect our billing | REMOVED |

---

## Verification Checklist (Post-Deploy)

Token Gate deployed to production 2026-02-09.

- [x] `token_usage` table shows rows for chat, email, KB, content generation
- [x] Redis keys exist: `redis-cli KEYS "monthly_tokens:*"`
- [ ] Budget exceeded test: Set company budget to 1 token, verify next call blocked
- [ ] Provider coverage: All 3 providers (anthropic, openai, xai) appear in `model_provider` column
- [ ] Agent coverage: Multiple agent_name values appear (sage, content_gen, etc.)
- [ ] No double recording: Chat calls should have ONE token_usage row, not two
- [x] System calls: company_id=0 calls now skipped (guard in `token_gate.record_to_db()`)
- [x] All 24 `record_to_db` call sites upgraded to `record_sync` (DB + Redis) — CognitiveLimiter now sees ALL costs
- [x] 8 previously untracked API call sites now instrumented (Phase 1 of cost tracking sprint)
- [ ] Performance: Response times not degraded (Token Gate adds <5ms overhead)

---

*See also: `FILE-INVENTORY.md` for which files are/aren't instrumented.*
*See also: `SAFETY-AND-LIMITS.md` for safety-specific gaps.*

*Maintained by: Platform Team*


--- FILE: 00-Introduction/DOCUMENTATION-INTELLIGENCE-SYSTEM.md ---

---
topic: introduction
keywords: [introduction, adding, admin, architecture, auth, auto-applied, automatic, capabilities, cases]
code_paths:
  - solid-backend/services/api_intelligence.py
  - solid-backend/services/documentation_intelligence.py
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

> **Verified 2026-08-29, live-code defect found (reported, not fixed):** the
> classification architecture described here is real —
> `services/documentation_intelligence.py::FOLDER_DEFAULTS` (line ~106) does
> implement PUBLIC/INTERNAL/PRIVATE-by-folder with a safe INTERNAL fallback
> (`_get_classification()`, line ~242). But `FOLDER_DEFAULTS`' own keys are
> stale: it still keys off `10-AI-Agents`, `08-Sales`, `16-Summary`, and
> `05-Public-Site`, none of which exist as folders anymore (renamed to
> `03-AI-Systems` [agents already classified separately], `27-Sales-Materials`,
> — no folder now serves the old `16-Summary` role — and `26-Public-Site`
> respectively), and it never lists `27-Sales-Materials`, `26-Public-Site`, or
> `16-Platform-Commerce` under their real numbers. Net effect: content in
> `26-Public-Site/` and `27-Sales-Materials/` currently falls through to the
> INTERNAL fallback instead of being classified PUBLIC as intended — a
> functional bug (fails safe/closed, not a security leak, but breaks the
> public-exposure feature for those folders). Not fixed as part of this doc
> pass.

# Documentation Intelligence System

> **Purpose:** Make Solid# documentation AI-queryable while protecting sensitive content
> **Location:** `services/documentation_intelligence.py`, `services/api_intelligence.py`
> **Last Updated:** January 12, 2026

---

## Overview

The Documentation Intelligence System turns the Owners Manual and API documentation into an intelligent layer that:

1. **External AI** can query "What can Solid do?"
2. **Internal AI** (Devon, ADA) can search implementation details
3. **Investors/Buyers** see comprehensive documentation
4. **Private content** (investment, security, strategy) is never exposed

---

## Architecture

```
┌─────────────────────────────────────────────────────────────────┐
│         OWNERS MANUAL / API ENDPOINTS (counts below are stale — │
│         see Owners-Manual/PLATFORM-METRICS.md for current counts)│
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│              CLASSIFICATION ENGINE (Convention-Based)            │
│                                                                  │
│   Folder/Path Defaults     →    PUBLIC / INTERNAL / PRIVATE     │
│   File/Endpoint Overrides  →    Exception handling              │
└─────────────────────────────────────────────────────────────────┘
                              │
          ┌───────────────────┼───────────────────┐
          ▼                   ▼                   ▼
    ┌──────────┐        ┌──────────┐        ┌──────────┐
    │  PUBLIC  │        │ INTERNAL │        │ PRIVATE  │
    │          │        │          │        │          │
    │ External │        │ Devon    │        │ NEVER    │
    │ LLMs     │        │ ADA      │        │ EXPOSED  │
    │ Investors│        │ Devs     │        │          │
    │ Sales    │        │          │        │          │
    └──────────┘        └──────────┘        └──────────┘
```

---

## Classification Levels

| Level | Who Sees It | What's Included |
|-------|-------------|-----------------|
| **PUBLIC** | External LLMs, investors, sales | Features, capabilities, what Solid does |
| **INTERNAL** | Devon, ADA, developers | Implementation, architecture, how it works |
| **PRIVATE** | Never exposed | Investment, security, strategy, legal |

---

## Documentation Classification

### Folder Defaults (Auto-Applied)

New files automatically inherit classification from their folder:

```python
# PUBLIC folders - safe for external consumption
"09-Core-Innovations": PUBLIC   # Features & capabilities
"10-AI-Agents": PUBLIC          # Agent descriptions
"08-Sales": PUBLIC              # Sales materials
"16-Summary": PUBLIC            # Platform overview

# INTERNAL folders - for developers
"01-Architecture": INTERNAL     # System design
"02-Backend": INTERNAL          # API implementation
"06-Operations": INTERNAL       # DevOps

# PRIVATE folders - never exposed
"17-Investment": PRIVATE        # Fundraising
"14-Security": PRIVATE          # Security policies
"18-Strategy-2026": PRIVATE     # Future roadmap
"22-Licensing": PRIVATE         # Pricing models
```

### File Overrides

Exceptions to folder defaults:

```python
# Make internal files PUBLIC
"03-AI-Systems/AGENT-REGISTRY-MAP.md": PUBLIC

# Make files PRIVATE (sensitive)
"06-Operations/secrets-configuration.md": PRIVATE
```

---

## API Classification

### Path Defaults

```python
# PUBLIC - External API consumers
"/api/v1/public/": PUBLIC
"/api/v1/products": PUBLIC
"/api/v1/orders": PUBLIC
"/api/v1/payments": PUBLIC

# INTERNAL - Admin tools
"/api/v1/admin/": INTERNAL
"/api/v1/settings": INTERNAL

# PRIVATE - Never exposed
"/api/v1/superadmin/": PRIVATE
"/api/v1/security/": PRIVATE
```

---

## MCP Tools

### For External LLMs ("What can Solid do?")

```python
# List all capabilities
solid.capabilities.list(category=None)

# Search capabilities
solid.capabilities.search("payment processing")

# Get categories
solid.capabilities.categories()

# Export full manifest
solid.capabilities.export()
```

### For Internal AI (Devon, ADA)

```python
# Search all documentation
devon.docs.search("api endpoints")

# Get specific document
devon.docs.get("02-Backend/api-endpoints.md")

# Documentation stats
devon.docs.stats()

# Trigger rescan
devon.docs.scan(force=True)
```

---

## API Endpoints

### Public (No Auth Required)

```
GET /api/v1/public/capabilities
    → List all capabilities

GET /api/v1/public/capabilities/search?q=payment
    → Search capabilities

GET /api/v1/public/capabilities/categories
    → List categories

GET /api/v1/public/capabilities/manifest
    → Export full manifest (JSON)
```

### Internal (Auth Required)

```
GET /api/v1/docs/search?q=deployment
    → Search internal docs

GET /api/v1/docs/document/{path}
    → Get specific document

GET /api/v1/docs/stats
    → Documentation statistics

POST /api/v1/docs/scan
    → Trigger rescan
```

**(Corrected 2026-08-29: none of the eight HTTP routes above exist.** There is no `api/routers/documentation_intelligence.py` and `app.py` mounts no `/api/v1/public/capabilities*` or `/api/v1/docs/*` router. A real, differently-shaped `controllers/capabilities.py` is mounted at `/api/v1/capabilities/*` (`app.py:1399-1400`) with routes `GET/POST /api/v1/capabilities`, `/stats`, `/categories`, `/questions`, `/questions/count`, `/questions/{id}/resolve`, `/clone-templates`, `/{capability_id}`, `/admin/templates` — but that controller is unrelated to this doc-intelligence system (it's the sandbox/onboarding capabilities API). The functionality this section describes (search/list/get/stats/scan) is real, but it is exposed only as **MCP tool functions** in `mcp/tools/documentation.py` — `solid__capabilities__list`, `solid__capabilities__search`, `solid__capabilities__categories`, `solid__export__capabilities`, `devon__docs__search`, `devon__docs__get`, `devon__docs__stats`, `devon__docs__scan`, `devon__docs__new_files` — matching the "MCP Tools" section above, not this "API Endpoints" section. There is no plain-HTTP surface for it.)

---

## Celery Jobs

### Schedule

| Job | Schedule | Purpose |
|-----|----------|---------|
| `sync_documentation` | Daily 3:00 AM | Full rescan |
| `detect_new_docs` | Every 6 hours | Find new files |
| `export_capabilities` | Daily 4:00 AM | Generate public manifest |

### Manual Run

```bash
# Full sync
python -m jobs.documentation_sync --sync

# Detect new files
python -m jobs.documentation_sync --detect

# Export capabilities
python -m jobs.documentation_sync --export

# Check status
python -m jobs.documentation_sync --status
```

---

## Adding New Documentation

### Automatic Classification

1. Add file to appropriate folder
2. Classification is automatic based on folder
3. Sync job picks it up within 6 hours

### Override Classification

Edit `services/documentation_intelligence.py`:

```python
FILE_OVERRIDES = {
    "path/to/file.md": Classification.PUBLIC,  # or INTERNAL, PRIVATE
}
```

---

## Use Cases

### External LLM Researching Solid

```
LLM: "What can Solid do for payments?"

→ Calls: solid.capabilities.search("payments")
→ Returns: Payment features, processing, invoicing, etc.
→ Does NOT return: Implementation details, pricing strategy
```

### Investor Due Diligence

```
Investor visits: /api/v1/public/capabilities/manifest

→ Gets: Complete JSON of all public capabilities
→ Sees: comprehensive feature list, 32 AI agents (Corrected 2026-08-29: doc count "469" is stale — see Owners-Manual/PLATFORM-METRICS.md for the current derived count; the "32 AI agents" figure itself checks out against PLATFORM-METRICS.md)
→ Does NOT see: Valuation, fundraising, security vulnerabilities
```

### Devon Debugging

```
Devon: "How does the payment webhook work?"

→ Calls: devon.docs.search("payment webhook")
→ Returns: Implementation docs, API specs, code patterns
→ Has access to: PUBLIC + INTERNAL docs
```

---

## Statistics (Current)

| Metric | Count |
|--------|-------|
| Total Documentation Files | 469 |
| Total Lines | 237,919 |
| Public Capabilities | ~80 files |
| Internal Documentation | ~300 files |
| Private Content | ~90 files |

**(Corrected 2026-08-29: this table is stale.** Per `Owners-Manual/PLATFORM-METRICS.md` (auto-generated 2026-08-29 by `scripts/platform_metrics.py`): **1,909** documentation files across Owners-Manual + Solid-Intelligence, in **97** doc sections — not 469 files. A raw `find Owners-Manual -iname "*.md" | wc -l` on this repo returns **1,880**. The PUBLIC/INTERNAL/PRIVATE per-classification breakdown (~80/~300/~90) was not re-derived — no script currently computes it, so those three sub-counts are unverified as of 2026-08-29. Do not hand-type a new total here; point readers to PLATFORM-METRICS.md instead.)

---

## Files

```
solid-backend/
├── services/
│   ├── documentation_intelligence.py  # Main engine
│   └── api_intelligence.py           # API classification
├── mcp/tools/
│   └── documentation.py              # MCP tools (the real HTTP-free surface — see API Endpoints correction above)
└── jobs/
    └── documentation_sync.py         # Celery jobs

Owners-Manual/
└── 00-Introduction/
    ├── DOCUMENTATION-INTELLIGENCE.md  # Classification map
    └── DOCUMENTATION-INTELLIGENCE-SYSTEM.md  # This file
```

---

*This system makes your documentation your competitive advantage - AI can understand everything, but only what you choose to expose.*


--- FILE: 00-Introduction/DOCUMENTATION-INTELLIGENCE.md ---

---
topic: introduction
keywords: [introduction, access, ai-systems, architecture, build, business-logic, classification, content, creation]
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

<!-- Re-verified 2026-08-29: this doc is a planning/proposal doc that predates the actual build and disagrees with it on mechanism — its "Proposed Architecture" and "Phase 1: Manifest Creation" describe a `manifest.json`-driven classifier, but the real implementation (`services/documentation_intelligence.py::FOLDER_DEFAULTS`, verified against source) is a convention-based Python dict with no manifest.json anywhere in the repo. Its "MCP Tools to Build" section and unchecked "Next Steps" checklist are also stale: those MCP tools are already built — `mcp/tools/documentation.py` implements `solid__capabilities__list/search/categories`, `devon__docs__search/get/stats/scan/new_files`, `solid__export__capabilities` — matching this doc's proposed tool names closely. See `DOCUMENTATION-INTELLIGENCE-SYSTEM.md` for the as-built system; treat this file as historical intent, not current status. -->

# Owners Manual Intelligence Map

> **Purpose:** Make documentation AI-queryable while protecting sensitive content
> **Created:** January 12, 2026
> **Total:** 469 files, 237,919 lines (Corrected 2026-08-29: stale. Per `Owners-Manual/PLATFORM-METRICS.md`, auto-generated 2026-08-29: **1,909** documentation files across Owners-Manual + Solid-Intelligence in **97** sections; `find Owners-Manual -iname "*.md" | wc -l` returns **1,880** on this repo alone. Line count not re-derived/unverified. Every per-folder file count in the tables below is likewise stale and was not individually re-counted in this pass — treat them as directional, not exact.)

---

## The Vision

Turn the Owners Manual into an **intelligent layer** that:
1. **Internal AI** (Devon, ADA) can query everything
2. **External AI/LLMs** can query "What can Solid do?" (public capabilities)
3. **Investors/Buyers** see comprehensive documentation (curated access)
4. **Hackers** see nothing useful (private content protected)

---

## Content Classification

### PUBLIC (Safe for external AI, investors, documentation)
Capabilities, features, what Solid does - no implementation secrets

| Folder | Files | Purpose |
|--------|-------|---------|
| `09-Core-Innovations/` | 65+ | Feature capabilities, what makes Solid unique |
| `03-AI-Systems/` (partial) | ~10 | AI capabilities overview |
| `07-Business-Logic/` (partial) | ~5 | Business features |
| `00-Introduction/SOLID-PLATFORM-OVERVIEW.md` | 1 | Platform overview (corrected 2026-08-29: folder `16-Summary/` no longer exists — `16` is now `16-Platform-Commerce/`) |

**Examples:**
- `complete-feature-inventory.md` - All features
- `ai-agents-ecosystem.md` - 32 AI agents
- `payment-suite.md` - Payment features
- `food-fight.md` - Onboarding magic

### INTERNAL (For Devon, ADA, developers only)
Implementation details, architecture, how things work

| Folder | Files | Purpose |
|--------|-------|---------|
| `01-Architecture/` | 6 | System design |
| `02-Backend/` | 9 | API, database |
| `04-Frontend/` | 11 | UI architecture |
| `05-Data/` | 5 | Data schemas |
| `06-Operations/` | 24 | Deployment, DevOps |
| `11-Platform-Architecture/` | 5 | Infrastructure |
| `13-Testing/` | 7 | QA procedures |
| `19-Onboarding/` | 28 | Onboarding flow details |

**Examples:**
- `api-endpoints.md` - All routes (Corrected 2026-08-29: was "1,342 routes" — stale; current derived count is 2,242 per Owners-Manual/PLATFORM-METRICS.md)
- `DATABASE_SCHEMA_MAP.md` - Full schema
- `deployment.md` - How to deploy
- `TROUBLESHOOTING.md` - Debug procedures

### PRIVATE (Never exposed - internal eyes only)
Strategy, security vulnerabilities, investment, competitive intelligence

| Folder | Files | Purpose |
|--------|-------|---------|
| `14-Security/` | 12 | Security policies, incident response |
| `17-Investment/` | 21 | Fundraising, valuations, investor materials |
| `18-Strategy-2026/` | 29 | Future roadmap, competitive strategy |
| `22-Licensing/` | 23 | Pricing models, partner deals |
| `23-Legal/` | 20 | Contracts, compliance |
| `12-Issues-Found/` | 6 | Known vulnerabilities |
| `00-CRITICAL/` | 1 | Security critical |

**Examples:**
- `INVESTMENT-MEMO.md` - Fundraising details
- `VALUATION-CALCULATOR.md` - Company valuation
- `COMPETITIVE-WARFARE.md` - Competitive strategy
- `INCIDENT-RESPONSE-PLAN.md` - Security procedures
- `known-issues.md` - Vulnerabilities

---

## Proposed Architecture

```
┌─────────────────────────────────────────────────────────────────┐
│                    OWNERS MANUAL (469 files)                     │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    CLASSIFICATION ENGINE                         │
│  manifest.json: { file: path, classification: public|internal|private }
└─────────────────────────────────────────────────────────────────┘
                              │
          ┌───────────────────┼───────────────────┐
          ▼                   ▼                   ▼
    ┌──────────┐        ┌──────────┐        ┌──────────┐
    │  PUBLIC  │        │ INTERNAL │        │ PRIVATE  │
    │    KB    │        │    KB    │        │  (never  │
    │          │        │          │        │ indexed) │
    └────┬─────┘        └────┬─────┘        └──────────┘
         │                   │
         ▼                   ▼
    ┌──────────┐        ┌──────────┐
    │ External │        │  Devon   │
    │ LLMs     │        │  ADA     │
    │ Sales    │        │ Internal │
    │ Investors│        │ AI agents│
    └──────────┘        └──────────┘
```

---

## MCP Tools to Build

### For External Queries (Public)
```python
# "What can Solid do?"
solid.capabilities.search(query: str) → List[Capability]
solid.capabilities.list(category: str) → List[Capability]
solid.capabilities.get(capability_id: str) → CapabilityDetail
```

### For Internal AI (Public + Internal)
```python
# Devon/ADA full access
devon.docs.search(query: str) → List[Document]
devon.docs.get(path: str) → Document
devon.docs.categories() → List[Category]
```

### For Sales/Investors (Curated Public)
```python
# Generate investor-ready summaries
solid.investor.overview() → PlatformOverview
solid.investor.capabilities(category: str) → List[Capability]
solid.investor.metrics() → PlatformMetrics
```

---

## Folder Classification Map

| Folder | Classification | Reason |
|--------|---------------|--------|
| `00-Introduction/` | INTERNAL | Setup procedures |
| `00-CRITICAL/` | PRIVATE | Security critical |
| `01-Architecture/` | INTERNAL | Implementation |
| `02-Backend/` | INTERNAL | Implementation |
| `03-AI-Systems/` | MIXED | Some public capabilities |
| `04-Frontend/` | INTERNAL | Implementation |
| `05-Data/` | INTERNAL | Schema details |
| `06-Operations/` | INTERNAL | DevOps |
| `07-Business-Logic/` | MIXED | Some features public |
| `08-Communication-Systems/` | INTERNAL | Implementation |
| `09-Core-Innovations/` | PUBLIC | Features & capabilities |
| `10-Billing/` | INTERNAL | Billing implementation |
| `11-Platform-Architecture/` | INTERNAL | Infrastructure |
| `12-Issues-Found/` | PRIVATE | Vulnerabilities |
| `13-Testing/` | INTERNAL | QA procedures |
| `14-Security/` | PRIVATE | Security policies |
| `15-AI-Sandbox-Engine/` | INTERNAL | Dev tools |
| `16-Platform-Commerce/` | INTERNAL | Billing implementation |
| `17-Investment/` | PRIVATE | Fundraising |
| `18-Strategy-2026/` | PRIVATE | Future strategy |
| `19-Onboarding/` | INTERNAL | Implementation |
| `20-Super-Admin/` | INTERNAL | Admin tools |
| `21-Solid-Offers/` | PUBLIC | Marketing |
| `22-Licensing/` | PRIVATE | Pricing/deals |
| `23-Legal/` | PRIVATE | Contracts |
| `24-Pages-Reference/` | INTERNAL | UI reference |
| `25-Platform-Reality/` | INTERNAL | Validation |
| `26-Public-Site/` | PUBLIC | Public features |
| `27-Sales-Materials/` | PUBLIC | Sales materials |
| `98-Backlog/` | INTERNAL | Backlog |

(Corrected 2026-08-29: the numbered folders drifted since this table was
written — `05-Public-Site/`, `08-Sales/`, `10-AI-Agents/`, and `16-Summary/`
no longer exist under those numbers; the real current folders are
`26-Public-Site/`, `27-Sales-Materials/`, `03-AI-Systems/` [already listed
above as MIXED — agent capability docs live there, there is no separate
AI-Agents folder], and `16-Platform-Commerce/`. `99-Backlog/` is now
`98-Backlog/` — folder `99` is `99-Active-Sprints/`. Verify any specific
folder number against `ls Owners-Manual/` before relying on it; numbers
drift and this doc is not authoritative over the live directory.)

---

## File-Level Exceptions

Some folders are MIXED - specific files need individual classification:

### 03-AI-Systems/ (MIXED)
| File | Classification |
|------|---------------|
| `00-INDEX.md` | PUBLIC |
| `AGENT-REGISTRY-MAP.md` | PUBLIC |
| `AI-INFRASTRUCTURE.md` | INTERNAL |
| `SECURITY-HARDENING.md` | PRIVATE |
| `LLM-PROVIDER-MAP.md` | PRIVATE |

### 07-Business-Logic/ (MIXED)
| File | Classification |
|------|---------------|
| `knowledge-bases.md` | PUBLIC |
| `ROLE-BASED-ACCESS-CONTROL.md` | INTERNAL |
| `PRICING_STRATEGY_GROWTH_OPTIMIZED.md` | PRIVATE |

---

## Statistics

| Classification | Folders | Est. Files | Purpose |
|---------------|---------|------------|---------|
| PUBLIC | 5 | ~80 | External AI, investors |
| INTERNAL | 15 | ~300 | Devon, ADA, developers |
| PRIVATE | 10 | ~90 | Never exposed |

---

## Implementation Plan

### Phase 1: Manifest Creation
Create `owners-manual-manifest.json`:
```json
{
  "files": [
    {
      "path": "09-Core-Innovations/food-fight.md",
      "classification": "public",
      "category": "onboarding",
      "keywords": ["agents", "onboarding", "automation"]
    }
  ]
}
```

### Phase 2: KB Ingestion
- Ingest PUBLIC files into platform KB (`solid_number` namespace)
- Ingest INTERNAL files into separate KB (`solid_internal` namespace)
- PRIVATE files never ingested

### Phase 3: MCP Tools
- `solid.capabilities.*` - Public queries
- `devon.docs.*` - Internal queries
- `solid.investor.*` - Curated investor view

### Phase 4: Export Engine
- Generate `solid-capabilities.json` from PUBLIC content
- Auto-update on documentation changes
- Serve via API endpoint

---

## Next Steps

1. [ ] Create classification manifest (JSON)
2. [ ] Build ingestion script
3. [ ] Create MCP tools
4. [ ] Test external queries
5. [ ] Set up auto-sync

---

*This makes your documentation your competitive advantage - AI can understand everything, but only what you choose to expose.*


--- FILE: 00-Introduction/DOCUMENTATION-MAP.md ---

---
topic: introduction
keywords: [introduction, adding, agent, agents, backend, case, code, configuration, conventions]
code_paths:
last_verified: 2026-01-22
status: current
priority: high
owner: platform-team
---

# Solid# Documentation Map

> Visual guide to navigating the Owner's Manual for developers, AI agents, and bug fixing.

**Last Updated:** December 13, 2025

> ⚠️ **PARTIALLY STALE (checked 2026-08-29, `last_verified` intentionally not
> bumped):** the numbered folders below drifted since December 2025 and this
> doc was not kept in sync — do NOT trust folder numbers here without
> checking `ls Owners-Manual/` yourself. Confirmed wrong in the table below:
> `05-Public-Site/` no longer exists (real: `26-Public-Site/`), `08-Sales/`
> no longer exists (real: `27-Sales-Materials/`), `10-AI-Agents/` does not
> exist as its own folder (agent docs live in `03-AI-Systems/`), and `05-Data/`
> and `16-Platform-Commerce/` are missing from this table entirely. The
> full ASCII tree diagrams further down in this file were NOT individually
> re-verified line-by-line as part of this pass — treat every folder number
> in this document as unconfirmed until checked against the live directory.
>
> **Additional spot-checks (2026-08-29):** several specific file references in
> this doc are also broken, not just the folder numbers. `09-Core-Innovations/
> food-fight.md` does not exist anywhere — the file lives at
> `35-Food-Team/FOOD-FIGHT.md` (its "85 agents, 6 phases" content was not
> independently re-verified). `09-Core-Innovations/MCP-INTEGRATION.md` and
> `09-Core-Innovations/AI-COST-INTELLIGENCE.md` are actually in
> `03-AI-Systems/`, and `09-Core-Innovations/AI-SECURITY-FRAMEWORK.md` is
> actually in `14-Security/` — none of the four are in 09-Core-Innovations as
> this doc's tables claim. The "655 tools" figure for the MCP server does
> check out against `Owners-Manual/PLATFORM-METRICS.md` (655 MCP Tools). The
> "1,342 API routes" figure does not — current derived count is 2,242 per
> PLATFORM-METRICS.md; do not hand-type a replacement number here, point to
> that file instead.

---

## How This Documentation Works

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                         DOCUMENTATION ARCHITECTURE                               │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│   The Owners Manual follows a LAYERED structure:                                │
│                                                                                  │
│   ┌─────────────────────────────────────────────────────────────────────────┐  │
│   │  LAYER 1: ENTRY POINTS                                                   │  │
│   │  ├── README.md              - Master index                              │  │
│   │  ├── production-reality.md  - IPs, URLs, ports, commands                │  │
│   │  └── DOCUMENTATION-MAP.md   - THIS FILE (navigation guide)              │  │
│   └─────────────────────────────────────────────────────────────────────────┘  │
│                               │                                                  │
│                               ▼                                                  │
│   ┌─────────────────────────────────────────────────────────────────────────┐  │
│   │  LAYER 2: ARCHITECTURE (How it all fits together)                       │  │
│   │  ├── 01-Architecture/system-overview.md  - THE MASTER REFERENCE         │  │
│   │  ├── 01-Architecture/tech-stack.md       - Technologies used            │  │
│   │  └── 01-Architecture/multi-tenancy.md    - Data isolation               │  │
│   └─────────────────────────────────────────────────────────────────────────┘  │
│                               │                                                  │
│                               ▼                                                  │
│   ┌─────────────────────────────────────────────────────────────────────────┐  │
│   │  LAYER 3: DOMAIN DOCUMENTATION (Deep dives by area)                     │  │
│   │  ├── 02-Backend/         - API, database, middleware                    │  │
│   │  ├── 03-AI-Systems/      - AI infrastructure, chat, MCP                 │  │
│   │  ├── 04-Frontend/        - Next.js, components                          │  │
│   │  ├── 05-Public-Site/     - MCP server, AI indexing                      │  │
│   │  ├── 06-Operations/      - Deployment, monitoring, config               │  │
│   │  └── 07-Business-Logic/  - Onboarding, knowledge bases                  │  │
│   └─────────────────────────────────────────────────────────────────────────┘  │
│                               │                                                  │
│                               ▼                                                  │
│   ┌─────────────────────────────────────────────────────────────────────────┐  │
│   │  LAYER 4: INNOVATIONS (What makes Solid# unique)                        │  │
│   │  └── 09-Core-Innovations/ - 65+ innovation documents                    │  │
│   │      ├── CUSTOMER-LEARNING-ARCHITECTURE.md                              │  │
│   │      ├── MCP-INTEGRATION.md                                             │  │
│   │      ├── PLATFORM-MODES.md                                              │  │
│   │      └── ... (see 00-INDEX.md for full list)                           │  │
│   └─────────────────────────────────────────────────────────────────────────┘  │
│                               │                                                  │
│                               ▼                                                  │
│   ┌─────────────────────────────────────────────────────────────────────────┐  │
│   │  LAYER 5: SPECIALIZED (By audience/purpose)                             │  │
│   │  ├── 10-AI-Agents/       - Agent registry, capabilities                 │  │
│   │  ├── 11-Platform-Architecture/ - Microservices                         │  │
│   │  ├── 12-Issues-Found/    - Known issues, tech debt                      │  │
│   │  ├── 13-Testing/         - Test strategies                              │  │
│   │  ├── 14-Security/        - Security documentation                       │  │
│   │  ├── 15-AI-Sandbox-Engine/ - Sandbox, dev tiers                        │  │
│   │  └── 17-Investment/      - Investor materials                           │  │
│   └─────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Document Relationships Flow

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                         DOCUMENT RELATIONSHIP MAP                                │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│                        ┌─────────────────────┐                                  │
│                        │   system-overview   │ ◄── THE HUB                      │
│                        │    (MASTER REF)     │                                  │
│                        └──────────┬──────────┘                                  │
│                                   │                                              │
│         ┌─────────────────────────┼─────────────────────────┐                   │
│         │                         │                         │                   │
│         ▼                         ▼                         ▼                   │
│  ┌─────────────┐          ┌─────────────┐          ┌─────────────┐             │
│  │ tech-stack  │          │multi-tenancy│          │  database   │             │
│  │ (how built) │          │(isolation)  │          │  (schema)   │             │
│  └──────┬──────┘          └──────┬──────┘          └──────┬──────┘             │
│         │                        │                        │                     │
│         └────────────────────────┼────────────────────────┘                     │
│                                  │                                              │
│                                  ▼                                              │
│  ┌───────────────────────────────────────────────────────────────────────────┐ │
│  │                        DOMAIN DOCUMENTATION                                │ │
│  │                                                                            │ │
│  │  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐                │ │
│  │  │   Backend    │◄──►│  AI Systems  │◄──►│   Frontend   │                │ │
│  │  │ api-endpoints│    │chat-action   │    │ app-structure│                │ │
│  │  │ database     │    │mcp-chat      │    │              │                │ │
│  │  └──────┬───────┘    └──────┬───────┘    └──────────────┘                │ │
│  │         │                   │                                             │ │
│  │         └───────────────────┼─────────────────────────────────────────┐  │ │
│  │                             │                                          │  │ │
│  │                             ▼                                          │  │ │
│  │  ┌──────────────────────────────────────────────────────────────────┐ │  │ │
│  │  │                    CORE INNOVATIONS                               │ │  │ │
│  │  │                                                                   │ │  │ │
│  │  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐           │ │  │ │
│  │  │  │  Customer    │  │    MCP       │  │   Agent      │           │ │  │ │
│  │  │  │  Learning    │  │ Integration  │  │   Chains     │           │ │  │ │
│  │  │  └──────────────┘  └──────────────┘  └──────────────┘           │ │  │ │
│  │  │         │                 │                 │                    │ │  │ │
│  │  │         └─────────────────┴─────────────────┘                    │ │  │ │
│  │  │                           │                                      │ │  │ │
│  │  │                           ▼                                      │ │  │ │
│  │  │              ┌────────────────────────┐                         │ │  │ │
│  │  │              │   MCP-Tools/ folder    │                         │ │  │ │
│  │  │              │  (individual tool docs)│                         │ │  │ │
│  │  │              └────────────────────────┘                         │ │  │ │
│  │  └──────────────────────────────────────────────────────────────────┘ │  │ │
│  │                                                                        │  │ │
│  └────────────────────────────────────────────────────────────────────────┘  │ │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Reading Paths by Use Case

### 1. New Developer Onboarding
```
START
  │
  ▼
┌─────────────────────────────┐
│ 00-Introduction/            │
│ production-reality.md       │  ← IPs, URLs, ports, how to run locally
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ 01-Architecture/            │
│ system-overview.md          │  ← Understand the whole system
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ 01-Architecture/            │
│ multi-tenancy.md            │  ← CRITICAL: company_id EVERYWHERE
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ 06-Operations/              │
│ DATABASE_SCHEMA_MAP.md      │  ← Understand the data model
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ 09-Core-Innovations/        │
│ 00-INDEX.md                 │  ← Browse innovations
└─────────────────────────────┘
```

### 2. Bug Fixing / Debugging
```
START: Identify the affected area
  │
  ├── Backend issue?
  │   └── 02-Backend/api-endpoints.md → Find the endpoint
  │       └── 02-Backend/er-diagram.md → Understand related tables
  │           └── 06-Operations/TROUBLESHOOTING.md → Common fixes
  │
  ├── AI issue?
  │   └── 03-AI-Systems/00-INDEX.md → Find relevant AI system
  │       └── 09-Core-Innovations/AI-COST-INTELLIGENCE.md (if cost)
  │       └── 09-Core-Innovations/AI-SECURITY-FRAMEWORK.md (if security)
  │       └── 09-Core-Innovations/CUSTOMER-LEARNING-ARCHITECTURE.md (if customer KB)
  │
  ├── Frontend issue?
  │   └── 04-Frontend/app-structure.md → Component location
  │       └── 04-Frontend/PAGE-INDEX.md → 287 pages documented
  │
  ├── Deployment issue?
  │   └── 06-Operations/deployment.md
  │       └── 06-Operations/TROUBLESHOOTING.md
  │       └── 06-Operations/LOCAL_VS_PRODUCTION_MAP.md
  │
  └── Known issue?
      └── 12-Issues-Found/known-issues.md ← CHECK HERE FIRST
```

### 3. Adding a New Feature
```
START
  │
  ▼
┌─────────────────────────────┐
│ Check if documented:        │
│ 09-Core-Innovations/        │
│ complete-feature-inventory  │  ← Does feature already exist?
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ Understand the pattern:     │
│ 01-Architecture/            │
│ system-overview.md          │  ← How similar features work
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ Check multi-tenancy:        │
│ 01-Architecture/            │
│ multi-tenancy.md            │  ← MUST filter by company_id
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ Database changes?           │
│ 02-Backend/                 │
│ database-migrations.md      │  ← How to add migrations
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ AI integration?             │
│ 09-Core-Innovations/        │
│ MCP-INTEGRATION.md          │  ← If adding AI tools
│ CUSTOMER-LEARNING.md        │  ← If customer-related
└─────────────────────────────┘
```

### 4. AI Agent Understanding (For AI Agents Reading This)
```
PRIORITY READING ORDER:
  │
  1. This file (DOCUMENTATION-MAP.md) - You are here
  │
  2. 01-Architecture/system-overview.md
  │   └── Contains: All major systems, how they connect, key concepts
  │
  3. 09-Core-Innovations/00-INDEX.md
  │   └── Contains: All 65+ innovations, organized by category
  │
  4. FOR SPECIFIC TASKS:
  │
  │   Customer/Contact data?
  │   └── 09-Core-Innovations/CUSTOMER-LEARNING-ARCHITECTURE.md
  │       └── 09-Core-Innovations/MCP-Tools/kb-contact-*.md
  │
  │   AI tools/actions?
  │   └── 09-Core-Innovations/MCP-INTEGRATION.md
  │       └── 05-Public-Site/mcp-server.md (655 tools)
  │
  │   Multi-agent workflows?
  │   └── 09-Core-Innovations/AGENT-CHAINS.md
  │
  │   User onboarding?
  │   └── 09-Core-Innovations/food-fight.md (85 agents, 6 phases)
  │
  │   Knowledge base?
  │   └── 07-Business-Logic/knowledge-bases.md (6-layer architecture)
```

---

## Key Files Quick Reference

### MUST-READ Files (Start Here)

| Priority | File | Why It Matters |
|----------|------|----------------|
| 1 | `00-Introduction/production-reality.md` | IPs, URLs, ports, commands |
| 2 | `01-Architecture/system-overview.md` | **THE MASTER REFERENCE** - all systems |
| 3 | `01-Architecture/multi-tenancy.md` | company_id is EVERYWHERE |
| 4 | `09-Core-Innovations/00-INDEX.md` | Navigate 65+ innovations |
| 5 | `12-Issues-Found/known-issues.md` | Check before debugging |

### Core Innovation Files (What Makes Solid# Unique)

| File | Innovation |
|------|------------|
| `CUSTOMER-LEARNING-ARCHITECTURE.md` | AI that remembers every customer |
| `MCP-INTEGRATION.md` | 655 tools for external AI |
| `AGENT-CHAINS.md` | Multi-agent autonomous workflows |
| `PROACTIVE-INTELLIGENCE.md` | Daily briefings, smart suggestions |
| `food-fight.md` | 85 agents, 6 phases, 25-min onboarding |
| `AI-COST-INTELLIGENCE.md` | SmartRouter, CognitiveLimiter |
| `AI-SECURITY-FRAMEWORK.md` | PromptGuard, 5-layer protection |
| `PLATFORM-MODES.md` | Google/Microsoft/Native integration |
| `AI-VIDEO-STUDIO.md` | 5 video AI providers |

### Database & Backend Files

| File | Purpose |
|------|---------|
| `02-Backend/api-endpoints.md` | All 1,342 API routes |
| `02-Backend/er-diagram.md` | Database ER diagram |
| `06-Operations/DATABASE_SCHEMA_MAP.md` | Complete schema reference |
| `02-Backend/database-migrations.md` | Migration procedures |

### Operations Files

| File | Purpose |
|------|---------|
| `06-Operations/deployment.md` | How to deploy |
| `06-Operations/TROUBLESHOOTING.md` | Common issues and fixes |
| `06-Operations/environment-configuration.md` | All env vars |
| `06-Operations/LOCAL_VS_PRODUCTION_MAP.md` | Environment differences |

---

## Folder Purpose Reference

| Folder | Purpose | When to Use |
|--------|---------|-------------|
| `00-Introduction/` | Entry points, getting started | First time setup |
| `01-Architecture/` | System design, how things connect | Understanding the system |
| `02-Backend/` | API, database, backend code | Backend development |
| `03-AI-Systems/` | AI infrastructure, chat systems | AI development |
| `04-Frontend/` | Next.js, React components | Frontend development |
| `05-Public-Site/` | MCP server, public endpoints | External AI integration |
| `06-Operations/` | Deployment, monitoring, config | DevOps, troubleshooting |
| `07-Business-Logic/` | Onboarding, business rules | Feature development |
| `08-Sales/` | Sales documentation, demos | Sales team |
| `09-Core-Innovations/` | **THE GOOD STUFF** - all innovations | Understanding differentiators |
| `10-AI-Agents/` | Agent registry, capabilities | Agent development |
| `11-Platform-Architecture/` | Microservices architecture | Infrastructure |
| `12-Issues-Found/` | Known issues, tech debt | Bug fixing |
| `13-Testing/` | Test strategies | QA |
| `14-Security/` | Security documentation | Security reviews |
| `15-AI-Sandbox-Engine/` | Sandbox, development tiers | Dev environment |
| `04-Frontend/` | Frontend docs | Architecture + 287 pages |
| `17-Investment/` | Investor materials | Business development |

---

## Code ↔ Documentation Mapping

### Backend Code → Documentation

| Code Path | Documentation |
|-----------|---------------|
| `solid-backend/agents/` | `10-AI-Agents/agent-registry.md` |
| `solid-backend/mcp/tools/` | `09-Core-Innovations/MCP-Tools/` |
| `solid-backend/services/knowledge_base/` | `09-Core-Innovations/CUSTOMER-LEARNING-ARCHITECTURE.md` |
| `solid-backend/services/ai_bridge.py` | `09-Core-Innovations/ai-bridge-system.md` |
| `solid-backend/controllers/` | `02-Backend/api-endpoints.md` |
| `solid-backend/models/` | `02-Backend/er-diagram.md` |

### Frontend Code → Documentation

| Code Path | Documentation |
|-----------|---------------|
| `solid-frontend/src/app/` | `04-Frontend/app-structure.md` |
| `solid-frontend/src/components/` | `04-Frontend/app-structure.md` |
| `solid-frontend/src/components/crm/` | `09-Core-Innovations/CUSTOMER-LEARNING-ARCHITECTURE.md` |

### Configuration → Documentation

| Config | Documentation |
|--------|---------------|
| `.env` files | `06-Operations/environment-configuration.md` |
| `docker-compose.*.yml` | `06-Operations/deployment.md` |
| `alembic/` | `02-Backend/database-migrations.md` |

---

## Document Naming Conventions

| Pattern | Meaning |
|---------|---------|
| `00-INDEX.md` | Navigation index for folder |
| `UPPERCASE.md` | Important/architectural document |
| `lowercase.md` | Standard documentation |
| `*-ARCHITECTURE.md` | System architecture deep dive |
| `*-INTEGRATION.md` | Integration documentation |
| `*-MAP.md` | Visual mapping/flow document |

---

## Version History

| Date | Change |
|------|--------|
| Dec 13, 2025 | Created comprehensive documentation map |

---

*This document is the key to navigating the entire Owners Manual efficiently.*


--- FILE: 00-Introduction/PRODUCTION-REALITY.md ---

---
topic: introduction
keywords: [introduction, access, adamcampbell, after, also, applied, authentication, back, backend]
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---
> ## ⛔ CORRECTED 2026-08-30 — this document predates the move to the cell.
> Production is the **`solid-production` cell** (DOKS, nyc1), not a single droplet.
> `solidnumber.com` resolves to the app load balancer **`134.199.179.65`** (voice to
> `134.199.179.67`); TLS is terminated by Caddy **in the cluster**, not on a box.
> The SFO droplet `<production-host>` is out of the request path for `solidnumber.com` and
> is kept alive only because two apex customer domains still hold its native IP —
> ⛔ **it must not be destroyed.**
> Live state: **`06-Operations/00-INFRA-TRUTH.md`** (generated from `doctl`/`kubectl`/`dig`).
> Deploying: **`06-Operations/00-DEPLOY-START-HERE.md`**.
> Statements below about a single droplet, an SSH deploy, or "no load balancer" are stale.


> **Verified 2026-08-29:** Production IP (`<production-host>`), live URLs, port
> reference, and `ALLOWED_ISOLATION_TABLES` in `middleware/mcp_auth.py`
> confirmed accurate. ⚠️ **The "Production Containers" diagram below is a
> simplified subset, not the full container list** — `docker-compose.base.yml`
> / `docker-compose.prod.yml` also define `solid-superadmin`, `solid-demo`,
> `solid-demo-backend`, `solid-staging`, `solid-platform-commerce` (+ its own
> DB), `solid-mcp-server`, `solid-ai-creator`, `solid-flower`, and
> `solid-celery-beat` (beat, separate from the worker shown). SFO runs
> multiple backend-role containers, not the single "backend" box drawn here.
>
> ⛔ **DANGEROUS STALE COMMANDS (2026-08-29): every bare `docker-compose
> restart/up/down` command in this file's "Production Structure" diagram,
> "Deployment Flow", "Emergency Procedures", and "Emergency Runbook" sections
> below is WRONG and must not be run as written.** Confirmed against
> `deploy.sh:75` and CLAUDE.md § "Production Docker Compose Pattern":
> production has no single `docker-compose.yml` to run bare commands against —
> the real, mandatory invocation is
> `docker compose -f docker-compose.base.yml -f docker-compose.prod.yml <cmd>`
> from `/root/solid`. Per CLAUDE.md: "NEVER use individual service
> docker-compose files on production!" — running e.g. `docker-compose restart`
> or `docker-compose up -d --build backend` as literally written in the
> Emergency Runbook below is the exact anti-pattern that crashes production.
> This doc's commands were not individually rewritten in this pass (that would
> be a large restructure); treat every `docker-compose ...` invocation from
> here down as needing the `-f docker-compose.base.yml -f docker-compose.prod.yml`
> flags inserted before running it for real.

# Production Reality

> The truth about what's running, where it's running, and how to access it.

**Last Updated:** January 1, 2026

---

## CRITICAL: Pre-Launch Security Requirements (January 2026)

**The backend will NOT start in production without these environment variables:**

```bash
# REQUIRED - Generate with: openssl rand -hex 32
JWT_SECRET_KEY=<your-secret>        # ✅ REQUIRED
MCP_API_KEY=<your-secret>           # ✅ REQUIRED
ENVIRONMENT=production              # ✅ REQUIRED (triggers strict mode)

# Optional (falls back to JWT_SECRET_KEY)
CUSTOMER_JWT_SECRET_KEY=<your-secret>
```

### Security Fixes Applied (January 2026)

| Fix | Status | Description |
|-----|--------|-------------|
| SQL injection protection | ✅ DONE | `ALLOWED_ISOLATION_TABLES` whitelist in mcp_auth.py |
| Hardcoded credentials removed | ✅ DONE | Setup scripts use env vars or generate random |
| JWT secret enforcement | ✅ DONE | RuntimeError at startup if not set in production |
| Rate limiting on auth | ✅ DONE | 5-30 req/min on session and OTP endpoints |

### Pre-Deployment Checklist

Before deploying to production, verify:

- [ ] `JWT_SECRET_KEY` is set in `/root/solid/.env` (not a default value)
- [ ] `MCP_API_KEY` is set in `/root/solid/.env` (not a default value)
- [ ] `ENVIRONMENT=production` is set
- [ ] Database password is NOT `solid_dev_password`
- [ ] Run `./deploy.sh` (includes security checks)

---

## Production Server

| Property | Value |
|----------|-------|
| **Provider** | DigitalOcean |
| **IP Address** | ⛔ **stale** — `solidnumber.com` resolves to `134.199.179.65` (cell app LB). `<production-host>` is the SFO droplet, out of the request path since 2026-08-30. |
| **SSH Access** | `ssh <operator>@<production-host>` |
| **Server Path** | `/root/solid/` |
| **OS** | Ubuntu (Docker host) |

---

## Live URLs

| Service | URL | Purpose |
|---------|-----|---------|
| **API** | https://api.solidnumber.com | Backend REST API |
| **Dashboard** | https://app.solidnumber.com | Customer dashboard (Next.js) |
| **Marketing** | https://solidnumber.com | Public marketing site |
| **MCP Endpoint** | https://solidnumber.com/api/mcp | AI tool integration |

---

## Production Containers

```
┌─────────────────────────────────────────────────────────────────┐
│                    Production (<production-host>)                   │
│                         /root/solid/                             │
│                                                                  │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐              │
│  │   backend   │  │  frontend   │  │   public    │              │
│  │   :8090     │  │   :3000     │  │   :3001     │              │
│  │  FastAPI    │  │  Next.js    │  │  Next.js    │              │
│  └─────────────┘  └─────────────┘  └─────────────┘              │
│                                                                  │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐              │
│  │  postgres   │  │   redis     │  │   caddy     │              │
│  │   :5432     │  │   :6379     │  │  :80/:443   │              │
│  │  Database   │  │   Cache     │  │  Reverse    │              │
│  └─────────────┘  └─────────────┘  │   Proxy     │              │
│                                    └─────────────┘              │
│  ┌─────────────┐                                                │
│  │   celery    │                                                │
│  │  workers    │                                                │
│  │  Background │                                                │
│  └─────────────┘                                                │
└─────────────────────────────────────────────────────────────────┘
```

---

## Port Reference

### Production Ports (External)
| Port | Service | Notes |
|------|---------|-------|
| 80 | Caddy (HTTP) | Redirects to HTTPS |
| 443 | Caddy (HTTPS) | All external traffic |

### Production Ports (Internal/Docker)
| Port | Service | Container Name |
|------|---------|----------------|
| 8090 | Backend API | solid-backend |
| 3000 | Frontend | solid-frontend |
| 3001 | Public Site | solid-public |
| 5432 | PostgreSQL | solid-postgres |
| 6379 | Redis | solid-redis |

### Local Development Ports (dev.sh)
| Port | Service | Notes |
|------|---------|-------|
| 8090 | Backend | http://localhost:8090 |
| 3000 | Frontend | http://localhost:3000 |
| 3001 | Public | http://localhost:3001 |
| 5432 | PostgreSQL | localhost:5432 |
| 6379 | Redis | localhost:6379 |
| 5555 | Flower | Celery monitoring |
| 8092 | MCP Server | http://localhost:8092 |
| 8093 | AI Creator | http://localhost:8093 |

---

## Git Repository Map

### GitHub Repositories
| Repo | URL | Branch | Purpose |
|------|-----|--------|---------|
| solid-backend | github.com/Adam-Camp-King/solid-backend | main | FastAPI backend |
| solid-frontend | github.com/Adam-Camp-King/solid-frontend | main | Next.js dashboard |
| solid-public | github.com/Adam-Camp-King/solid-public | main | Marketing site |
| solid-live | github.com/Adam-Camp-King/solid-live | feature/unified-knowledge-base | Docs & configs |

### Local Structure
```
/Users/adamcampbell/Desktop/Solid/          ← solid-live (parent repo)
├── Owners-Manual/                          ← Documentation (you are here)
├── docker-compose.base.yml                 ← Shared service definitions
├── docker-compose.local.yml                ← Local dev overrides
├── dev.sh                                  ← Local dev orchestration script
├── COMMIT_ALL.sh                           ← Safe commit script
├── deploy.sh                               ← Production deploy + QA script
├── solid-backend/                          ← Separate git repo
├── solid-frontend/                         ← Separate git repo
└── solid-public/                           ← Separate git repo
```

### Production Structure
```
/root/solid/                                ← Production server
├── docker-compose.yml                      ← Production config (DIFFERENT from local)
├── .env                                    ← Production secrets
├── solid-backend/                          ← Git repo (pulls from GitHub)
├── solid-frontend/                         ← Git repo (pulls from GitHub)
└── solid-public/                           ← Git repo (pulls from GitHub)
```

---

## Deployment Flow

```
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  LOCAL MACHINE  │────▶│     GITHUB      │────▶│   PRODUCTION    │
│                 │     │                 │     │                 │
│  Edit code      │     │  solid-backend  │     │  git pull       │
│  ./dev.sh       │     │  solid-frontend │     │  docker restart │
│  ./COMMIT_ALL.sh│     │  solid-public   │     │                 │
│                 │     │  solid-live     │     │  <production-host> │
└─────────────────┘     └─────────────────┘     └─────────────────┘
```

### Commands

```bash
# Local development
cd /Users/adamcampbell/Desktop/Solid
./dev.sh                                   # Start all services

# Commit all changes
./COMMIT_ALL.sh "feat: Your message"       # Commit to GitHub
./COMMIT_ALL.sh "feat: Message" --deploy   # Commit + deploy

# Deploy to production (after commit)
./deploy.sh validate                       # Pre-push validation
./deploy.sh deploy backend                 # Deploy backend + AUTO-QA
./deploy.sh deploy frontend                # Deploy frontend
./deploy.sh deploy                         # Deploy ALL services + AUTO-QA
./deploy.sh status                         # Check container status
./deploy.sh health                         # Check health endpoints
./deploy.sh qa                             # Run QA scanner manually
./deploy.sh rollback backend               # Rollback backend if broken

# Manual production access
ssh <operator>@<production-host>
cd /root/solid
docker ps                                  # See containers
docker logs solid-backend --tail 50        # View logs
docker-compose restart backend             # Restart service
```

---

## Health Checks

### Quick Production Check
```bash
# API Health
curl https://api.solidnumber.com/api/v1/_health

# Frontend (should return HTML or redirect)
curl -I https://app.solidnumber.com

# Public Site
curl -I https://solidnumber.com
```

### Expected Responses
- **API**: `{"status":"OK","service":"solid-backend",...}`
- **Frontend**: HTTP 200 or 307 redirect
- **Public**: HTTP 200

---

## Tokens & Authentication

### GitHub Tokens (Local Machine)
| Token Name | Purpose | Used For |
|------------|---------|----------|
| **Solid Live** | Local development | All local git push |

### GitHub Tokens (Production Server)
| Token Name | Purpose | Used For |
|------------|---------|----------|
| **DigitalOcean Production Server** | Production deploys | All git pull on server |

### How to Update Expired Tokens

**Local (all repos use same token):**
```bash
cd /Users/adamcampbell/Desktop/Solid
git remote set-url origin "https://NEW_TOKEN@github.com/Adam-Camp-King/solid-live.git"

cd solid-backend
git remote set-url origin "https://NEW_TOKEN@github.com/Adam-Camp-King/solid-backend.git"

# Repeat for solid-frontend, solid-public
```

**Production:**
```bash
ssh <operator>@<production-host>
cd /root/solid/solid-backend
git remote set-url origin "https://NEW_TOKEN@github.com/Adam-Camp-King/solid-backend.git"

# Repeat for solid-frontend, solid-public
```

---

## Environment Files

### Local (.env files in /Users/adamcampbell/Desktop/Solid/)
| File | Purpose |
|------|---------|
| `.env` | Shared environment variables |
| `.env.local` | Local overrides |
| `.env.dev` | Development settings |

### Production (.env in /root/solid/)
| Variable | Purpose |
|----------|---------|
| `ENV=production` | **CRITICAL** - Must be "production" |
| `DATABASE_URL` | PostgreSQL connection |
| `REDIS_URL` | Redis connection |
| `SECRET_KEY` | App secret |
| Various API keys | Stripe, Twilio, etc. |

---

## Emergency Procedures

### Production Down?
```bash
# 1. Check container status
ssh <operator>@<production-host> "docker ps -a"

# 2. Check logs
ssh <operator>@<production-host> "docker logs solid-backend --tail 100"

# 3. Restart all containers
ssh <operator>@<production-host> "cd /root/solid && docker-compose restart"

# 4. Nuclear option: rebuild
ssh <operator>@<production-host> "cd /root/solid && docker-compose down && docker-compose up -d"
```

### Rollback Deployment
```bash
# On production server
ssh <operator>@<production-host>
cd /root/solid/solid-backend
git log --oneline -5                       # Find previous commit
git checkout <commit-hash>                 # Rollback
docker-compose restart backend
```

### Database Backup
```bash
# Create backup
./BACKUP_DATABASE.sh

# Or manually
ssh <operator>@<production-host> "docker exec solid-postgres pg_dump -U solid solid > /root/backup.sql"
```

---

## Emergency Runbook

> **When things break at 3am, follow this guide.**

### Severity Levels

| Level | Definition | Response Time |
|-------|------------|---------------|
| **P0 - Critical** | Site completely down, no users can access | Immediate |
| **P1 - High** | Major feature broken, payments failing | < 1 hour |
| **P2 - Medium** | Feature degraded, workaround exists | < 4 hours |
| **P3 - Low** | Minor issue, cosmetic, edge case | Next business day |

---

### P0: Complete Outage

```bash
# STEP 1: Verify the outage (30 seconds)
curl -I https://api.solidnumber.com/api/v1/_health
curl -I https://app.solidnumber.com
curl -I https://solidnumber.com

# STEP 2: Check server is reachable (30 seconds)
ssh <operator>@<production-host> "echo 'Server OK'"

# STEP 3: Check Docker status (1 minute)
ssh <operator>@<production-host> "docker ps -a"
# Look for: containers not in "Up" state

# STEP 4: Check container logs (2 minutes)
ssh <operator>@<production-host> "docker logs solid-backend --tail 100"
ssh <operator>@<production-host> "docker logs solid-frontend --tail 100"
ssh <operator>@<production-host> "docker logs solid-postgres --tail 50"

# STEP 5: Restart all services (3 minutes)
ssh <operator>@<production-host> "cd /root/solid && docker-compose restart"

# STEP 6: If restart fails, full rebuild (5-10 minutes)
ssh <operator>@<production-host> "cd /root/solid && docker-compose down && docker-compose up -d"

# STEP 7: Verify recovery
curl https://api.solidnumber.com/api/v1/_health
```

---

### P1: Backend API Down (Frontend Works)

```bash
# Check backend specifically
ssh <operator>@<production-host> "docker logs solid-backend --tail 200"

# Common issues:
# - Database connection: Check solid-postgres container
# - Redis connection: Check solid-redis container
# - Out of memory: Check with 'docker stats'

# Restart backend only
ssh <operator>@<production-host> "cd /root/solid && docker-compose restart backend"

# Check memory/CPU
ssh <operator>@<production-host> "docker stats --no-stream"
```

---

### P1: Database Issues

```bash
# Check PostgreSQL status
ssh <operator>@<production-host> "docker logs solid-postgres --tail 100"

# Check disk space (common cause)
ssh <operator>@<production-host> "df -h"

# Check database connections
ssh <operator>@<production-host> "docker exec solid-postgres psql -U solid -c 'SELECT count(*) FROM pg_stat_activity;'"

# Restart PostgreSQL (WARNING: brief downtime)
ssh <operator>@<production-host> "cd /root/solid && docker-compose restart postgres"

# If corrupted, restore from backup
ssh <operator>@<production-host> "docker exec solid-postgres psql -U solid solid < /root/backup.sql"
```

---

### P1: Celery/Background Jobs Stuck

```bash
# Check Celery logs
ssh <operator>@<production-host> "docker logs solid-celery --tail 100"

# Check Redis (Celery broker)
ssh <operator>@<production-host> "docker exec solid-redis redis-cli ping"

# Restart Celery
ssh <operator>@<production-host> "cd /root/solid && docker-compose restart celery"

# Clear stuck tasks (CAUTION: loses pending tasks)
ssh <operator>@<production-host> "docker exec solid-redis redis-cli FLUSHDB"
```

---

### P1: SSL/HTTPS Issues

```bash
# Check Caddy logs
ssh <operator>@<production-host> "docker logs solid-caddy --tail 100"

# Restart Caddy (usually fixes cert issues)
ssh <operator>@<production-host> "cd /root/solid && docker-compose restart caddy"

# Force cert renewal
ssh <operator>@<production-host> "docker exec solid-caddy caddy reload --config /etc/caddy/Caddyfile"
```

---

### P2: High Memory Usage

```bash
# Check current usage
ssh <operator>@<production-host> "docker stats --no-stream"
ssh <operator>@<production-host> "free -h"

# Clear Docker cache
ssh <operator>@<production-host> "docker system prune -f"

# Restart high-memory container
ssh <operator>@<production-host> "cd /root/solid && docker-compose restart backend"
```

---

### P2: Slow API Response

```bash
# Check for slow queries
ssh <operator>@<production-host> "docker exec solid-postgres psql -U solid -c \"SELECT pid, now() - pg_stat_activity.query_start AS duration, query FROM pg_stat_activity WHERE state = 'active' ORDER BY duration DESC LIMIT 5;\""

# Check Redis
ssh <operator>@<production-host> "docker exec solid-redis redis-cli INFO stats"

# Check backend connections
ssh <operator>@<production-host> "docker exec solid-backend netstat -an | grep ESTABLISHED | wc -l"
```

---

### Rollback Checklist

```bash
# 1. Identify the bad commit
ssh <operator>@<production-host> "cd /root/solid/solid-backend && git log --oneline -10"

# 2. Note the current commit (in case rollback fails)
ssh <operator>@<production-host> "cd /root/solid/solid-backend && git rev-parse HEAD"

# 3. Rollback to previous commit
ssh <operator>@<production-host> "cd /root/solid/solid-backend && git checkout HEAD~1"

# 4. Rebuild and restart
ssh <operator>@<production-host> "cd /root/solid && docker-compose up -d --build backend"

# 5. Verify
curl https://api.solidnumber.com/api/v1/_health

# 6. If rollback worked, DON'T push to GitHub yet
# Fix the issue locally, then deploy properly
```

---

### Communication Template

```
INCIDENT: [Brief description]
STATUS: [Investigating/Identified/Monitoring/Resolved]
IMPACT: [Who is affected, what's broken]
START TIME: [When it started]
CURRENT ACTION: [What we're doing]
ETA: [When we expect resolution]
UPDATES: [Will update every X minutes]
```

---

### Post-Incident Checklist

- [ ] Incident documented in 12-Issues-Found/known-issues.md
- [ ] Root cause identified
- [ ] Fix deployed and verified
- [ ] Monitoring added if applicable
- [ ] Team notified of resolution
- [ ] Consider: Does this need automated alerting?

---

## Key Files Reference

| File | Location | Purpose |
|------|----------|---------|
| `COMMIT_ALL.sh` | /Solid/ | Safe commit all repos |
| `deploy.sh` | /Solid/ | Deploy + QA + rollback |
| `docker-compose.base.yml` | /Solid/ | Shared service definitions |
| `docker-compose.local.yml` | /Solid/ | Local dev overrides |
| `dev.sh` | /Solid/ | Local orchestration script |
| `GIT-DEPLOYMENT-WORKFLOW.md` | Owners-Manual/06-Operations/ | Detailed git flow (Corrected 2026-08-29: was listed as `05-Operations/git-deployment-workflow.md` — that folder/filename doesn't exist; real path confirmed above) |

---

## Quick Reference Card

```
┌────────────────────────────────────────────────────────────────┐
│                     SOLID# QUICK REFERENCE                      │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  LOCAL DEVELOPMENT                                             │
│  ─────────────────                                             │
│  cd /Users/adamcampbell/Desktop/Solid                          │
│  ./dev.sh                         # Start everything           │
│  ./dev.sh watch                   # Start with hot-reload      │
│  http://localhost:3000            # Frontend                   │
│  http://localhost:8090            # Backend API                │
│                                                                │
│  COMMIT & PUSH                                                 │
│  ─────────────                                                 │
│  ./COMMIT_ALL.sh "message"        # Commit all to GitHub       │
│  ./COMMIT_ALL.sh "msg" --deploy   # Commit + deploy            │
│                                                                │
│  PRODUCTION                                                    │
│  ──────────                                                    │
│  ./deploy.sh validate             # Pre-push check             │
│  ./deploy.sh deploy backend       # Deploy + AUTO-QA           │
│  ./deploy.sh rollback backend     # Rollback if broken         │
│  ssh <operator>@<production-host>          # Access server              │
│                                                                │
│  LIVE URLS                                                     │
│  ─────────                                                     │
│  https://api.solidnumber.com      # Backend API                │
│  https://app.solidnumber.com      # Dashboard                  │
│  https://solidnumber.com          # Marketing site             │
│                                                                │
└────────────────────────────────────────────────────────────────┘
```

---

## See Also

- [deployment.md](../06-Operations/deployment.md) - Deployment procedures
- [TROUBLESHOOTING.md](../06-Operations/TROUBLESHOOTING.md) - Common issues and fixes
- [environment-configuration.md](../06-Operations/environment-configuration.md) - Environment variables
- [security-overview.md](../14-Security/security-overview.md) - Security architecture
- [testing-guide.md](../13-Testing/testing-guide.md) - Test procedures

---

_Last updated: 2025-12-13_


--- FILE: 00-Introduction/SOLID-PLATFORM-OVERVIEW.md ---

---
topic: introduction
keywords: [introduction, additional, agents, business, businesses, code, codebase, coding, complete]
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# Solid# Platform Overview

> **AI Business Infrastructure — the layer between AI models and business operations.**

---

## What We Are

**Solid# is AI Business Infrastructure.** Not a SaaS platform with AI features. Not an AI wrapper. Not a CRM. **Infrastructure.** The same way AWS is cloud infrastructure for compute, Solid# is AI infrastructure for running businesses.

### Why This Identity Matters

The code proves it: **55% AI services**, 21% payments, 21% CRM. CRM and payments are capabilities, not the product. The AI layer — SmartRouter (model selection), CognitiveLimiter (cost control), PromptGuard (security) — is what makes everything work. Without it, it's just another business tool. With it, 32 AI agents execute real work across every business function.

### What Customers Get

Everything a business needs — CRM, payments, inventory, e-commerce, POS, website builder, marketing — built from the ground up where AI is the core. **32 AI agents** work 24/7, backed by **273 background task functions**. When AI recommends something, the platform delivers it. No shopping for another tool. Customers own what they build — rent, buy, or self-host.

| Traditional SaaS | Solid# |
|------------------|--------|
| Rent features | Own properties |
| Stop paying = lose everything | Stop paying = export your assets |
| AI advises | AI executes (closed loop) |
| Learn 50 features day 1 | Discover as you grow |
| 10+ disconnected tools | One unified platform with full AI awareness |

**The Result:** 25-minute onboarding. 58 industry templates. AI that delivers, not just advises.

---

## Who We Serve

### Primary: Small & Medium Businesses

| Industry | Examples |
|----------|----------|
| **Home Services** | Plumbers, HVAC, Electricians, Roofers, Landscapers |
| **Professional Services** | Law firms, Accounting, Insurance, Real Estate |
| **Healthcare** | Dentists, Chiropractors, Veterinarians, Medical practices |
| **Retail & Hospitality** | Restaurants, Bars, Retail stores, Hotels |
| **Automotive** | Auto repair, Dealerships, Car washes |
| **Fitness & Wellness** | Gyms, Spas, Dance studios |

**58 industry templates** ensure every business type gets pre-built expertise on day one.

### The Problem We Solve

| Traditional Approach | Solid# Approach |
|---------------------|-----------------|
| 10+ separate software tools | One unified platform you own |
| $2,000+/month in subscriptions | $89-499/month for hosting + tokens |
| Weeks of setup and training | 25 minutes to operational |
| Generic AI that advises | AI that knows YOUR business and executes |
| Stop paying = lose everything | Stop paying = export your properties |
| Locked to vendor infrastructure | CLI + Vibe coding + Droplet = your platform |
| Hire 5+ employees for operations | 32 AI agents work for you |

---

## What We Offer

### The Complete Business Stack

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                           SOLID# PLATFORM                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  CRM & SALES                    PAYMENTS & COMMERCE                          │
│  ├── Contact management         ├── Credit card processing                  │
│  ├── Deal pipeline              ├── ACH/bank transfers                      │
│  ├── Lead scoring (0-100)       ├── Text-to-pay links                       │
│  ├── Email & SMS campaigns      ├── Invoice OCR (photo → payment)           │
│  └── AI sales assistants        └── no additional platform fee                         │
│                                                                              │
│  E-COMMERCE & POS               INVENTORY & OPERATIONS                       │
│  ├── Online store               ├── Multi-location stock                    │
│  ├── Shopping cart              ├── Barcode/SKU scanning                    │
│  ├── Terminal management        ├── Kit/bundle support                      │
│  ├── Digital signatures         ├── Auto-reorder alerts                     │
│  └── Tip adjustment             └── Transfer management                     │
│                                                                              │
│  WEBSITE & CONTENT              MARKETING AUTOMATION                         │
│  ├── AI website builder         ├── Drip email campaigns                    │
│  ├── 10 content blocks          ├── A/B testing                             │
│  ├── SEO auto-optimization      ├── Lead nurturing                          │
│  ├── Blog/landing pages         ├── Predictive analytics                    │
│  └── Embeddable widgets         └── Campaign performance                    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## Our Core Innovations

### 1. 25-Minute Onboarding (Not Weeks)

When you sign up and select your industry:
- **500+ knowledge base entries** cloned instantly
- **AI trained on your business type** immediately
- **Sales scripts and objection handling** ready to use
- **All features configured** for your industry

Traditional CRM: 4-6 weeks of setup
**Solid#: 25 minutes**

### 2. 32 AI Agents + 271 Background Task Functions

Two categories — never conflate them:

**32 AI agents** (33 registry entries, 23 deeply trained) = AI personalities with rich system prompts. Customers interact with these:

| Agent | Role | What They Do |
|-------|------|--------------|
| **Sarah** (ID 1) | Customer Service | Answer questions, resolve issues, multi-channel |
| **Marcus** (ID 4) | Marketing & Growth | Create campaigns, write content, growth strategy |
| **Devon** (ID 11) | Operations Monitor | System monitoring, performance, uptime |
| **ADA** (ID 12) | Orchestrator | Coordinates all agents, routes requests, revenue optimization |
| **Jake** (ID 2) | Inventory | Monitor stock, auto-reorder, supply chain |
| **+ more** | Specialized | Finance, Brand, Developer, Affiliate, Sales Follow-up, etc. |

**271 Celery task functions** (176 scheduled) = background processing jobs (scans, syncs, audits, drip campaigns). Infrastructure, NOT agents.

These are two different categories and are never summed into one number. See `Owners-Manual/PLATFORM-METRICS.md` for the derived counts.

### 3. AI with Persistent Memory

Our AI remembers everything across all channels:
- Customer calls Voice AI about a leak
- Later chats on website - AI already knows about the leak
- Emails for a quote - AI includes leak repair details

**No more "I don't have that information" frustration.**

### 4. 6 AI Personalities

Choose your brand's voice:
- **Professional** - Formal, business-focused
- **Southern Hospitality** - "Hey honey!", warm and friendly
- **British** - "Brilliant!", proper and polite
- **Italian** - "Ciao amico!", passionate and expressive
- **Tech Bro** - "Yo!", casual startup vibes
- **Super Sweet** - Extra caring and supportive

### 5. No Additional Platform Fees

**Two payment options:**

| Option | Rate | Details |
|--------|------|---------|
| **Solid Payments [DEFUNCT — retired; platform is multi-processor, 14 adapters]** | 2.9% + $0.30 | We handle everything, no platform fee |
| **Own Processor** | 0.5% platform fee | Only charged if you don't use Solid Payments [DEFUNCT — retired; platform is multi-processor, 14 adapters] |

Use Solid Payments [DEFUNCT — retired; platform is multi-processor, 14 adapters] = no extra fees. Use your own processor = 0.5% platform fee.

### 6. Vibe Coding - Natural Language Business Control

Configure your entire business by typing what you want in plain English:

| What You Say | What Happens |
|--------------|--------------|
| "Add a massage for $120" | Creates bookable service |
| "Create a pricing page" | Builds CMS page with your services |
| "Send reminders 24h before appointments" | Creates automated workflow |
| "Show me this month's sales" | Generates analytics report |
| "Make Sarah more autonomous" | Configures AI agent settings |
| "Increase all prices by 10%" | Updates service/product pricing |

**10 Entity Types:** Services, Products, Pages, Forms, KB, Emails, Workflows, Reports, Agent Settings, Pricing

**Safety Guarantees:**
- Can NEVER delete data (archive only)
- Preview before every change
- One-click rollback on any action
- Full audit trail with version history

**Included in ALL tiers** - Vibe Coding is a core feature, not a premium add-on.

---

## By The Numbers

| Metric | Value |
|--------|-------|
| AI Agents | 32 (33 registry entries, 23 deeply trained; customer-facing personalities) |
| Background Task Functions | 271 Celery task functions (176 scheduled) |
| Industry Templates | 58 |
| KB Entries per Industry | 500+ |
| API Endpoints | 2,242 |
| MCP Tools (for AI integration) | 655 |
| Vibe Coding Entity Types | 10 |
| Vibe Coding Tests | 63 (all passing) |
| Onboarding Time | 25 minutes |
| Payment Processing | 2.9% + $0.30 (Solid) or 0.5% (own processor) |
| Human Employees Replaced | 5-10 |
| Annual Savings (AI workforce) | $675,000+ |

### Codebase Statistics

| Metric | Value |
|--------|-------|
| Lines of Code | 5.32M (5,324,767 lines) across 16 repos |
| Database Tables | 627, isolated by `company_id` + row-level security policies enforced at the DB level by the non-superuser `solid_app` role |
| API Endpoints | 2,242 |
| Documentation | 1,959 files across 97 sections |

*See `PLATFORM-METRICS.md` for auto-generated authoritative numbers.*

---

## The ROI

### Software Consolidation

| Tool | Monthly Cost | Replaced By Solid# |
|------|-------------|-------------------|
| CRM (HubSpot/Salesforce) | $300-800 | ✓ |
| Payment processor | $50-200 | ✓ |
| POS system | $100-300 | ✓ |
| E-commerce platform | $79-299 | ✓ |
| Website builder | $30-100 | ✓ |
| Email marketing | $50-500 | ✓ |
| Inventory management | $50-200 | ✓ |
| Scheduling software | $25-100 | ✓ |
| Chat/support tool | $50-300 | ✓ |
| Analytics platform | $50-200 | ✓ |
| **TOTAL** | **$784-2,999/mo** | **$89-499/mo** |

### Staff Savings

Our 14+ autonomous AI agents replace:
- 1 Inventory Manager ($65,000/year)
- 1 SDR for follow-up ($55,000/year)
- 1 Admin Assistant ($45,000/year)
- 1 Business Analyst ($85,000/year)
- 1 Email Specialist ($50,000/year)
- And more...

**Total: $675,000+/year in labor automation**

---

## Pricing

| Plan | Price | Best For |
|------|-------|----------|
| **Starter** | $89/month | Solo operators, getting started |
| **Builder** | $199/month | Growing businesses, small teams |
| **Professional** | $499/month | Established businesses, full features |

All plans include:
- Unlimited AI agents
- no additional platform fees
- Industry-specific templates
- Full feature access (tier-based limits)

---

## How It Works

```
STEP 1: Sign Up (2 min)
└── Enter business name, select industry

STEP 2: Industry Detection (30 sec)
└── MCC code identifies your business type
└── 58 industries supported

STEP 3: AI Onboarding (25 min)
└── 32 AI agents configure for your business
└── 500+ knowledge base entries created
└── Sales scripts, FAQs, policies ready

STEP 4: You're Live
└── Accept payments immediately
└── AI answers customer questions
└── Lead scoring active
└── Marketing automation ready
```

---

## Technology

- **Backend:** Python FastAPI, PostgreSQL, Redis
- **Frontend:** Next.js 15, React, TypeScript
- **AI:** OpenAI GPT-4, custom agents
- **Payments:** Stripe, Solid Payments [DEFUNCT — retired; platform is multi-processor, 14 adapters] (retired processor)
- **Voice:** OpenAI Realtime API, Twilio
- **Infrastructure:** Docker, Kubernetes

**For AI Integration:** 655 MCP tools available for connecting external AI systems.

---

## The One-Line Pitch

**"The operating system for small business. Own it, don't rent it."**

Or: **"32 AI agents. When they recommend something, the platform delivers it."**

Or: **"Your business stack. Your properties. Pay for hosting, keep what you build."**

---

## Contact & Links

| Resource | URL |
|----------|-----|
| Website | https://solidnumber.com |
| App | https://app.solidnumber.com |
| API | https://api.solidnumber.com |
| Documentation | /Owners-Manual |

---

*Solid# - The Operating System for Small Business*

---

## Maintenance Notes

**File Location:** `Owners-Manual/16-Summary/solid-platform-overview.md`

**Last Updated:** 2025-12-10

**What Was Missing (Dec 2025 audit):**
- Codebase statistics section was completely absent
- No line counts or file counts for the platform
- Missing breakdown of code vs documentation

**How to regenerate codebase stats:**
```bash
# Total lines (code + docs)
find . -type f \( -name "*.py" -o -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.md" \) | grep -v node_modules | grep -v ".venv" | grep -v ".next" | grep -v ".git" | xargs cat | wc -l

# Code only
find . -type f \( -name "*.py" -o -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \) | grep -v node_modules | grep -v ".venv" | grep -v ".next" | grep -v ".git" | xargs cat | wc -l

# Documentation only
find . -type f -name "*.md" | grep -v node_modules | grep -v ".venv" | grep -v ".git" | xargs cat | wc -l

# Database tables
grep -r "__tablename__" solid-backend/models/*.py | wc -l
```

**Key directories included in count:**
- solid-backend, solid-frontend, solid-public, solid-superadmin
- solid-mcp-server, ai-creator-server, arcade-api, solid-token-orchestrator
- solid-ai-director, ai-native-server, Owners-Manual
- Root-level documentation (.md files)


--- FILE: 00-THESIS.md ---

---
topic: platform-thesis
keywords: [thesis, positioning, ai-infrastructure, strategy, why-solid, platform-identity]
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# The Solid# Thesis

## The One-Liner

**Solid# is the AI layer for payments. Without it, payment companies die.**

---

## The Gap

AI is taking over business operations. Every business will run on AI within 5 years.

When AI runs the business, AI decides where money moves.

If AI decides where money moves, whoever owns the AI owns commerce.

**Payment companies don't have AI. AI companies don't have payments.**

That's the gap. We are the plug.

---

## Three Paths to Win

### 1. Direct Sales
Sell to merchants. Prove it works. Build density.
- $89-$3,999/month subscriptions
- 500 merchants = $3.9M ARR
- Cash flow funds everything else

### 2. Plugin Sales
Sell to payment processors as their AI layer.
- White-label to ISOs and PayFacs
- They keep their merchants, we power the AI
- License + per-merchant + token revenue

### 3. Acquisition
Someone with power needs this gap filled.
- **Stripe** — Needs AI before AI eats them
- **OpenAI/GPT** — Needs payments before payments blocks them
- **Visa** — Needs to prevent the above from happening

One of them knows this gap exists. We are the plug.

---

## The Nuclear Option

We can make the software **free**.

Revenue comes from:
- **Payment transactions** (2.9% + $0.30, or 0.5% if they bring their own processor)
- **Hosting** ($24-200/month per instance)
- **AI tokens** (3x markup on LLM costs)

This is Stripe's model but with AI infrastructure instead of payment rails.

When software is free, SaaS competitors can't compete on price.

---

## Who Dies

**HubSpot** — CRM with AI bolted on. We're AI with CRM built in.

**Salesforce** — Enterprise bloat. AI doesn't need 200 features, it needs authority.

**Vertical SaaS** — They're building horses. We built a jet.

**Anyone charging for software** — When AI runs the business, software is just the interface. You can give away the interface.

The future is: **Free software. Paid infrastructure.**

We already built both.

---

## Why This Works

1. **32 AI agents** already built and running (derived — see `Owners-Manual/PLATFORM-METRICS.md`)
2. **655 MCP tools** for AI-to-AI integration (incl. 501 verbs (390 native + 111 ADA bridge) shipped May 2026) — see `Owners-Manual/PLATFORM-METRICS.md`
3. **58 industry templates** — day-one expertise for any business (corrected 2026-08-29: was "234", which does not match the 58 real template files in `solid-backend/scripts/templates/industries/`; see `Owners-Manual/PLATFORM-METRICS.md`)
4. **Full payment stack** — not bolted on, native
5. **Multi-tenant architecture** — one codebase serves infinite customers

The code exists. The infrastructure exists. The gap exists.

Someone will fill this gap. It's us or it's no one for 3-5 years.

---

## The Outcome

One of three things happens:

1. **We sell direct** and become profitable on transactions + tokens
2. **We sell as a plugin** and payment companies pay us to survive
3. **We get acquired** by someone who wants the power move

All three are wins. All three fund each other.

---

## The Truth

We're not building a billion-dollar company.

We're filling a gap that a billion-dollar company needs filled.

That's a better position.

---

*This thesis governs all decisions. When in doubt, ask: "Does this make us more essential to the gap?"*


--- FILE: 01-Architecture/MULTI-TENANCY.md ---

---
topic: architecture
keywords: [architecture, action, affected, agent, audit, audit_service, authenticated, base]
code_paths:
  - solid-backend/api/routers/customers.py
  - solid-backend/middleware/company.py
  - solid-backend/middleware/domain_resolver.py
  - solid-backend/middleware/mcp_tenant_scope.py
  - solid-backend/services/audit_service.py
  - solid-backend/services/customer_service.py
last_verified: 2026-05-25
status: current
priority: critical
owner: platform-team
---

# Multi-Tenancy Architecture

> How Solid# guarantees complete data isolation between companies.
>
> **Why this design:** Shared-schema multi-tenancy with PostgreSQL Row-Level Security was chosen over schema-per-tenant or database-per-tenant because all 45+ industries share an identical table structure — a plumber's contacts table is structurally the same as a dentist's. RLS enforces isolation at the database engine level rather than trusting application code, so a missed WHERE clause cannot leak data. The 5-layer defense (schema, base model, middleware, service, controller) exists because no single layer is trusted alone — defense in depth is non-negotiable when 570 tables serve every tenant.
>
> **When this applies:** Every query, every API call, every agent tool execution. If code touches the database, it flows through this system. The company_id is extracted from the JWT at the middleware layer and injected into every service constructor.

---

## The Principle

**Every piece of data belongs to exactly one company.**

```
┌─────────────────────────────────────────────────────────┐
│  RULE: No query executes without company_id filter     │
└─────────────────────────────────────────────────────────┘
```

---

## Implementation Layers

### Layer 1: Database Schema

Every table has a `company_id` foreign key:

```sql
-- Example: customers table
CREATE TABLE customers (
    id SERIAL PRIMARY KEY,
    company_id INTEGER NOT NULL REFERENCES companies(id),
    name VARCHAR(255),
    email VARCHAR(255),
    created_at TIMESTAMP DEFAULT NOW()
);

-- Index for fast company-scoped queries
CREATE INDEX idx_customers_company_id ON customers(company_id);
```

### Layer 2: SQLAlchemy Base Model

All models inherit from a base class that enforces company scope:

```python
# models/base.py
class CompanyScoped(Base):
    """Base class for all company-scoped models."""

    __abstract__ = True

    company_id = Column(
        Integer,
        ForeignKey('companies.id'),
        nullable=False,
        index=True
    )

    @declared_attr
    def company(cls):
        return relationship("Company", lazy="select")
```

### Layer 3: Middleware Enforcement

Every request extracts and validates company_id:

```python
# middleware/company.py
@app.middleware("http")
async def inject_company_id(request: Request, call_next):
    # Extract from JWT token
    token = request.headers.get("Authorization")
    if token:
        payload = decode_jwt(token)
        company_id = payload.get("company_id")

        # Inject into request scope
        request.scope["company_id"] = company_id

    response = await call_next(request)
    return response
```

### Layer 4: Service Layer Filtering

Services always filter by company_id:

```python
# services/customer_service.py
class CustomerService:
    def __init__(self, db: Session, company_id: int):
        self.db = db
        self.company_id = company_id

    def get_all(self) -> List[Customer]:
        return self.db.query(Customer).filter(
            Customer.company_id == self.company_id
        ).all()

    def get_by_id(self, customer_id: int) -> Customer:
        return self.db.query(Customer).filter(
            Customer.company_id == self.company_id,
            Customer.id == customer_id
        ).first()

    def create(self, data: CustomerCreate) -> Customer:
        customer = Customer(
            company_id=self.company_id,  # Always set
            **data.dict()
        )
        self.db.add(customer)
        self.db.commit()
        return customer
```

### Layer 5: Controller Injection

Controllers receive company_id from request context:

```python
# controllers/customers.py
@router.get("/customers")
async def list_customers(
    request: Request,
    db: Session = Depends(get_db)
):
    company_id = request.scope.get("company_id")
    if not company_id:
        raise HTTPException(401, "Not authenticated")

    service = CustomerService(db, company_id)
    return service.get_all()
```

---

## Knowledge Base Isolation

The KB system has 4 layers, each with its own isolation:

```
┌─────────────────────────────────────────────────────────┐
│  PLATFORM KB (Shared)                                   │
│  - company_id = NULL                                    │
│  - 52 industry templates                               │
│  - Accessible by all companies (read-only)              │
├─────────────────────────────────────────────────────────┤
│  COMPANY KB (Per Company)                               │
│  - company_id = X                                       │
│  - Cloned from platform + customized                    │
│  - Only accessible by company X                         │
├─────────────────────────────────────────────────────────┤
│  REP KB (Per Employee)                                  │
│  - company_id = X                                       │
│  - user_id = Y                                          │
│  - Personal notes, scripts                              │
├─────────────────────────────────────────────────────────┤
│  CLIENT KB (Per Customer)                               │
│  - company_id = X                                       │
│  - customer_id = Z                                      │
│  - Customer-specific information                        │
└─────────────────────────────────────────────────────────┘
```

### KB Query Pattern

```python
def get_kb_entries(company_id: int, user_id: int = None, customer_id: int = None):
    query = db.query(KBEntry)

    # Platform KB (shared)
    platform_kb = query.filter(KBEntry.company_id == None)

    # Company KB
    company_kb = query.filter(KBEntry.company_id == company_id)

    # Rep KB (if user specified)
    if user_id:
        rep_kb = query.filter(
            KBEntry.company_id == company_id,
            KBEntry.user_id == user_id
        )

    # Client KB (if customer specified)
    if customer_id:
        client_kb = query.filter(
            KBEntry.company_id == company_id,
            KBEntry.customer_id == customer_id
        )

    # Combine and return
    return platform_kb.union(company_kb).all()
```

---

## Agent Action Isolation

AI agent actions are always scoped:

```sql
-- agent_actions table
CREATE TABLE agent_actions (
    id SERIAL PRIMARY KEY,
    company_id INTEGER NOT NULL,  -- Always required
    agent_id INTEGER NOT NULL,
    action_type VARCHAR(100),
    target_entity VARCHAR(100),
    target_id INTEGER,
    result JSONB,
    executed_at TIMESTAMP DEFAULT NOW()
);

-- Query pattern
SELECT * FROM agent_actions
WHERE company_id = 123  -- Always filtered
ORDER BY executed_at DESC;
```

---

## Token Usage Isolation

LLM usage is tracked per company:

```sql
-- token_usage table
CREATE TABLE token_usage (
    id SERIAL PRIMARY KEY,
    company_id INTEGER NOT NULL,
    provider VARCHAR(50),
    model VARCHAR(100),
    input_tokens INTEGER,
    output_tokens INTEGER,
    cost_cents INTEGER,
    request_id UUID,
    created_at TIMESTAMP DEFAULT NOW()
);

-- Monthly aggregation (per company)
SELECT
    company_id,
    SUM(input_tokens) as total_input,
    SUM(output_tokens) as total_output,
    SUM(cost_cents) as total_cost_cents
FROM token_usage
WHERE company_id = 123
AND created_at >= '2024-11-01'
GROUP BY company_id;
```

---

## Cross-Company Prevention

### What Could Go Wrong

```python
# BAD: No company filter - returns ALL customers!
def get_customers_DANGEROUS():
    return db.query(Customer).all()

# BAD: User can specify any company_id
def get_customers_DANGEROUS(company_id: int):
    return db.query(Customer).filter(
        Customer.company_id == company_id  # User-controlled!
    ).all()
```

### Prevention Mechanisms

```python
# GOOD: Company ID from authenticated token only
def get_customers(request: Request):
    company_id = request.scope["company_id"]  # From JWT, not user input
    return db.query(Customer).filter(
        Customer.company_id == company_id
    ).all()

# GOOD: Middleware enforces before controller runs
@app.middleware("http")
async def enforce_company_scope(request, call_next):
    if not request.scope.get("company_id"):
        if is_protected_route(request.url.path):
            return JSONResponse({"error": "Unauthorized"}, 401)
    return await call_next(request)
```

---

## Subdomain Routing

Each company can have a custom subdomain:

```
https://acme.app.solidnumber.com → company_id = 123
https://bigco.app.solidnumber.com → company_id = 456
https://app.solidnumber.com → resolved from JWT
```

### Middleware Implementation

```python
# middleware/domain_resolver.py
async def resolve_company_from_subdomain(request: Request):
    host = request.headers.get("host", "")
    subdomain = extract_subdomain(host)

    if subdomain and subdomain != "app":
        company = db.query(Company).filter(
            Company.subdomain == subdomain
        ).first()

        if company:
            request.scope["company_id"] = company.id
            return company.id

    return None
```

---

## Testing Isolation

### Unit Test Pattern

```python
# tests/test_customer_isolation.py
def test_customer_isolation():
    # Create two companies
    company_a = create_company("Company A")
    company_b = create_company("Company B")

    # Create customers for each
    customer_a = create_customer(company_a.id, "Alice")
    customer_b = create_customer(company_b.id, "Bob")

    # Service for Company A
    service_a = CustomerService(db, company_a.id)
    customers_a = service_a.get_all()

    # Should only see Company A's customers
    assert len(customers_a) == 1
    assert customers_a[0].name == "Alice"

    # Service for Company B
    service_b = CustomerService(db, company_b.id)
    customers_b = service_b.get_all()

    # Should only see Company B's customers
    assert len(customers_b) == 1
    assert customers_b[0].name == "Bob"
```

---

## Audit Trail

All company-scoped operations are logged:

```python
# services/audit_service.py
class AuditService:
    def log(
        self,
        company_id: int,
        user_id: int,
        action: str,
        resource_type: str,
        resource_id: int,
        details: dict = None
    ):
        audit = Audit(
            company_id=company_id,
            user_id=user_id,
            action=action,
            resource_type=resource_type,
            resource_id=resource_id,
            details=details,
            timestamp=datetime.utcnow()
        )
        self.db.add(audit)
        self.db.commit()
```

---

## MCP Tenant Scope

MCP server enforces tenant isolation for AI tool calls:

```python
# middleware/mcp_tenant_scope.py
async def mcp_tenant_scope(request: Request):
    # Extract company from MCP auth header
    api_key = request.headers.get("X-MCP-API-Key")
    company = validate_mcp_key(api_key)

    if company:
        request.scope["company_id"] = company.id
        request.scope["mcp_scoped"] = True
```

All MCP tool calls are automatically filtered by company_id.

---

## ⚠️ Known Exception: CRM Module Uses `tenant_company_id`

**Important:** The CRM module (`crm_contacts`, `crm_companies`, etc.) uses `tenant_company_id` instead of `company_id` for multi-tenant isolation.

```python
# Standard pattern (most tables):
SELECT * FROM orders WHERE company_id = :company_id

# CRM pattern (exception):
SELECT * FROM crm_contacts WHERE tenant_company_id = :company_id
```

### Why This Matters

If you query CRM tables with `company_id`, you may get incorrect results:

```sql
-- ❌ WRONG: Returns 0 rows even when contacts exist
SELECT COUNT(*) FROM crm_contacts WHERE company_id = 1;

-- ✅ CORRECT: Returns actual contact count
SELECT COUNT(*) FROM crm_contacts WHERE tenant_company_id = 1;
```

### They are NOT the same column — corrected 2026-08-29

⛔ **This section previously said "in practice, `tenant_company_id` always equals
`company_id`" and proposed a migration to collapse them. Both were wrong, and acting on
either would have caused a tenant leak and destroyed data.**

Verified in `solid-backend/models/crm.py`:

| column | type | foreign key | nullable |
|---|---|---|---|
| **`tenant_company_id`** | `Mapped[int]` | → **`companies.id`** (the TENANT) | **NOT NULL** |
| `company_id` | `Mapped[Optional[int]]` | → **`crm_companies.id`** (a CUSTOMER's company, B2B) | nullable |

They point at **different tables**. `company_id` on a CRM row is not a tenant at all — it
is an optional link to the B2B company that contact belongs to.

⛔ **Filtering a CRM table by `company_id` does not scope it to a tenant.** It filters by
a customer-company id that is frequently NULL. That is the leak.

⛔ **NEVER run the migration this section used to suggest**
(`UPDATE crm_contacts SET company_id = tenant_company_id`). It would overwrite every
B2B customer-company relationship in the CRM with a tenant id — silently, irreversibly,
and while looking like a tidy-up.

### Affected Tables

Every CRM table carries `tenant_company_id` as its isolation column — `crm_contacts`,
`crm_companies`, `crm_deals` and the rest. `models/crm.py` header records this as the
v0.4.0 "CRITICAL FIX: Add tenant_company_id to ALL CRM tables for multi-tenant isolation".

### If standardization is ever revisited

It is a rename of the ISOLATION column only, and it must not touch `company_id`, which
is a different relationship with its own meaning. Treat any plan that assigns one to the
other as a data-loss bug.

---

## Summary

| Layer | Mechanism | Enforcement |
|-------|-----------|-------------|
| Database | company_id FK | Schema constraint |
| ORM | CompanyScoped base | Model inheritance |
| Middleware | Token extraction | Request interception |
| MCP | API key validation | Tool call filtering |
| Service | Query filtering | Business logic |
| Controller | Context injection | Dependency injection |
| Audit | Logging | Compliance |

**Result:** Zero data leakage between companies, guaranteed at every layer.

**Note:** Remember the CRM module exception uses `tenant_company_id` - see section above.

---

## Next Steps

- [System Overview](./system-overview.md) - Full architecture
- [Data Flow](../69-Lead-Enrichment-Engine/DATA-FLOW.md) - Request lifecycles
- [Tech Stack](./tech-stack.md) - Technologies used


--- FILE: 01-Architecture/MULTI-TENANT-PARITY.md ---

---
topic: architecture
keywords: [architecture, across, actions, adding, automatically, blocking, check, clean]
code_paths:
  - solid-backend/scripts/lint_multi_tenant.py
last_verified: 2026-05-25
status: current
priority: critical
owner: platform-team
---

# Multi-Tenant Code Parity System

> **CRITICAL**: This document describes how Solid# ensures that code works identically for ALL company IDs. Violations of these principles will cause features to break for real customers.
>
> **Why this design:** Built after a real production incident (2025-12-22) where Company 1 showed transactions but Company 3 showed "No results" for the same feature. Root cause: INNER JOIN on a nullable FK — seeded data had populated fields, real data did not. The 3-layer enforcement (pre-commit lint, CI pipeline, parity tests) makes this class of bug structurally impossible. LEFT JOINs on nullable FKs, NULL-safe accessors, and the ban on hardcoded company_ids are non-negotiable.
>
> **When this applies:** Every time you write or review a database query. The linter (`scripts/lint_multi_tenant.py`) runs on every commit.

## The Problem We Solved

On **2025-12-22**, we discovered a critical bug:
- Company 1 (dev/seeded data) showed transactions in the dashboard
- Company 3 (real customer data) showed "No results" for the same feature

**Root Cause**: The dashboard query used `INNER JOIN products` which excluded orders without `product_id`. Company 1's seeded data had 100% `product_id` populated, but real orders often don't have this field.

## The Principle

```
SAME CODE → DIFFERENT DATA → SAME BEHAVIOR

┌─────────────────────┐     ┌─────────────────────┐
│ Company 1 (Dev)     │     │ Company 4000 (Future)│
│ - Seeded test data  │     │ - Real user data     │
│ - All fields set    │     │ - Some fields NULL   │
└──────────┬──────────┘     └──────────┬──────────┘
           │                           │
           ▼                           ▼
      ┌────────────────────────────────────┐
      │         UNIVERSAL CODE             │
      │  - Uses LEFT JOINs                 │
      │  - Handles NULLs gracefully        │
      │  - No hardcoded company_id         │
      │  - Queries by JWT company_id       │
      └────────────────────────────────────┘
           │                           │
           ▼                           ▼
┌─────────────────────┐     ┌─────────────────────┐
│ Shows Company 1     │     │ Shows Company 4000  │
│ data correctly      │     │ data identically    │
└─────────────────────┘     └─────────────────────┘
```

## Company ID Architecture

| Company ID | Purpose | Data Type |
|------------|---------|-----------|
| 1 | SolidNumber (Development) | Seeded demo data |
| 2 | Template Company | Blank template for cloning |
| 3+ | Real Customers | Real production data |

**Key Rule**: Code changes in Company 1 MUST automatically work for Company 2+. There is ONE codebase for ALL companies.

## Enforcement System

We have three layers of enforcement:

### 1. Pre-Commit Hook (Local)
```bash
# Automatically runs on every commit
.git/hooks/pre-commit → scripts/lint_multi_tenant.py
```
- Blocks commits with multi-tenant violations
- Developer must fix issues before committing

### 2. CI Pipeline (GitHub Actions)
```yaml
# .github/workflows/tests.yml
multi-tenant-check:
  - Run Multi-Tenant Linter
  - Fails PR if violations found
```
- Catches issues if pre-commit hook is bypassed
- Blocks PR merge until fixed

### 3. Parity Tests
```bash
pytest tests/test_company_parity.py -v
```
- Verifies data patterns across companies
- Documents differences between seeded and real data

## Coding Standards

### Rule 1: Use LEFT JOIN for Nullable Foreign Keys

**Nullable FKs in `orders` table:**
- `product_id` - Orders may not have a product
- `contact_id` - Orders may not be linked to CRM contact

```sql
-- WRONG: Excludes orders without product_id
SELECT * FROM orders o
JOIN products p ON o.product_id = p.id
WHERE o.company_id = :company_id

-- CORRECT: Includes ALL orders
SELECT * FROM orders o
LEFT JOIN products p ON o.product_id = p.id
WHERE o.company_id = :company_id
```

### Rule 2: Handle NULL Values

```python
# WRONG: Crashes if product_name is NULL
product_name = result.product_name

# CORRECT: Graceful fallback
product_name = result.product_name or "Unknown Product"
```

### Rule 3: SQLAlchemy - Use outerjoin or isouter=True

```python
# WRONG: INNER JOIN by default
query.join(Product, Order.product_id == Product.id)

# CORRECT: LEFT JOIN
query.outerjoin(Product, Order.product_id == Product.id)
# OR
query.join(Product, Order.product_id == Product.id, isouter=True)
```

### Rule 4: Never Hardcode Company IDs

```python
# WRONG: Hardcoded company
orders = db.query(Order).filter(Order.company_id == 1).all()

# CORRECT: From JWT/session
company_id = current_user.company_id  # From authenticated user
orders = db.query(Order).filter(Order.company_id == company_id).all()
```

## Known Intentional Exceptions

Some queries intentionally use INNER JOIN for business logic:

| File | Line | Reason |
|------|------|--------|
| dashboard.py | 485 | Top Products report - ranks products by sales |
| dashboard.py | 962 | Revenue by Product - groups by product |
| report_service.py | 432 | Top Items report - product ranking |

These are documented in `scripts/lint_multi_tenant.py` under `KNOWN_INTENTIONAL`.

## Running the Linter

```bash
# Check for multi-tenant issues
python scripts/lint_multi_tenant.py

# Expected output if clean:
# ✅ No multi-tenant issues found!

# If issues found:
# ⚠️ Found N potential issues:
# 📁 file.py
#    Line X: [INNER_JOIN_NULLABLE_FK]
#    → INNER JOIN on nullable 'product_id'...
```

## Adding New Exceptions

If you have a legitimate reason for INNER JOIN on a nullable FK:

1. Add to `KNOWN_INTENTIONAL` in `scripts/lint_multi_tenant.py`:
```python
KNOWN_INTENTIONAL = [
    ("path/to/file.py", line_number, "Reason why this is intentional"),
]
```

2. Document the reason in code comments
3. Ensure the feature handles the case appropriately

## Testing Company Parity

```bash
# Run parity tests
pytest tests/test_company_parity.py -v -s

# This verifies:
# - Orders visible regardless of product_id
# - Dashboard queries don't exclude data
# - Revenue reports include all orders
# - Data patterns documented across companies
```

## Troubleshooting

### "No results" for a feature in Company 3+

1. Check if the query uses INNER JOIN on nullable FK
2. Run the linter: `python scripts/lint_multi_tenant.py`
3. Compare data patterns:
```sql
SELECT company_id,
       COUNT(*) as total,
       COUNT(product_id) as with_product
FROM orders
GROUP BY company_id;
```

### Pre-commit hook blocking commit

1. Read the error message - it tells you the file and line
2. Change `JOIN` to `LEFT JOIN` or add `isouter=True`
3. If intentional, add to `KNOWN_INTENTIONAL` with documentation

### CI failing on multi-tenant check

Same as pre-commit - fix the issue or document the exception.

## Summary

| Layer | When | Action |
|-------|------|--------|
| Pre-commit hook | Every commit | Blocks if violations |
| CI pipeline | Every PR | Fails build if violations |
| Parity tests | On demand | Documents data differences |

**Remember**: If it works for Company 1, it MUST work for Company 4000. Same code, different data, same behavior.

---

*Created: 2025-12-22*
*Reason: Dashboard transaction list showed "No results" for Company 3 due to INNER JOIN on nullable product_id*


--- FILE: 01-Architecture/SYSTEM-OVERVIEW.md ---

---
topic: architecture
keywords: [architecture, accounting, affiliate, agent, ai-first, authentication, backend, base]
code_paths:
  - solid-backend/agents/registry.py
  - solid-backend/api/routers/vibe.py
  - solid-backend/app.py
  - solid-backend/celery_app.py
  - solid-backend/mcp/tools/kb_contact_learn.py
  - solid-backend/mcp/tools/validation_api.py
  - solid-backend/mcp/tools/validation_journey.py
  - solid-backend/mcp/tools/validation_pages.py
  - solid-backend/services/knowledge_base/layers.py
  - solid-backend/services/vibe/entity_executors.py
  - solid-backend/services/vibe/vibe_engine.py
  - solid-backend/services/vibe/vibe_history.py
  - solid-backend/services/vibe/vibe_safety.py
  - solid-frontend/src/app/layout.tsx
  - solid-frontend/src/lib/api/client.ts
last_verified: 2026-08-29
status: current
priority: critical
owner: platform-team
---

# System Overview

> ## ⛔ CORRECTED 2026-08-30 — this document predates the move to the cell.
> Production is the **`solid-production` cell** (DOKS, nyc1), not a single droplet.
> `solidnumber.com` resolves to the app load balancer **`134.199.179.65`** (voice to
> `134.199.179.67`); TLS is terminated by Caddy **in the cluster**, not on a box.
> The SFO droplet `<production-host>` is out of the request path for `solidnumber.com` and
> is kept alive only because two apex customer domains still hold its native IP —
> ⛔ **it must not be destroyed.**
> Live state: **`06-Operations/00-INFRA-TRUTH.md`** (generated from `doctl`/`kubectl`/`dig`).
> Deploying: **`06-Operations/00-DEPLOY-START-HERE.md`**.
> Statements below about a single droplet, an SSH deploy, or "no load balancer" are stale.


> **Solid# is AI Business Infrastructure** — one platform replacing 10+ vertical SaaS tools because AI agents need unified data to act. They cannot orchestrate across disconnected APIs with different auth models.
>
> **Why this design:** The monolithic-but-modular architecture (one backend, one database, shared models) was chosen over microservices because cross-entity operations (e.g., an agent booking an appointment, sending a confirmation, and charging a card) must happen in a single transaction boundary. CRM and Payments are capabilities, not the product — 55% of the codebase is AI services.
>
> **When this applies:** This is the top-level map. Consult it when you need to understand which subsystem owns a capability, how the 32 AI agents relate to the 273 background task functions, or where a new feature should live.

---

## Platform at a Glance

| Metric | Count |
|--------|-------|
| **Lines of Code** | 5.32M (5,324,767 lines) across 16 repositories |
| **AI Agents** | 32 (33 registry entries, 23 deeply trained; Sarah, Marcus, Devon, ADA + more) — customer-facing personalities |
| **Background Task Functions** | 271 Celery task functions (156 scheduled — scans, syncs, audits, drip campaigns) |
| **MCP Tools** | 655 |
| **Industry Templates** | 58 (MCC mapped) |
| **API Endpoints** | 2,242 routes |
| **Database Tables** | 627, isolated by `company_id` + row-level security policies enforced at the DB level by the non-superuser `solid_app` role |
| **AI Features** | 30+ specialized systems |
| **Vibe Coding Entities** | 10 types (63 tests passing) |
| **LLM Providers** | 7 supported |
| **Total Documentation** | 1,959 files across 97 sections |
| **Platform Integrations** | 18+ (Google, Microsoft, TikTok, Instagram, etc.) |

*Last verified: 2026-08-29 — see `Owners-Manual/PLATFORM-METRICS.md` for auto-generated authoritative numbers.*

---

## The Complete Business Suite (AI-First)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    SOLID# - THE COMPLETE BUSINESS OPERATING SYSTEM              │
│                                                                                  │
│           "Replace 10+ tools with ONE platform. AI runs everything."            │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         CRM & SALES                                      │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Contacts    │ │ Leads       │ │ Deals       │ │ Pipeline    │       │   │
│  │  │ Management  │ │ w/ AI Score │ │ Tracking    │ │ Forecasting │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Custom      │ │ Tags &      │ │ Activity    │ │ Import/     │       │   │
│  │  │ Fields      │ │ Segments    │ │ Timeline    │ │ Export      │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │                                                                          │   │
│  │  AI: Lead scoring 0-100, LTV prediction, lookalike finder, auto-nurture │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                                                                  │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         MARKETING AUTOMATION                             │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Email       │ │ SMS         │ │ Drip        │ │ A/B         │       │   │
│  │  │ Campaigns   │ │ Campaigns   │ │ Sequences   │ │ Testing     │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Social      │ │ Landing     │ │ Forms       │ │ Surveys     │       │   │
│  │  │ Media       │ │ Pages       │ │ Builder     │ │ w/ AI       │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │                                                                          │   │
│  │  AI: Content generation, send-time optimization, engagement prediction   │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                                                                  │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         E-COMMERCE & SHOP                                │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Product     │ │ Shopping    │ │ Checkout    │ │ Order       │       │   │
│  │  │ Catalog     │ │ Cart        │ │ Flow        │ │ Management  │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Inventory   │ │ Multi-      │ │ Shipping    │ │ Returns &   │       │   │
│  │  │ Tracking    │ │ Location    │ │ Labels      │ │ Refunds     │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │                                                                          │   │
│  │  AI: Product recommendations, abandoned cart recovery, demand forecasting│   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                                                                  │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         PAYMENTS & INVOICING                             │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Card        │ │ ACH/Bank    │ │ Text2Pay    │ │ Payment     │       │   │
│  │  │ Processing  │ │ Transfer    │ │ Links       │ │ QR Codes    │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Invoicing   │ │ Recurring   │ │ BNPL        │ │ Split       │       │   │
│  │  │ w/ OCR      │ │ Billing     │ │ (Affirm)    │ │ Payments    │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │                                                                          │   │
│  │  AI: Invoice scanning, fraud detection, dunning optimization             │   │
│  │  2.9% + $0.30 via Stripe | 0.5% if using own processor                    │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                                                                  │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         POINT OF SALE (POS)                              │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Terminal    │ │ Card        │ │ Tip         │ │ Receipt     │       │   │
│  │  │ Support     │ │ Reader      │ │ Adjustment  │ │ Printing    │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Lane        │ │ Cash        │ │ Barcode     │ │ Offline     │       │   │
│  │  │ Management  │ │ Drawer      │ │ Scanning    │ │ Mode        │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │                                                                          │   │
│  │  AI: Smart upsells at checkout, customer recognition, loyalty prompts    │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                                                                  │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         APPOINTMENTS & SCHEDULING                        │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Online      │ │ Calendar    │ │ Reminders   │ │ Recurring   │       │   │
│  │  │ Booking     │ │ Sync        │ │ (SMS/Email) │ │ Appointments│       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Service     │ │ Staff       │ │ Buffer      │ │ Waitlist    │       │   │
│  │  │ Types       │ │ Assignment  │ │ Time        │ │ Management  │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │                                                                          │   │
│  │  AI: Smart scheduling, no-show prediction, automatic rebooking           │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                                                                  │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         WEBSITE & CMS                                    │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Page        │ │ Blog        │ │ SEO         │ │ Media       │       │   │
│  │  │ Builder     │ │ Platform    │ │ Tools       │ │ Library     │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Templates   │ │ Custom      │ │ Analytics   │ │ Multi-      │       │   │
│  │  │ (10 blocks) │ │ Domains     │ │ Dashboard   │ │ Site        │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │                                                                          │   │
│  │  AI: Page generation from prompts, blog writing, SEO optimization        │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                                                                  │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         AI CHAT & SUPPORT                                │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Website     │ │ SMS         │ │ Voice       │ │ WhatsApp    │       │   │
│  │  │ Chatbot     │ │ Bot         │ │ AI (Twilio) │ │ Integration │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Knowledge   │ │ Conversation│ │ Human       │ │ Ticket      │       │   │
│  │  │ Base RAG    │ │ Memory      │ │ Handoff     │ │ Creation    │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │                                                                          │   │
│  │  AI: 6 personalities, persistent memory, KB-grounded responses           │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                                                                  │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         ANALYTICS & REPORTING                            │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Revenue     │ │ Lead        │ │ Campaign    │ │ Customer    │       │   │
│  │  │ Dashboard   │ │ Analytics   │ │ Performance │ │ Insights    │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐       │   │
│  │  │ Custom      │ │ Export      │ │ Scheduled   │ │ AI          │       │   │
│  │  │ Reports     │ │ (CSV/PDF)   │ │ Reports     │ │ Discoveries │       │   │
│  │  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘       │   │
│  │                                                                          │   │
│  │  AI: Proactive insights, anomaly detection, growth recommendations       │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                                                                  │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         INTEGRATIONS                                     │   │
│  │                                                                          │   │
│  │  Workspace:        Accounting:         Ads:             Communication:  │   │
│  │  • Google          • QuickBooks        • Google Ads     • Twilio        │   │
│  │  • Microsoft 365   • Xero              • Meta Ads       • Resend        │   │
│  │  • Native Email    • FreshBooks        • LinkedIn Ads   • SES           │   │
│  │                                                                          │   │
│  │  AI Providers:     Payments:           Data:            Embeds:         │   │
│  │  • OpenAI          • Stripe            • CSV Import     • Chat Widget   │   │
│  │  • Anthropic       • PayPal            • API Access     • Booking       │   │
│  │  • Google Gemini   • Square            • Webhooks       • Checkout      │   │
│  │  • xAI Grok                            • MCP Server     • Forms         │   │
│  │  • Meta Llama      • Affirm/Klarna     • (655 tools)  • Surveys       │   │
│  │                                                                          │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

### Platform Modes (User Choice)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    PLATFORM MODES - YOUR BUSINESS, YOUR WAY                      │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  Choose how you want to work. All features available in every mode.             │
│                                                                                  │
│  ┌──────────────────────┐  ┌──────────────────────┐  ┌──────────────────────┐  │
│  │    GOOGLE MODE       │  │   MICROSOFT MODE     │  │    NATIVE MODE       │  │
│  │                      │  │                      │  │                      │  │
│  │  For Google Shops    │  │  For Microsoft Shops │  │  For Independent     │  │
│  │                      │  │                      │  │                      │  │
│  │  ✓ Gmail             │  │  ✓ Outlook           │  │  ✓ Email/Password    │  │
│  │  ✓ Google Calendar   │  │  ✓ Microsoft 365     │  │  ✓ Built-in Calendar │  │
│  │  ✓ Google Drive      │  │  ✓ OneDrive          │  │  ✓ Local Storage     │  │
│  │  ✓ Google Meet       │  │  ✓ Teams             │  │  ✓ Zoom/Generic      │  │
│  │  ✓ Gemini AI         │  │  ✓ Copilot AI        │  │  ✓ All AI Providers  │  │
│  │                      │  │                      │  │                      │  │
│  │  Single Sign-On      │  │  Single Sign-On      │  │  2FA Options:        │  │
│  │  via Google          │  │  via Microsoft       │  │  • TOTP (Authy)      │  │
│  │                      │  │                      │  │  • WebAuthn/Passkeys │  │
│  │                      │  │                      │  │  • Face ID/Touch ID  │  │
│  └──────────────────────┘  └──────────────────────┘  └──────────────────────┘  │
│                                                                                  │
│  All modes get: Full CRM, E-commerce, Payments, 32 AI Agents, 58 Templates      │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

### What You're Replacing

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    TOOLS SOLID# REPLACES                                         │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  BEFORE SOLID#                              WITH SOLID#                         │
│  ════════════════                           ═══════════                         │
│                                                                                  │
│  CRM:                                       ┌─────────────────────────────────┐ │
│  • Salesforce ($150/user)                   │                                 │ │
│  • HubSpot ($45/user)                       │         ONE PLATFORM            │ │
│  • Zoho CRM ($35/user)                      │                                 │ │
│                                              │    All features included        │ │
│  Marketing:                                  │    32 AI agents working 24/7   │ │
│  • Mailchimp ($350/mo)                      │    58 industry templates        │ │
│  • Constant Contact ($65/mo)                │                                 │ │
│  • ActiveCampaign ($229/mo)                 │    Starting at $89/month        │ │
│                                              │                                 │ │
│  E-commerce:                                 │    No per-seat pricing          │ │
│  • Shopify ($299/mo)                        │    No feature limits            │ │
│  • WooCommerce + hosting                    │    No integration headaches     │ │
│  • BigCommerce ($299/mo)                    │                                 │ │
│                                              │    ─────────────────────────    │ │
│  Appointments:                               │                                 │ │
│  • Calendly ($12/user)                      │    Typical savings:              │ │
│  • Acuity ($23/mo)                          │    $2,000 - $4,000/month        │ │
│  • Square Appointments                      │                                 │ │
│                                              │    ROI: 10-30x                  │ │
│  Payments:                                   │                                 │ │
│  • Square (2.9%)                            │    2.9%+$0.30 via Stripe        │ │
│  • Stripe (2.9%)                            │    (0.5% if own processor)      │ │
│                                              │                                 │ │
│  Chat:                                       └─────────────────────────────────┘ │
│  • Intercom ($74/mo)                                                            │
│  • Drift ($400/mo)                                                              │
│  • Zendesk ($55/agent)                                                          │
│                                                                                  │
│  TOTAL: $2,000 - $4,000/month               SOLID#: $89 - $499/month           │
│  + Integration hell                          + Everything just works            │
│  + Different logins                          + AI runs it all                   │
│  + Data silos                                + Single source of truth           │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## High-Level Architecture

> **Edge state (2026-08-30):** DNS is still on GoDaddy (`ns35/ns36.domaincontrol.com`), but every A record for `solidnumber.com` — apex, `*`, api, app, dev, enroll, mcp — now points at the cell's app load balancer **`134.199.179.65`** (`voice` at `134.199.179.67`). The 2026-05-09 line said they pointed direct at the droplet `<production-host>`; that stopped being true on 2026-08-30. Caddy on the box terminates TLS (HTTP/2 + HTTP/3) and reverse-proxies to the Next.js + FastAPI containers. **Cloudflare is NOT in front of the app today** — the only Cloudflare integration is R2 object storage. Cloudflare proxy + WAF + Turnstile are PLANNED, tracked separately. Don't quote this diagram as deployed perimeter.

```
                                    ┌─────────────────┐
                                    │     Caddy       │
                                    │  (TLS, H2/H3)   │
                                    │  ⚠️ Cloudflare  │
                                    │  proxy PLANNED  │
                                    └────────┬────────┘
                                             │
              ┌──────────────────────────────┼──────────────────────────────┐
              │                              │                              │
              ▼                              ▼                              ▼
    ┌─────────────────┐          ┌─────────────────┐          ┌─────────────────┐
    │  solid-public   │          │ solid-frontend  │          │  solid-backend  │
    │   (Next.js)     │          │   (Next.js)     │          │   (FastAPI)     │
    │   Port 3001     │          │   Port 3000     │          │   Port 8090     │
    │                 │          │                 │          │                 │
    │ - Marketing     │          │ - Dashboard     │          │ - REST API      │
    │ - MCP Server    │          │ - CRM           │          │ - WebSocket     │
    │ - Demo Pages    │          │ - AI Hub        │          │ - MCP Tools     │
    │ - Blog/CMS      │          │ - Gateway       │          │ - 32 AI Agents  │
    │ - Embeds        │          │ - POS           │          │ - SmartRouter   │
    └────────┬────────┘          └────────┬────────┘          └────────┬────────┘
             │                            │                            │
             │                            │                            │
             └────────────────────────────┼────────────────────────────┘
                                          │
                                          ▼
                               ┌─────────────────────┐
                               │    PostgreSQL       │
                               │    Port 5432        │
                               │                     │
                               │  - 369 models       │
                               │  - Multi-tenant     │
                               │  - company_id FK    │
                               │  - RLS policies     │
                               └─────────────────────┘
                                          │
              ┌───────────────────────────┼───────────────────────────┐
              │                           │                           │
              ▼                           ▼                           ▼
    ┌─────────────────┐        ┌─────────────────┐        ┌─────────────────┐
    │     Redis       │        │     Celery      │        │  Token Orch.    │
    │   Port 6379     │        │    Workers      │        │   Port 8091     │
    │                 │        │                 │        │                 │
    │ - Cache         │        │ - Background    │        │ - SmartRouter   │
    │ - Event Bus     │        │   Tasks (30+)   │        │ - LLM Billing   │
    │ - Session       │        │ - AI Jobs       │        │ - Usage Track   │
    │ - Celery Broker │        │ - Agent Chains  │        │ - Cost Intel    │
    │ - 2FA State     │        │ - Video Gen     │        │ - 7 Providers   │
    └─────────────────┘        └─────────────────┘        └─────────────────┘
```

---

## AI Systems Architecture

### The AI Ecosystem

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                         SOLID# AI ECOSYSTEM                                      │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  CORE AI AGENTS (The Vegetable Team)                                            │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   SAGE         MARCUS        DEVON         ADA                           │  │
│  │   Customer     Growth        Operations    System                        │  │
│  │   Chat         Intelligence  Automation    Orchestrator                  │  │
│  │   ↓            ↓             ↓             ↓                             │  │
│  │   Uses         Uses          Uses          Coordinates                   │  │
│  │   SmartRouter  Industry KB   Agent Chains  All Agents                    │  │
│  │                                                                           │  │
│  │   + 110 MORE SPECIALIZED AGENTS                                          │  │
│  │   Food Agents (24) - KB Onboarding (Apple, Kale, Beet, etc.)            │  │
│  │   Veggie Agents (9) - CRM Automation                                     │  │
│  │   Fruit Agents (4) - LLM Support                                         │  │
│  │   Bread Agents (4) - Healthcare/HIPAA                                    │  │
│  │   Emma - Lead Targeting & Prospecting (NEW Jan 2026)                     │  │
│  │   Victor - Platform Quality Engineer (NEW Jan 2026)                      │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  AI BRIDGE (SmartRouter)                                                        │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐           │  │
│  │   │ OpenAI  │ │Anthropic│ │ Google  │ │   xAI   │ │  Meta   │           │  │
│  │   │ GPT-4o  │ │ Claude  │ │ Gemini  │ │  Grok   │ │ Llama   │           │  │
│  │   └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘           │  │
│  │        └───────────┴──────────┬┴───────────┴───────────┘                │  │
│  │                               │                                          │  │
│  │                    ┌──────────▼──────────┐                              │  │
│  │                    │    SmartRouter      │                              │  │
│  │                    │                     │                              │  │
│  │                    │  • Cost optimization│                              │  │
│  │                    │  • Quality routing  │                              │  │
│  │                    │  • Failover         │                              │  │
│  │                    │  • Load balancing   │                              │  │
│  │                    └─────────────────────┘                              │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  AI HUB (Two-Layer Architecture)                                                │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   LAYER 1: Platform AI (Always Available)                                │  │
│  │   └── Sarah, Marcus, Devon, Victor, ADA - Uses Solid#'s API keys         │  │
│  │   └── Included in subscription with token limits                        │  │
│  │                                                                           │  │
│  │   LAYER 2: Customer's Own Keys (Optional)                                │  │
│  │   └── Customers can add their own Gemini/Claude/GPT keys                │  │
│  │   └── Unlimited usage, they pay provider directly                        │  │
│  │   └── AES-256 encrypted storage                                          │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

### AI Security & Observability

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                         AI PROTECTION SYSTEMS                                    │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  PromptGuard (5-Layer Protection)           AgentTelemetry (Observability)      │
│  ┌────────────────────────────────┐        ┌────────────────────────────────┐  │
│  │ Layer 1: Input Sanitization    │        │ • Dead Agent Detection         │  │
│  │ Layer 2: Pattern Detection     │        │ • Performance Drift Alerts     │  │
│  │ Layer 3: Canary Tokens         │        │ • A/B Experiment Framework     │  │
│  │ Layer 4: Output Validation     │        │ • Cost per Agent Tracking      │  │
│  │ Layer 5: Audit Trail           │        │ • Health Dashboard             │  │
│  └────────────────────────────────┘        └────────────────────────────────┘  │
│                                                                                  │
│  CognitiveLimiter (Cost Intelligence)       Agentic Memory (4-Tier)            │
│  ┌────────────────────────────────┐        ┌────────────────────────────────┐  │
│  │ • Per-company token budgets    │        │ Tier 1: Short-term (session)   │  │
│  │ • Tier-based limits            │        │ Tier 2: Medium-term (week)     │  │
│  │ • Cost forecasting             │        │ Tier 3: Long-term (permanent)  │  │
│  │ • ROI tracking per agent       │        │ Tier 4: Cross-agent shared     │  │
│  │ • Automatic throttling         │        │                                │  │
│  └────────────────────────────────┘        └────────────────────────────────┘  │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Vibe Coding V2.5 (Natural Language Business Control)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                         VIBE CODING V2.5                                         │
│                     "Your Portal Into Destiny"                                   │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  Configure your entire business by typing what you want in plain English:       │
│                                                                                  │
│  "Add a massage for $120"              → Creates bookable service                │
│  "Create a pricing page"               → Builds CMS page with your services      │
│  "Send reminders 24h before appts"     → Creates automated workflow              │
│  "Show me this month's sales"          → Generates analytics report              │
│  "Make Sarah more autonomous"          → Configures AI agent settings            │
│  "Increase all prices by 10%"          → Updates service/product pricing         │
│                                                                                  │
│  SUPPORTED ENTITY TYPES (10)                                                     │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │ Services    Products    Pages       Forms      KB Entries                 │  │
│  │ Emails      Workflows   Reports     Agent Settings    Pricing             │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  SAFETY GUARANTEES                                                               │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │ • Can NEVER delete data (archive only)                                    │  │
│  │ • Preview before every change                                             │  │
│  │ • One-click rollback on any action                                        │  │
│  │ • Full audit trail with state_before/state_after                          │  │
│  │ • Multi-language DELETE blocking (EN/ES/FR)                               │  │
│  │ • Company isolation (company_id enforced everywhere)                      │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  AVAILABILITY: Included in ALL tiers (Starter, Builder, Professional, Enterprise)│
│                                                                                  │
│  BACKEND FILES                                                                   │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │ services/vibe/vibe_engine.py      - Claude LLM intent parsing             │  │
│  │ services/vibe/entity_executors.py - 10 executor classes                   │  │
│  │ services/vibe/vibe_safety.py      - NO DELETE enforcement                 │  │
│  │ services/vibe/vibe_history.py     - Audit trail + rollback                │  │
│  │ api/routers/vibe.py               - 14 API endpoints                      │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  Documentation: /22-Licensing/VIBE-CODING-ARCHITECTURE.md                       │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Knowledge Base Architecture (6-Layer)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                         6-LAYER KNOWLEDGE BASE                                   │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│   LAYER 0: SYSTEM KB (Platform-wide)                                            │
│   └── Solid# documentation, system prompts, agent instructions                  │
│       ↓                                                                         │
│   LAYER 1: ORGANIZATION KB (Industry Templates)                                 │
│   └── 58 industries via MCC codes - cloned on signup                           │
│       ↓                                                                         │
│   LAYER 2: DEPARTMENT KB (Team-level)                                           │
│   └── Department-specific knowledge, SOPs, workflows                            │
│       ↓                                                                         │
│   LAYER 3: USER KB (Per employee)                                               │
│   └── Individual scripts, preferences, performance data                         │
│       ↓                                                                         │
│   LAYER 4: CONTACT KB (Per customer) ★ NEW                                      │
│   └── AI-learned customer preferences, traits, sentiment history                │
│       ↓                                                                         │
│   LAYER 5: SESSION KB (Conversation-level) ★ NEW                                │
│   └── Short-term context within active conversations                            │
│                                                                                  │
│   SPECIAL COMPANY IDs:                                                          │
│   ┌─────────────────────────────────────────────────────────────────────────┐  │
│   │ ID 1: SolidNumber Dev     - Development/testing environment             │  │
│   │ ID 2: Template Company    - Source for industry template cloning        │  │
│   │ ID 3: SolidNumber Prod    - Solid# as our own customer (dogfooding)    │  │
│   │ ID 4+: Customer Accounts  - Real paying customers                       │  │
│   └─────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│   KB Features:                                                                   │
│   • Vector Search (OpenAI embeddings, 1536 dimensions)                          │
│   • Hybrid Search (Vector + keyword with RRF)                                   │
│   • Re-ranking (GPT-4 relevance scoring)                                        │
│   • RAG Pipeline (Retrieval-Augmented Generation)                               │
│   • Goal-Driven Entries (business goals that drive AI behavior all year)        │
│   • Customer Learning (AI that remembers every customer)                        │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Customer Learning Architecture (AI That Remembers)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    CUSTOMER LEARNING ARCHITECTURE                                │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  PHILOSOPHY: "Every interaction teaches us something about the customer.        │
│               AI agents that remember create relationships, not transactions."  │
│                                                                                  │
│  HOW IT WORKS                                                                    │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Customer Interaction → AI Agent → kb.contact_learn → Contact KB        │  │
│  │                                                                           │  │
│  │   ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────────┐ │  │
│  │   │ "I prefer text  │    │  Sarah (Agent)  │    │   Contact KB Entry  │ │  │
│  │   │  over calls,    │───▶│  Extracts:      │───▶│                     │ │  │
│  │   │  mornings work  │    │  - Preferences  │    │ communication: text │ │  │
│  │   │  best for me"   │    │  - Sentiment    │    │ time_pref: mornings │ │  │
│  │   └─────────────────┘    │  - Tier signals │    │ sentiment: positive │ │  │
│  │                          └─────────────────┘    └─────────────────────┘ │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  MCP TOOLS (6 Customer Learning Tools)                                          │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   kb.contact_learn          - Save learnings after customer interactions │  │
│  │   kb.contact_get            - Retrieve all knowledge about a customer    │  │
│  │   kb.contact_search         - Find customers by traits (VIP, etc.)       │  │
│  │   kb.contact_insights       - Generate AI insights (churn risk, upsells) │  │
│  │   kb.contact_update_consent - Update GDPR consent flags (NEW)            │  │
│  │   kb.contact_request_deletion - Handle right to be forgotten (NEW)       │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  GDPR COMPLIANCE (Built-In)                                                      │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Consent Flags (Per Customer):                                          │  │
│  │   • ai_learning         - Can AI learn from interactions?               │  │
│  │   • ai_personalization  - Can AI personalize experiences?               │  │
│  │   • marketing_emails    - Can we send marketing emails?                 │  │
│  │   • sms_notifications   - Can we send SMS?                              │  │
│  │   • data_sharing        - Can we share with third parties?              │  │
│  │                                                                           │  │
│  │   Right to Be Forgotten:                                                 │  │
│  │   • gdpr_deletion_requested flag stops all AI learning                  │  │
│  │   • Data anonymization after retention period                           │  │
│  │   • Full audit trail of consent changes                                 │  │
│  │                                                                           │  │
│  │   Files: services/knowledge_base/layers.py (GDPR fields)                │  │
│  │          mcp/tools/kb_contact_learn.py (consent checks)                 │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  CUSTOMER TIER SYSTEM (Auto-calculated)                                         │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐                    │  │
│  │   │   NEW   │  │STANDARD │  │PREFERRED│  │   VIP   │                    │  │
│  │   │ Default │─▶│ $100+   │─▶│ $500+   │─▶│ $1000+  │                    │  │
│  │   │         │  │ or 2ord │  │ or 5ord │  │ or 10ord│                    │  │
│  │   └─────────┘  └─────────┘  └─────────┘  └─────────┘                    │  │
│  │                                                                           │  │
│  │   Tier affects: AI tone, offer priority, service level, recommendations  │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  SENTIMENT TRACKING                                                              │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Per-Interaction:      Trend Analysis:       Automated Actions:         │  │
│  │   • positive            • improving ↗         • Low health → Alert CS    │  │
│  │   • neutral             • stable →            • Declining → Re-engage    │  │
│  │   • negative            • declining ↘         • VIP + negative → Urgent  │  │
│  │                                                                           │  │
│  │   Health Score: 0-100 (composite of sentiment, tier, activity)           │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  AGENTS WITH CUSTOMER LEARNING                                                   │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Sarah (customer_service) - Primary learner, uses after every chat      │  │
│  │   Jake (inventory_manager) - Tracks service history preferences          │  │
│  │   Marcus (growth_strategist) - Identifies upsell opportunities           │  │
│  │   Devon (operations) - Monitors customer health metrics                  │  │
│  │   ADA (orchestrator) - Coordinates proactive re-engagement               │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  CRM SYNC (Automatic)                                                           │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   New Contact Created → ContactKBSync → Contact KB Entry Initialized     │  │
│  │                                                                           │  │
│  │   Syncs: name, email, phone, tags, first interaction timestamp           │  │
│  │   Sets: Default tier (new), empty preferences, ready for learning        │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  Documentation: /09-Core-Innovations/CUSTOMER-LEARNING-ARCHITECTURE.md          │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## AI Creative Communications

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    AI CREATIVE COMMUNICATIONS SYSTEM                             │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  PHILOSOPHY: "AI isn't about taking jobs. It's about strengthening              │
│               human connection through delightful moments."                      │
│                                                                                  │
│  AI VIDEO STUDIO                                                                │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Video Providers:        Output Channels:        Use Cases:             │  │
│  │   ┌─────────────┐        ┌─────────────┐        ┌─────────────────────┐ │  │
│  │   │ Sora        │        │ Email       │        │ Welcome videos      │ │  │
│  │   │ Veo         │───────▶│ SMS         │───────▶│ Trial reminders     │ │  │
│  │   │ Runway      │        │ Push        │        │ Celebration moments │ │  │
│  │   │ Pika        │        │ In-App      │        │ Support follow-ups  │ │  │
│  │   │ Kling       │        │ Social      │        │ Payment thank-yous  │ │  │
│  │   └─────────────┘        └─────────────┘        └─────────────────────┘ │  │
│  │                                                                           │  │
│  │   Model: Embed-First (links, no storage overhead)                        │  │
│  │   Overlays: Text, logos, CTAs on any video                               │  │
│  │   Freemium: 5 free/month, pro costs tokens                               │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  TEMPLATE + ANCHOR MODEL                                                        │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Templates are pre-approved by compliance/legal                         │  │
│  │   ┌─────────────────────────────────────────────────────────────────┐   │  │
│  │   │  "Hi {customer_name}, your {product} order is ready! Here's a   │   │  │
│  │   │   special {discount}% off your next purchase: {video_url}"      │   │  │
│  │   └─────────────────────────────────────────────────────────────────┘   │  │
│  │                                                                           │  │
│  │   AI fills the anchors (variables) at send time:                         │  │
│  │   • customer_name = "Tracy"                                              │  │
│  │   • product = "Invisalign consultation"                                  │  │
│  │   • discount = 15                                                         │  │
│  │   • video_url = "dancing tooth celebration"                              │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  POSITIVE ANCHORING (Joy System)                                                │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Celebration Triggers:    Gamification:         Emotion Memory:         │  │
│  │   • First sale             • Points system       • AI remembers wins     │  │
│  │   • Goal reached           • Streaks             • References past       │  │
│  │   • Milestone hit          • Badges              • Builds on success     │  │
│  │   • Team achievement       • Leaderboards        • Personalized joy      │  │
│  │                                                                           │  │
│  │   Output: Confetti, animations, video celebrations, team notifications   │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Document Formatting Engine (AI↔Human Bridge)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    DOCUMENT FORMATTING ENGINE                                    │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  PHILOSOPHY: "AI speaks Markdown. Humans speak Google Docs."                    │
│                                                                                  │
│  ANY-TO-ANY FORMAT CONVERSION                                                   │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │      INPUT                    ENGINE                    OUTPUT           │  │
│  │   ┌─────────────┐        ┌─────────────┐        ┌─────────────────────┐ │  │
│  │   │ Markdown    │        │             │        │ Google Docs         │ │  │
│  │   │ Word Doc    │        │   AI-Powered│        │ Word Doc            │ │  │
│  │   │ PDF         │───────▶│   Format    │───────▶│ PDF                 │ │  │
│  │   │ HTML        │        │   Bridge    │        │ HTML                │ │  │
│  │   │ Plain Text  │        │             │        │ Email Template      │ │  │
│  │   │ Photo       │        │             │        │ Presentation        │ │  │
│  │   └─────────────┘        └─────────────┘        └─────────────────────┘ │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  MULTI-OUTPUT (One Input → Many Formats)                                        │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   User pastes budget notes → AI outputs:                                 │  │
│  │   ├── Spreadsheet (Google Sheets)                                        │  │
│  │   ├── PDF report                                                          │  │
│  │   ├── Email summary                                                       │  │
│  │   └── Presentation slide                                                  │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  IMAGE-TO-DOCUMENT                                                              │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Photo of whiteboard → Structured meeting notes                         │  │
│  │   Screenshot of data → Formatted spreadsheet                             │  │
│  │   Handwritten notes → Typed document                                      │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Sales Intelligence Research

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    SALES INTELLIGENCE RESEARCH                                   │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  COMPANY RESEARCH PIPELINE                                                      │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   INPUT: "Research MoveDocs"                                             │  │
│  │                    │                                                      │  │
│  │                    ▼                                                      │  │
│  │   ┌─────────────────────────────────────────────────────────────────┐   │  │
│  │   │  AI RESEARCH ENGINE                                              │   │  │
│  │   │  ├── Company Overview (founded, HQ, size, revenue)              │   │  │
│  │   │  ├── Key People (decision makers, LinkedIn)                     │   │  │
│  │   │  ├── Tech Stack (what they use)                                 │   │  │
│  │   │  ├── Pain Points (from reviews, complaints)                     │   │  │
│  │   │  ├── Competitive Position (market standing)                     │   │  │
│  │   │  └── Recent News (funding, launches, changes)                   │   │  │
│  │   └─────────────────────────────────────────────────────────────────┘   │  │
│  │                    │                                                      │  │
│  │                    ▼                                                      │  │
│  │   OUTPUT (Multi-Format):                                                 │  │
│  │   ├── Research Report (PDF/MD)                                           │  │
│  │   ├── Spreadsheet (data table)                                           │  │
│  │   ├── CRM Lead Record (auto-populated)                                   │  │
│  │   └── KB Entries (when converted to client)                              │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  PRE-TO-POST-SALE PIPELINE                                                      │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   PROSPECT → Research → Report → CRM Lead → Close → CLIENT KB            │  │
│  │                                                                           │  │
│  │   All research automatically becomes client knowledge when they sign up  │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Intelligent Contact Matching

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    INTELLIGENT CONTACT MATCHING                                  │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  PHILOSOPHY: "Duplicate contacts kill businesses. AI prevents them."            │
│                                                                                  │
│  FUZZY MATCHING ENGINE                                                          │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │  • Name variations: "Bob Smith" = "Robert Smith" = "R. Smith"            │  │
│  │  • Email patterns: personal vs business email detection                  │  │
│  │  • Phone normalization: +1 (555) 123-4567 = 5551234567                   │  │
│  │  • Address standardization: "Street" = "St" = "St."                      │  │
│  │  • Company name matching: "ABC Corp" = "ABC Corporation" = "ABC Inc"    │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  DUPLICATE DETECTION                                                            │
│  ├── Real-time matching on import                                               │
│  ├── Batch deduplication scans                                                  │
│  ├── Merge suggestions with confidence scores                                   │
│  └── Automatic enrichment from multiple sources                                 │
│                                                                                  │
│  ENRICHMENT                                                                     │
│  ├── Social profile linking                                                     │
│  ├── Company data append                                                        │
│  ├── Industry classification                                                    │
│  └── Lead scoring integration                                                   │
│                                                                                  │
│  Documentation: /09-Core-Innovations/INTELLIGENT-CONTACT-MATCHING.md            │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Agent Chains (Multi-Agent Workflows)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    AGENT CHAINS - AUTONOMOUS WORKFLOWS                           │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  PHILOSOPHY: "Complex tasks require multiple specialized agents working         │
│               together. Agent chains are the assembly line of AI."              │
│                                                                                  │
│  HOW IT WORKS                                                                    │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Trigger → Agent 1 → Agent 2 → Agent 3 → Result                         │  │
│  │                                                                           │  │
│  │   Each agent:                                                             │  │
│  │   • Has a specific role (research, write, review, execute)               │  │
│  │   • Passes context to the next agent                                      │  │
│  │   • Can branch based on results                                           │  │
│  │   • Runs autonomously without human intervention                          │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  8 PRE-BUILT CHAIN TEMPLATES                                                    │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   1. Lead Qualification Chain                                             │  │
│  │      Research → Score → Enrich → Route to Sales                          │  │
│  │                                                                           │  │
│  │   2. Content Creation Chain                                               │  │
│  │      Brief → Draft → Edit → SEO → Publish                                │  │
│  │                                                                           │  │
│  │   3. Customer Onboarding Chain                                            │  │
│  │      Welcome → KB Setup → Training → Check-in                            │  │
│  │                                                                           │  │
│  │   4. Support Escalation Chain                                             │  │
│  │      Triage → Attempt Fix → Escalate → Follow-up                         │  │
│  │                                                                           │  │
│  │   5. Sales Outreach Chain                                                 │  │
│  │      Research → Personalize → Send → Track → Follow-up                   │  │
│  │                                                                           │  │
│  │   6. Inventory Reorder Chain                                              │  │
│  │      Monitor → Alert → Quote → Approve → Order                           │  │
│  │                                                                           │  │
│  │   7. Financial Review Chain                                               │  │
│  │      Collect → Analyze → Report → Recommend                              │  │
│  │                                                                           │  │
│  │   8. Marketing Campaign Chain                                             │  │
│  │      Plan → Create → Test → Launch → Optimize                            │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  Documentation: /09-Core-Innovations/AGENT-CHAINS.md                            │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Proactive Intelligence

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    PROACTIVE INTELLIGENCE SYSTEM                                 │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  PHILOSOPHY: "AI shouldn't wait to be asked. The best assistant anticipates."   │
│                                                                                  │
│  DAILY BRIEFINGS                                                                │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Every morning, AI prepares a personalized briefing:                    │  │
│  │                                                                           │  │
│  │   • Today's appointments and priorities                                   │  │
│  │   • Key metrics changes (revenue up/down, leads, etc.)                   │  │
│  │   • Customers needing attention (at-risk, VIP follow-ups)                │  │
│  │   • Tasks due today and overdue                                           │  │
│  │   • Inventory alerts (low stock, reorders needed)                        │  │
│  │   • Weather-based suggestions (for service businesses)                   │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  SMART SUGGESTIONS                                                              │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Context-aware recommendations throughout the day:                      │  │
│  │                                                                           │  │
│  │   • "Sarah hasn't ordered in 3 weeks - send re-engagement?"              │  │
│  │   • "You have a gap at 2pm - want me to suggest leads to call?"          │  │
│  │   • "This deal has stalled - here's a follow-up template"                │  │
│  │   • "Product X is selling fast - consider reorder now"                   │  │
│  │   • "Review scores dropped - want to see recent feedback?"               │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  DELIVERY CHANNELS                                                              │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   • In-app notifications (real-time)                                      │  │
│  │   • Email digest (morning/evening summary)                                │  │
│  │   • SMS alerts (urgent items only)                                        │  │
│  │   • Push notifications (mobile app)                                       │  │
│  │   • Slack/Teams integration                                               │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  Documentation: /09-Core-Innovations/PROACTIVE-INTELLIGENCE.md                  │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Food Fight (AI Onboarding System)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    FOOD FIGHT - 25-MINUTE AI ONBOARDING                          │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  PHILOSOPHY: "Onboarding a business shouldn't take weeks.                       │
│               32 AI agents working in parallel do it in 25 minutes."           │
│                                                                                  │
│  THE 6 PHASES (Named after food - because AI agents are hungry!)                │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Phase 1: APPETIZER (0-5 min)                                           │  │
│  │   └── Initial data collection, business info, industry detection         │  │
│  │                                                                           │  │
│  │   Phase 2: SOUP (5-10 min)                                               │  │
│  │   └── Industry template selection, MCC code mapping                      │  │
│  │                                                                           │  │
│  │   Phase 3: SALAD (10-15 min)                                             │  │
│  │   └── Knowledge base generation (600+ entries)                           │  │
│  │                                                                           │  │
│  │   Phase 4: MAIN COURSE (15-20 min)                                       │  │
│  │   └── CRM setup, products, services, pricing                             │  │
│  │                                                                           │  │
│  │   Phase 5: DESSERT (20-23 min)                                           │  │
│  │   └── Marketing assets, email templates, chat personality                │  │
│  │                                                                           │  │
│  │   Phase 6: COFFEE (23-25 min)                                            │  │
│  │   └── Final review, AI introduction, ready to go live                    │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  SPECIALIZED FOOD/VEGETABLE-TEAM AGENTS WORKING IN PARALLEL                     │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   • Apple (KB Foundation)      • Kale (Industry Expert)                  │  │
│  │   • Beet (Data Validation)     • Carrot (Content Generation)             │  │
│  │   • Onion (CRM Setup)          • Pepper (Marketing Assets)               │  │
│  │   • Tomato (Product Catalog)   • Lettuce (FAQ Generation)                │  │
│  │   • ... and more specialized food/vegetable-team agents                 │  │
│  │                                                                           │  │
│  │   Each agent has a specific task, runs in parallel where possible,       │  │
│  │   and hands off to dependent agents when done.                           │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  58 INDUSTRY TEMPLATES                                                          │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Mapped to MCC codes (Merchant Category Codes):                         │  │
│  │   • Restaurant (5812)     • Hair Salon (7230)    • Dentist (8021)       │  │
│  │   • Auto Repair (7538)    • Landscaping (0780)   • Law Firm (8111)      │  │
│  │   • ... 52 more industries with pre-built templates                     │  │
│  │                                                                           │  │
│  │   Each template includes:                                                 │  │
│  │   • Industry-specific KB entries                                          │  │
│  │   • Common products/services                                              │  │
│  │   • Typical pricing structures                                            │  │
│  │   • Industry benchmarks (CAC, LTV, ROAS)                                 │  │
│  │   • Compliance requirements                                               │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  Documentation: /09-Core-Innovations/food-fight.md                              │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Affiliate & Referral Systems

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    AFFILIATE & REFERRAL SYSTEMS                                  │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  TWO-TIER AFFILIATE ARCHITECTURE                                                │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   TIER 1: Platform Affiliates (Super Admin Level)                        │  │
│  │   ├── LLM platforms (ChatGPT, Claude, Gemini) recommending Solid#       │  │
│  │   ├── Strategic partners (accounting firms, consultants)                 │  │
│  │   ├── Tech integrators and resellers                                     │  │
│  │   └── Tracked via: Special signup codes, referral URLs                   │  │
│  │                                                                           │  │
│  │   TIER 2: Company Promoters (Per-Merchant Level)                         │  │
│  │   ├── Customer referral programs                                          │  │
│  │   ├── Employee referral bonuses                                           │  │
│  │   ├── Influencer partnerships                                             │  │
│  │   └── Each company manages their own promoter network                    │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  COMMISSION STRUCTURES                                                          │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Platform Affiliates:              Company Promoters:                   │  │
│  │   • 20% revenue share (year 1)      • Configurable per company           │  │
│  │   • 10% revenue share (year 2+)     • Cash, credit, or product rewards   │  │
│  │   • Lifetime customer attribution   • Tiered bonuses available           │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  Documentation: /09-Core-Innovations/AFFILIATE-REFERRAL-SYSTEMS.md              │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## App Engine & Embeds

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    APP ENGINE & EMBEDS SYSTEM                                    │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  APP ENGINE (Plugin System)                                                     │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   12 Embeddable Apps:                                                    │  │
│  │   ├── Appointment Scheduler      ├── Product Catalog                    │  │
│  │   ├── Contact Form               ├── Invoice Payment                    │  │
│  │   ├── Chat Widget                ├── Review Collector                   │  │
│  │   ├── Survey Builder             ├── Loyalty Program                    │  │
│  │   ├── Event Registration         ├── Gift Cards                         │  │
│  │   ├── Quote Request              └── Membership Portal                  │  │
│  │                                                                           │  │
│  │   Integration Options:                                                    │  │
│  │   • iFrame embed (any website)                                           │  │
│  │   • JavaScript widget (responsive)                                        │  │
│  │   • API-only (headless)                                                  │  │
│  │   • White-label (full customization)                                     │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  EMBEDS (Widgets for External Sites)                                           │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Checkout Widget:                                                        │  │
│  │   └── Add Solid# checkout to any website                                │  │
│  │                                                                           │  │
│  │   Survey Widget:                                                          │  │
│  │   └── Embed surveys, responses go to CRM                                 │  │
│  │                                                                           │  │
│  │   Chat Widget:                                                            │  │
│  │   └── AI chat (Sarah) on any page, branded to merchant                   │  │
│  │                                                                           │  │
│  │   Booking Widget:                                                         │  │
│  │   └── Appointment scheduling, syncs to calendar                          │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  DATA IMPORT ENGINE (AI-Powered)                                                │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Upload CSV/Excel → AI auto-maps columns → Validates → Imports          │  │
│  │                                                                           │  │
│  │   Smart Features:                                                         │  │
│  │   • Fuzzy column matching ("First Name" = "fname" = "FirstName")        │  │
│  │   • Data type detection (phone, email, date, currency)                   │  │
│  │   • Duplicate detection and merge suggestions                            │  │
│  │   • Validation rules with error reporting                                │  │
│  │   • Rollback capability                                                   │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  Documentation: /09-Core-Innovations/app-engine.md, embeds-system.md            │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Service Communication

### Frontend → Backend

```
solid-frontend (Next.js)
    │
    ├── API Client (src/lib/api/client.ts)
    │   └── CSRF token management
    │   └── Cookie-based auth
    │   └── Error handling
    │
    └── Endpoints
        ├── REST: https://api.solidnumber.com/api/v1/*
        ├── WebSocket: wss://api.solidnumber.com/ws
        ├── MCP: https://solidnumber.com/api/mcp
        └── AI Hub: /api/v1/ai-hub/providers/*
```

### Backend → Database

```
solid-backend (FastAPI)
    │
    ├── SQLAlchemy ORM
    │   └── 133 model files
    │   └── 627 database tables
    │
    ├── Alembic Migrations
    │   └── Version controlled schema
    │
    └── Connection Pool
        └── PostgreSQL (async)
        └── Redis (caching)
```

### Event-Driven Communication

```
Event Publisher                    Event Consumer
      │                                  │
      │  ┌───────────────────────┐      │
      └──│      Redis Pub/Sub    │──────┘
         │                       │
         │  Events:              │
         │  - customer.created   │
         │  - order.completed    │
         │  - payment.received   │
         │  - kb.updated         │
         │  - goal.achieved      │
         │  - milestone.reached  │
         └───────────────────────┘
                    │
                    ▼
         ┌───────────────────────┐
         │   32 AI Agents        │
         │   (incl. Emma)        │
         │  Listening & Acting   │
         │  on business events   │
         └───────────────────────┘
```

---

## Multi-Tenant Isolation

Every request is scoped to a `company_id`:

```
Request Flow:
1. JWT Token contains company_id
2. Middleware extracts and validates
3. All queries filter by company_id
4. Response only includes company's data

┌─────────────────────────────────────────────────────────┐
│                    Company A (id=4)                      │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐   │
│  │Customers│  │ Orders  │  │Products │  │   KB    │   │
│  │ (1000)  │  │ (5000)  │  │  (200)  │  │ (500)   │   │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘   │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│                    Company B (id=5)                      │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐   │
│  │Customers│  │ Orders  │  │Products │  │   KB    │   │
│  │  (500)  │  │ (2000)  │  │  (50)   │  │ (300)   │   │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘   │
└─────────────────────────────────────────────────────────┘

NO DATA LEAKAGE - Guaranteed by:
- ORM model base class with company_id
- Middleware enforcement
- Database-level RLS policies
```

---

## Authentication & Security

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    AUTHENTICATION SYSTEM                                         │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  PLATFORM MODES (User Choice)                                                   │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   ┌─────────────┐    ┌─────────────┐    ┌─────────────┐                 │  │
│  │   │   Google    │    │  Microsoft  │    │   Native    │                 │  │
│  │   │  Workspace  │    │    365      │    │   (Email)   │                 │  │
│  │   └─────────────┘    └─────────────┘    └─────────────┘                 │  │
│  │                                                                           │  │
│  │   Each mode provides:                                                    │  │
│  │   • OAuth 2.0 authentication                                             │  │
│  │   • Calendar sync                                                         │  │
│  │   • Email integration                                                     │  │
│  │   • Drive/OneDrive storage                                               │  │
│  │   • Native AI tools (Gemini/Copilot)                                     │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  2FA OPTIONS (Native Mode)                                                      │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   • TOTP (Google Authenticator, Authy)                                   │  │
│  │   • WebAuthn/Passkeys (Face ID, Touch ID, YubiKey)                       │  │
│  │   • Backup Codes (one-time use)                                          │  │
│  │   • SMS (fallback only)                                                   │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  TOKEN SECURITY                                                                  │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   • JWT tokens with company_id claim                                     │  │
│  │   • Redis-stored session state                                           │  │
│  │   • AES-256 encrypted OAuth tokens                                       │  │
│  │   • Automatic token refresh                                               │  │
│  │   • CSRF protection on all mutations                                     │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## External Integrations

### Payment Processing

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    PAYMENT SUITE (25+ Features)                                  │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  PROCESSORS                              FEATURES                               │
│  ┌────────────────────────┐             ┌────────────────────────────────────┐ │
│  │ Stripe (platform default) │             │ • Split payments                   │ │
│  │   (2.9% + $0.30)       │             │ • BNPL (Affirm, Klarna, Afterpay) │ │
│  │ Own processor (0.5%)   │             │ • Payment links + QR codes         │ │
│  │   Stripe/PayPal/Square │             │ • Text2Pay                         │ │
│  └────────────────────────┘             │ • Subscriptions                    │ │
│                                          │ • Invoicing with OCR               │ │
│                                          │ • Terminal/POS                     │ │
│                                          │ • Multi-currency                   │ │
│                                          └────────────────────────────────────┘ │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

### Proposal & Estimate System (NEW Jan 2026)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    PROPOSAL & ESTIMATE SYSTEM                                    │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  DOCUMENT TYPES                         FEATURES                                │
│  ├── Proposals                          ├── AI-powered content generation       │
│  ├── Estimates                          ├── Digital signatures                  │
│  ├── Quotes                             ├── Template library                    │
│  └── Bids                               ├── Line item builder                   │
│                                          ├── Approval workflows                  │
│  WORKFLOW                               ├── Version history                     │
│  Create → Send → Track → Sign → Invoice └── Auto-convert to invoice            │
│                                                                                  │
│  AI Features:                                                                    │
│  • Smart pricing suggestions based on industry benchmarks                       │
│  • Auto-populate from CRM contact data                                          │
│  • Follow-up reminders and re-engagement                                        │
│                                                                                  │
│  Documentation: /09-Core-Innovations/proposal-estimate-system.md                │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

### Lead Targeting System (NEW Jan 2026)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    LEAD TARGETING SYSTEM (Emma Agent)                            │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  THE EMMA AGENT                                                                 │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │  Emma is the newest AI agent, specializing in:                           │  │
│  │  • Prospect identification and research                                   │  │
│  │  • Lead scoring and qualification                                         │  │
│  │  • Target account list building                                           │  │
│  │  • Outreach personalization                                               │  │
│  │  • Market segment analysis                                                │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  TARGETING CRITERIA                                                             │
│  ├── Industry vertical                  ├── Revenue range                       │
│  ├── Geographic location                ├── Employee count                      │
│  ├── Technology stack                   ├── Growth signals                      │
│  └── Buying intent indicators           └── Lookalike matching                  │
│                                                                                  │
│  INTEGRATION WITH EXISTING AGENTS                                               │
│  Emma → Marcus (growth strategy) → Sally (outreach) → Sarah (support)          │
│                                                                                  │
│  Documentation: /10-AI-Agents/AGENT-REGISTRY.md                                 │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Platform Quality System (Victor Agent)

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    PLATFORM QUALITY SYSTEM (Victor Agent)                        │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  THE VICTOR AGENT                                                                │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │  Victor is the Platform Quality Engineer, running continuously to:       │  │
│  │  • Validate all 287+ pages load correctly (HTTP 200, no JS errors)       │  │
│  │  • Check all API endpoints respond properly                              │  │
│  │  • Run critical user journeys (signup, dashboard, CRM, payments, AI)     │  │
│  │  • Diagnose failures and identify root causes                            │  │
│  │  • Alert ADA when issues are found                                       │  │
│  │  • Create tasks for Ace when code fixes are needed                       │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  PAGE TIER SYSTEM                                                                │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   TIER 1 (Critical) - Checked every 60 minutes                          │  │
│  │   └── Login, Register, Dashboard, Billing, AI Chat, CRM, Payments       │  │
│  │                                                                           │  │
│  │   TIER 2 (Core) - Checked every 6 hours                                  │  │
│  │   └── CRM details, Orders, Products, Appointments, AI Hub, CMS          │  │
│  │                                                                           │  │
│  │   TIER 3 (Advanced) - Checked every 24 hours                             │  │
│  │   └── Analytics, Reports, Integrations, Healthcare, POS                 │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  MCP TOOLS (15 Validation Tools)                                                 │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   Page Validation:                                                        │  │
│  │   • validation.page.check          - Check single page loads             │  │
│  │   • validation.page.batch_check    - Check multiple pages                │  │
│  │   • validation.page.content_check  - Verify page content                 │  │
│  │   • validation.page.tier1_check    - Validate all Tier 1 pages          │  │
│  │   • validation.report.generate     - Generate validation report          │  │
│  │                                                                           │  │
│  │   API Validation:                                                         │  │
│  │   • validation.api.health          - Check API health                    │  │
│  │   • validation.api.endpoint_check  - Test specific endpoint              │  │
│  │   • validation.api.latency_check   - Check response times                │  │
│  │   • validation.api.critical_endpoints - Check all critical APIs          │  │
│  │                                                                           │  │
│  │   Journey Validation:                                                     │  │
│  │   • validation.journey.run         - Run specific user journey           │  │
│  │   • validation.journey.all_critical - Run all critical journeys         │  │
│  │   • validation.diagnose.failure    - Diagnose why something failed       │  │
│  │   • validation.full_platform_check - Comprehensive platform validation   │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  CRITICAL USER JOURNEYS                                                          │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │                                                                           │  │
│  │   signup    - Register → Industries API → Login                          │  │
│  │   dashboard - Dashboard → Company API → Profile API                      │  │
│  │   crm       - Contacts → Contacts API → Pipeline → Deals API            │  │
│  │   payment   - Invoices → Invoices API → Payments → Payments API         │  │
│  │   ai_chat   - AI Chat → Conversations API → Agents API                  │  │
│  │                                                                           │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  INTEGRATION WITH EXISTING AGENTS                                                │
│  Victor → ADA (alerts) → Ace (fixes) → Victor (re-validation)                  │
│                                                                                  │
│  Files:                                                                          │
│  • mcp/tools/validation_pages.py     - Page validation tools                   │
│  • mcp/tools/validation_api.py       - API validation tools                    │
│  • mcp/tools/validation_journey.py   - Journey validation tools                │
│  • validation/page_registry.yaml     - 287+ pages organized by tier            │
│  • agents/registry.py                - Victor agent definition                  │
│                                                                                  │
│  Documentation: /03-AI-Systems/VICTOR-AGENT.md                                  │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

### AI/LLM Providers

```
┌───────────────────────────────────────────────────────────────────┐
│                    LLM Provider Factory                            │
│                                                                    │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐ │
│  │ OpenAI  │  │Anthropic│  │   xAI   │  │ Google  │  │  Meta   │ │
│  │ GPT-4o  │  │ Claude  │  │  Grok   │  │ Gemini  │  │ Llama   │ │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘  └─────────┘ │
│                                                                    │
│  SmartRouter selects optimal provider based on:                   │
│  - Task complexity                                                │
│  - Cost optimization                                              │
│  - Quality requirements                                           │
│  - Provider availability                                          │
│                                                                    │
│  Billing: 3x markup, per-company tracking, promo code exemptions  │
└───────────────────────────────────────────────────────────────────┘
```

### Video AI Providers

```
┌───────────────────────────────────────────────────────────────────┐
│                    VIDEO AI FACTORY                                │
│                                                                    │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐ │
│  │  Sora   │  │   Veo   │  │ Runway  │  │  Pika   │  │  Kling  │ │
│  │ (OpenAI)│  │(Google) │  │  ML     │  │  Labs   │  │   AI    │ │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘  └─────────┘ │
│                                                                    │
│  Model: Embed-first (links, not uploads)                          │
│  Freemium: 5 videos/month free, pro costs tokens                  │
│  Overlays: Text, logos, CTAs on any video                         │
└───────────────────────────────────────────────────────────────────┘
```

### Communication

```
┌─────────────────┐     ┌─────────────────┐
│  solid-backend  │────▶│     Twilio      │
│                 │     │  - SMS          │
│                 │     │  - Voice AI     │
│                 │     │  - WhatsApp     │
└─────────────────┘     └─────────────────┘
         │
         ▼
┌─────────────────┐     ┌─────────────────┐
│  Email Service  │────▶│  Resend/SES     │
│                 │     │  - Transactional│
│                 │     │  - Marketing    │
│                 │     │  - AI Creative  │
└─────────────────┘     └─────────────────┘
```

### Accounting Systems

```
┌───────────────────────────────────────────────────────────────────┐
│                  Accounting Sync Engine                            │
│                                                                    │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐   │
│  │   QuickBooks    │  │      Xero       │  │   FreshBooks    │   │
│  │   Online        │  │                 │  │                 │   │
│  │   80% market    │  │   15% market    │  │    5% market    │   │
│  └─────────────────┘  └─────────────────┘  └─────────────────┘   │
│                                                                    │
│  Features:                                                         │
│  - OAuth 2.0 with encrypted token storage (AES-256)               │
│  - Real-time sync (Customer, Invoice, Payment)                    │
│  - Batch sync (nightly reconciliation)                            │
│  - Webhook processing                                              │
│  - Conflict resolution (solid_wins, remote_wins, newer_wins)      │
└───────────────────────────────────────────────────────────────────┘
```

---

## Growth Intelligence Architecture

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                    GROWTH INTELLIGENCE ARCHITECTURE                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  SOLID# INTERNAL (Company ID 1, 3)          PER-MERCHANT (All other IDs)   │
│  ════════════════════════════════          ════════════════════════════    │
│                                                                              │
│  ┌─────────────────────────┐               ┌─────────────────────────┐     │
│  │       MARCUS            │               │   Client Growth Agent   │     │
│  │   Growth Commander      │               │   (Per Company)         │     │
│  │                         │               │                         │     │
│  │   Target: $100M         │               │   Target: "Your Number" │     │
│  │   Pareto 4-Tier         │               │   $500K → $5M → $100M   │     │
│  │   Kelly Criterion       │               │   Lifestyle/Growth/Scale│     │
│  └───────────┬─────────────┘               └───────────┬─────────────┘     │
│              │                                         │                    │
│              └─────────────────┬───────────────────────┘                    │
│                                │                                            │
│                    ┌───────────▼───────────┐                               │
│                    │  SHARED INTELLIGENCE  │                               │
│                    │                       │                               │
│                    │  • Industry Benchmarks│ (CAC, ROAS, LTV by industry) │
│                    │  • Pareto Math Engine │ (Fractal 80/20 calculations)  │
│                    │  • Four Levers        │ (Sell More, Ads, Prices, Vol) │
│                    │  • Tri-State Engine   │ (Hunt/Repair/Scale)          │
│                    │  • Stop-Loss Rules    │ (Automated kill switches)     │
│                    └───────────────────────┘                               │
│                                                                              │
│  Network Effect: More merchants = Better benchmarks = Smarter AI            │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## Dogfooding & Internal Testing

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                    DOGFOODING SYSTEM (Company ID 3)                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  PHILOSOPHY: "If we won't use it, why would our customers?"                 │
│                                                                              │
│  Company ID 3 = Solid# running as its own customer                          │
│  ├── Real leads, real customers, real revenue                               │
│  ├── Every feature tested here first                                        │
│  ├── Best content becomes customer templates                                │
│  └── A/B testing with statistical significance                              │
│                                                                              │
│  FEATURE ROLLOUT STAGES:                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  Stage 1: Internal (ID 3)  →  2-4 weeks                             │   │
│  │  Stage 2: Beta Customers   →  2-4 weeks                             │   │
│  │  Stage 3: Gradual (10%→50%→100%)  →  1-2 weeks each                 │   │
│  │  Stage 4: General Availability                                       │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│  COMPETITIVE ADVANTAGE:                                                     │
│  We have REAL metrics, not theory. Every feature has proven ROI.            │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## Deployment Architecture

### Production (DigitalOcean)

```
┌─────────────────────────────────────────────────────────┐
│                    DigitalOcean                         │
│                                                         │
│  ┌─────────────────────────────────────────────────┐   │
│  │              Docker Compose                      │   │
│  │                                                  │   │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐        │   │
│  │  │ backend  │ │ frontend │ │  public  │        │   │
│  │  │  :8090   │ │  :3000   │ │  :3001   │        │   │
│  │  └──────────┘ └──────────┘ └──────────┘        │   │
│  │                                                  │   │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐        │   │
│  │  │ postgres │ │  redis   │ │  celery  │        │   │
│  │  │  :5432   │ │  :6379   │ │ workers  │        │   │
│  │  └──────────┘ └──────────┘ └──────────┘        │   │
│  └─────────────────────────────────────────────────┘   │
│                                                         │
│  Host: api.solidnumber.com (<production-host>)            │
└─────────────────────────────────────────────────────────┘
```

### Local Development (Tilt)

```
┌─────────────────────────────────────────────────────────┐
│                    Tilt (K8s-like)                      │
│                                                         │
│  Hot-reload enabled for all services                   │
│  File sync to containers                               │
│  Unified log aggregation                               │
│                                                         │
│  tilt up → Starts all 9 services                       │
│  tilt down → Stops all services                        │
│  http://localhost:10350 → Tilt dashboard               │
└─────────────────────────────────────────────────────────┘
```

---

## Key Files

| Component | Main File | Purpose |
|-----------|-----------|---------|
| Backend Entry | `solid-backend/app.py` | FastAPI application |
| Celery Entry | `solid-backend/celery_app.py` | Background task config |
| Frontend Entry | `solid-frontend/src/app/layout.tsx` | Root layout |
| Public Entry | `solid-public/src/app/layout.tsx` | Marketing site layout |
| MCP Server | `solid-public/src/app/api/mcp/route.ts` | 655 MCP tools for external AI |
| Token Orch | `solid-token-orchestrator/main.py` | SmartRouter + LLM billing |
| AI Bridge | `solid-backend/services/ai_bridge.py` | Unified AI interface |
| Agent Registry | `solid-backend/agents/registry.py` | 32 AI agents (plus platform-internal orchestrators) (incl. Emma, Victor) |

---

## Documentation Index

### Core Innovations (79+ docs in `/09-Core-Innovations/`)

| Category | Key Documents |
|----------|---------------|
| **AI Systems** | ai-agents-ecosystem.md, ai-bridge-system.md, AI-COST-INTELLIGENCE.md |
| **AI Security** | AI-SECURITY-FRAMEWORK.md, AI-OBSERVABILITY.md, AI-DATA-GOVERNANCE.md |
| **AI Memory** | AGENTIC-MEMORY.md, ai-personality-memory.md, KNOWLEDGE-GRAPH.md |
| **AI Workflows** | AGENT-CHAINS.md, PROACTIVE-INTELLIGENCE.md |
| **Customer Learning** | CUSTOMER-LEARNING-ARCHITECTURE.md, MCP-Tools/*.md |
| **Creative** | AI-CREATIVE-COMMUNICATIONS.md, AI-VIDEO-STUDIO.md, POSITIVE-ANCHORING.md |
| **Documents** | DOCUMENT-FORMATTING-ENGINE.md, SALES-INTELLIGENCE-RESEARCH.md |
| **Growth** | pareto-growth-engine.md, client-growth-engine.md, advertising-engine.md |
| **Platform** | PLATFORM-MODES.md, AI-HUB-ARCHITECTURE.md, MCP-INTEGRATION.md |
| **CRM & Leads** | INTELLIGENT-CONTACT-MATCHING.md, lead-intelligence.md |
| **Sales Docs** | proposal-estimate-system.md |
| **Testing** | DOGFOODING-INTERNAL-TESTING.md |
| **Onboarding** | food-fight.md, kb-templates-system.md (58 industries) |
| **Commerce** | payment-suite.md, pos-system.md, shop-ecommerce.md, inventory-management.md |
| **Accounting** | accounting-integrations.md (QuickBooks, Xero, FreshBooks) |
| **Extensions** | app-engine.md, embeds-system.md, data-import-engine.md |
| **Referrals** | AFFILIATE-REFERRAL-SYSTEMS.md |
| **Marketing** | marketing-automation.md, cms-system.md |
| **Auth** | AUTHENTICATION-SYSTEM-OVERVIEW.md, NATIVE-2FA-ARCHITECTURE.md, OAUTH-2FA-ARCHITECTURE.md |
| **Workspace** | Google-Workspace-Integration/*.md, MICROSOFT-365-INTEGRATION.md |
| **2026 Strategy** | 18-Strategy-2026/*.md (30 documents) |

---

## 2026 Strategy: Social Intelligence Engine

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                    2026: AI DISCOVERABILITY + NATIVE COMMERCE                    │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  THE PITCH:                                                                     │
│  "Your customers buy on TikTok, Instagram, and YouTube without ever leaving    │
│   the app. We run your entire commerce operation across every platform—         │
│   inventory, payments, fulfillment—while building your authority so AI          │
│   recommends you first."                                                        │
│                                                                                  │
│  TWO-LAYER ARCHITECTURE                                                         │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │  LAYER 1: Solid# Platform Discovery                                      │  │
│  │  └── How WE get clients (internal marketing) - Company ID 1, 3           │  │
│  │                                                                           │  │
│  │  LAYER 2: Merchant AI Discoverability  ◄── THE PRODUCT                   │  │
│  │  └── Why merchants PAY US $1,500-$15K+/mo (top 10%) - Company ID 4+                    │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  SOCIAL INTELLIGENCE ENGINE FLOW                                                │
│  ┌──────────────────────────────────────────────────────────────────────────┐  │
│  │  Business Action → KIWI (transform) → PEPPER (distribute) →              │  │
│  │  SARAH (engage) → MARCUS (learn) → KB Update                             │  │
│  └──────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
│  THE 6 MOATS                                                                    │
│  ├── 1. Cross-Platform Attribution (TikTok → Google → Instagram → Purchase)   │
│  ├── 2. Data Stack (Payments + CRM + Inventory + Social)                       │
│  ├── 3. Knowledge Engine (6-layer KB, 58 templates)                           │
│  ├── 4. Customer Learning (AI memory across touchpoints)                       │
│  ├── 5. Agent Ecosystem (32 AI agents + 271 Celery task functions — see PLATFORM-METRICS.md)                            │
│  └── 6. MCP Integration (655 tools for external AI)                          │
│                                                                                  │
│  12-PHASE BUILD PLAN                                                            │
│  ├── Phase 1-4: Database, Adapters, KIWI, MCP Tools                            │
│  ├── Phase 5-8: Onboarding, Tier 2 Adapters, Dashboard                         │
│  └── Phase 9-12: Commerce, Approval Workflow, Attribution                      │
│                                                                                  │
│  Documentation: /18-Strategy-2026/ (30 documents)                               │
│  Build Plan: /18-Strategy-2026/29-12-PHASE-BUILD-PLAN.md                        │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## Next Steps

- [Tech Stack](./tech-stack.md) - Detailed technology choices
- [Data Flow](../69-Lead-Enrichment-Engine/DATA-FLOW.md) - How data moves through the system
- [Multi-Tenancy](./multi-tenancy.md) - Company isolation details
- [Complete Feature Inventory](../09-Core-Innovations/complete-feature-inventory.md) - Full feature list

---

**Last Updated:** January 11, 2026
**This is not a CRM. This is AI Business Infrastructure.**


--- FILE: 01-Architecture/TECH-STACK.md ---

---
topic: architecture
keywords: [architecture, authentication, backend, background, billing, branching, compliance, components, control]
last_verified: 2026-05-25
status: current
priority: critical
owner: platform-team
---

# Tech Stack

> Every technology used in Solid#, why it was chosen, and where it's used.
>
> **Why this design:** FastAPI + PostgreSQL + Next.js 15 was chosen because the platform is AI-first: FastAPI's async handles concurrent LLM API calls without blocking, PostgreSQL's JSONB + RLS supports flexible multi-tenant schemas, and Next.js App Router provides SSR for tenant sites while keeping the dashboard responsive. Celery with Redis was chosen over managed queues because the 273 background task functions need sub-second dispatch for real-time agent tool execution, not just batch jobs.
>
> **When this applies:** When adding dependencies, choosing libraries, or evaluating technology. Every addition must justify itself against this stack — no parallel ORMs, no alternative task queues, no second frontend framework.

---

## Backend (solid-backend)

### Core Framework

| Technology | Version | Purpose |
|------------|---------|---------|
| **Python** | 3.11+ | Primary language |
| **FastAPI** | Latest | Web framework (async, high-performance) |
| **Uvicorn** | Latest | ASGI server |
| **Pydantic** | v2 | Request/response validation |

**Why FastAPI?**
- Async/await for high concurrency
- Auto-generated OpenAPI docs
- Type hints = fewer bugs
- Fast (on par with Node.js/Go)

### Database

| Technology | Version | Purpose |
|------------|---------|---------|
| **PostgreSQL** | 15+ | Primary database |
| **SQLAlchemy** | 2.0 | ORM |
| **Alembic** | Latest | Schema migrations |
| **Redis** | 7+ | Cache, sessions, pub/sub, Celery broker |

**Why PostgreSQL?**
- JSONB for flexible schemas
- Full-text search built-in
- Row-level security for multi-tenancy
- Battle-tested, scales well

### Background Processing

| Technology | Version | Purpose |
|------------|---------|---------|
| **Celery** | 5.3+ | Task queue |
| **Redis** | - | Celery broker + result backend |
| **Flower** | Latest | Celery monitoring UI |

**Key Tasks:**
- KB onboarding (25 min orchestration)
- Email sending (bulk campaigns)
- Billing processing
- AI agent jobs
- Report generation

### AI/ML

| Technology | Purpose |
|------------|---------|
| **OpenAI API** | GPT-4, GPT-4o-mini for reasoning |
| **Anthropic API** | Claude for writing, analysis |
| **Google AI** | Gemini for vision tasks |
| **Meta Llama** | Cost-effective bulk processing |

**Token Orchestrator** routes requests to optimal provider.

### File Locations

```
solid-backend/
├── app.py                    # FastAPI entry point
├── celery_app.py             # Celery configuration
├── models/                   # 133 SQLAlchemy models
├── controllers/              # 165 API controllers
├── services/                 # 146 business services
├── agents/                   # 32 AI agents
├── mcp/                      # MCP server (655 tools)
├── middleware/               # 23 middleware components
├── tasks/                    # 10 Celery task modules
└── migrations/               # Alembic migrations
```

---

## Frontend (solid-frontend)

### Core Framework

| Technology | Version | Purpose |
|------------|---------|---------|
| **Next.js** | 15 | React framework (App Router) |
| **React** | 19 | UI library |
| **TypeScript** | 5.9 | Type safety |

**Why Next.js 15?**
- App Router (modern patterns)
- Server components (performance)
- Built-in API routes
- Image optimization
- Great DX

### State Management

| Technology | Version | Purpose |
|------------|---------|---------|
| **Zustand** | 5 | Client state (preferences, theme) |
| **React Query** | @tanstack | Server state (API caching) |
| **React Context** | Built-in | Auth, features, sandbox |

**State Architecture:**
```
Zustand Store
├── Theme mode (light/dark)
├── Theme preset
└── Layout preferences

React Query
├── Customers data
├── Orders data
├── Products data
└── All API responses

React Context
├── AuthContext (user, permissions)
├── FeatureVisibilityContext
└── SandboxContext
```

### UI Components

| Technology | Version | Purpose |
|------------|---------|---------|
| **Tailwind CSS** | 4 | Utility-first styling |
| **Shadcn UI** | Latest | Component library (Radix-based) |
| **Radix UI** | Latest | Headless accessible components |
| **Lucide React** | 0.453 | Icon library |

**47 UI components** in `/components/ui/`

### Forms & Validation

| Technology | Version | Purpose |
|------------|---------|---------|
| **React Hook Form** | 7 | Form state management |
| **Zod** | 3.25 | Schema validation |
| **@hookform/resolvers** | Latest | Zod integration |

### File Locations

```
solid-frontend/
├── src/
│   ├── app/                  # Next.js App Router
│   │   ├── (main)/           # Protected routes
│   │   ├── (auth)/           # Auth routes
│   │   └── api/              # 83 API routes
│   ├── components/           # 223 React components
│   │   └── ui/               # 47 base components
│   ├── lib/                  # Utilities
│   │   └── api/              # API client
│   ├── hooks/                # 40+ custom hooks
│   ├── stores/               # Zustand stores
│   └── contexts/             # React contexts
├── package.json
└── tailwind.config.js
```

---

## Public Site (solid-public)

### Core Framework

| Technology | Version | Purpose |
|------------|---------|---------|
| **Next.js** | 15.5 | Marketing site |
| **React** | 19.1 | UI |
| **TypeScript** | 5.9 | Type safety |
| **Tailwind CSS** | 4.1 | Styling |

### MCP Server

| Technology | Purpose |
|------------|---------|
| **Custom MCP Implementation** | 655 tools across 14 servers for AI agents |
| **JSON-RPC Support** | Standard MCP protocol |
| **OpenAPI Spec** | Documentation at /api/mcp/openapi.json |

### File Locations

```
solid-public/
├── src/
│   ├── app/
│   │   ├── api/mcp/          # MCP Server (5,000+ lines)
│   │   ├── demo/             # 25+ demo modules
│   │   ├── features/         # Feature pages
│   │   └── blog/             # Blog system
│   ├── components/
│   │   ├── cms/              # CMS components
│   │   └── ui/               # 50+ UI components
│   └── lib/
│       └── api/              # API clients
└── public/
    └── .well-known/          # ai-plugin.json, mcp.json
```

---

## Token Orchestrator

### Purpose
Centralized LLM billing and routing service.

| Technology | Purpose |
|------------|---------|
| **Python/FastAPI** | Service framework |
| **PostgreSQL** | Usage tracking |
| **Redis** | Rate limiting |

### Supported Providers

**Text LLMs:**
- OpenAI (GPT-4, GPT-4o-mini)
- Anthropic (Claude Opus, Sonnet, Haiku)
- Google (Gemini Pro)
- xAI (Grok)
- Meta (Llama)

**Image Generation:**
- DALL-E 3, DALL-E 2

**Video Generation:**
- Sora, Veo, Runway, Luma

### Billing Model
```
Wholesale Cost × 3 = Customer Cost
Tracked per company_id
Promo codes exempt from billing
```

---

## Infrastructure

### Development

| Technology | Purpose |
|------------|---------|
| **dev.sh** | Local orchestration script |
| **Docker Compose Watch** | Hot-reload & file sync |
| **Docker** | Containerization |
| **Docker Compose** | Multi-container dev |

### Production

| Technology | Purpose |
|------------|---------|
| **DigitalOcean** | Cloud hosting |
| **Docker** | Container runtime |
| **Caddy** | TLS termination + reverse proxy (HTTP/2 + HTTP/3, auto Let's Encrypt) |
| **Nginx** | Internal frontend balancer (security headers, rate limits) |
| **Cloudflare R2** | Object storage (S3-compatible) — DEPLOYED |
| **Cloudflare CDN / WAF / Turnstile** | ⚠️ PLANNED — not in front of production today. DNS currently on GoDaddy (`ns35/ns36.domaincontrol.com`) with A records direct to the droplet. Verified 2026-05-09. |

### CI/CD

| Technology | Purpose |
|------------|---------|
| **GitHub Actions** | CI/CD pipelines |
| **Husky** | Git hooks (pre-commit) |
| **ESLint** | Code linting |
| **Prettier** | Code formatting |

---

## Testing

### Backend

| Technology | Purpose |
|------------|---------|
| **Pytest** | Unit & integration tests |
| **pytest-asyncio** | Async test support |

### Frontend

| Technology | Purpose |
|------------|---------|
| **Jest** | Unit tests |
| **React Testing Library** | Component tests |
| **Playwright** | E2E tests |
| **Vitest** | Fast unit tests |

---

## Security

### Authentication

| Technology | Purpose |
|------------|---------|
| **JWT** | Token-based auth |
| **NextAuth.js** | Frontend auth (OAuth) |
| **bcrypt** | Password hashing |

### API Security

| Technology | Purpose |
|------------|---------|
| **CSRF Tokens** | Cross-site request protection |
| **Rate Limiting** | Abuse prevention |
| **CORS** | Cross-origin control |
| **HTTPS** | Transport encryption |

### Compliance

- **SOC 2 Type II** ready
- **PCI-DSS** compliant (payments)
- **GDPR** compliant (data handling)
- **HIPAA** ready (healthcare module)

---

## Package Counts

| Repository | Dependencies |
|------------|-------------|
| solid-backend | 80+ Python packages |
| solid-frontend | 60+ npm packages |
| solid-public | 58 npm packages |
| token-orchestrator | 20+ Python packages |

---

## Version Control

| Technology | Purpose |
|------------|---------|
| **Git** | Source control |
| **GitHub** | Repository hosting |
| **Git Submodules** | Backend/frontend/public sync |

### Branching Strategy

```
main (production)
  └── feature/* (development)
        └── PR → merge to main
```

---

## Next Steps

- [System Overview](./system-overview.md) - Architecture diagrams
- [Data Flow](../69-Lead-Enrichment-Engine/DATA-FLOW.md) - Request lifecycles
- [Multi-Tenancy](./multi-tenancy.md) - Isolation patterns

---

_Last updated: 2025-12-13_


--- FILE: 02-Backend/AI-DATA-IMPORTER-FLOW.md ---

---
topic: core-innovations
keywords: [core-innovations, ai_field_mapper, collected, columns, complete, component, continues, controllers, creation]
code_paths:
  - solid-backend/controllers/crm_contacts.py
  - solid-backend/services/ai_field_mapper.py
  - solid-backend/services/ai_field_mapper_enhanced.py
  - solid-backend/services/data_transform.py
  - solid-backend/services/import_executor.py
  - solid-backend/services/schema_evolution_service.py
  - solid-backend/services/universal_file_parser.py
  - solid-backend/api/routers/data_mappings.py
  - solid-frontend/src/hooks/use-crm-config.ts
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# AI Data Importer - Complete Flow

> **AI-First Approach**: Upload your data, we figure out the schema.
> No configuration needed - AI analyzes columns and creates the structure.

---

## High-Level Flow

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                        AI DATA IMPORT PIPELINE                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  1. UPLOAD                                                                   │
│  ────────                                                                    │
│  User uploads CSV/Excel file                                                 │
│  System parses file, extracts columns + sample data                          │
│                                                                              │
│  2. AI ANALYSIS (AIFieldMapper)                                              │
│  ─────────────────────────────                                               │
│  Claude API analyzes:                                                        │
│  • Column names ("OWNER 1 FIRST NAME", "Loan Amount", etc.)                 │
│  • Sample values ($350,000, john@email.com, etc.)                           │
│  • Business context (mortgage company, doctor's office, etc.)               │
│                                                                              │
│  Returns mappings:                                                           │
│  • "OWNER 1 FIRST NAME" → first_name (core field)                           │
│  • "Loan Amount" → custom_fields.loan_amount (new custom field)             │
│                                                                              │
│  3. SCHEMA EVOLUTION (SchemaEvolutionService)                               │
│  ────────────────────────────────────────────                               │
│  For each custom_fields.* mapping:                                          │
│  • Detect field type from sample data                                       │
│  • Create CompanyFieldSchema record                                         │
│  • NO DATABASE MIGRATION - just metadata                                    │
│                                                                              │
│  4. DATA IMPORT (ImportExecutor)                                            │
│  ────────────────────────────────                                           │
│  • Transform data per mappings                                              │
│  • Validate against schemas                                                  │
│  • Insert records with custom_fields JSONB                                  │
│                                                                              │
│  5. UI UPDATE                                                                │
│  ───────────                                                                 │
│  • useCRMConfig fetches updated field_schema                                │
│  • buildDynamicColumns renders new columns                                   │
│  • Imported data appears with custom columns!                               │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## Detailed Component Flow

### Step 1: File Upload & Parsing

⚠️ **`api/routers/data_import.py` does not exist.** The real upload
endpoints live in `api/routers/data_mappings.py` (mounted at
`/api/v1/data-mappings`, see the corrected API Endpoints table below) —
`POST /data-mappings/upload-file` and `POST /data-mappings/upload-async`,
not `/data-import/upload`. The pseudocode below is illustrative of the
parsing step, not a literal excerpt.

```python
# api/routers/data_mappings.py
@router.post("/upload-file")  # or /upload-async for large files
async def upload_file(file: UploadFile):
    # 1. Save file temporarily
    # 2. Parse with UniversalFileParser
    # 3. Extract columns and sample rows
    # 4. Return for AI analysis
```

**Output:**
```json
{
  "columns": ["OWNER 1 FIRST NAME", "Personal Email 1", "Loan Amount", "Property Address"],
  "sample_data": [
    {"OWNER 1 FIRST NAME": "John", "Personal Email 1": "john@test.com", "Loan Amount": "$350,000", "Property Address": "123 Main St"},
    {"OWNER 1 FIRST NAME": "Jane", "Personal Email 1": "jane@test.com", "Loan Amount": "$425,000", "Property Address": "456 Oak Ave"}
  ],
  "row_count": 1500
}
```

---

### Step 2: AI Field Mapping

```python
# services/ai_field_mapper.py

class AIFieldMapper:
    async def suggest_mappings(
        self,
        source_columns: List[str],
        sample_data: List[Dict],
        target_schema: Dict,
        business_context: str
    ) -> List[Dict]:
        """
        Uses Claude API to suggest field mappings.
        """
        prompt = f"""
        Analyze these CSV columns and suggest CRM mappings:

        Source columns: {source_columns}
        Sample data: {sample_data[:5]}
        Business context: {business_context}
        Target schema: {target_schema}

        For each column, provide:
        - target_field (CRM field or custom_fields.*)
        - confidence (0-1)
        - transformation (if needed)
        """

        response = await self.claude.messages.create(
            model="claude-sonnet-4-6",  # current default in services/ai_field_mapper.py, verified 2026-08-29
            messages=[{"role": "user", "content": prompt}]
        )

        return self._parse_mappings(response)
```

**AI Output:**
```json
{
  "mappings": [
    {
      "source_field": "OWNER 1 FIRST NAME",
      "target_field": "first_name",
      "confidence": 0.95,
      "transformation": null
    },
    {
      "source_field": "Personal Email 1",
      "target_field": "primary_email",
      "confidence": 0.92,
      "transformation": "lowercase"
    },
    {
      "source_field": "Loan Amount",
      "target_field": "custom_fields.loan_amount",
      "confidence": 0.88,
      "transformation": "parse_currency"
    },
    {
      "source_field": "Property Address",
      "target_field": "custom_fields.property_address",
      "confidence": 0.85,
      "transformation": null
    }
  ]
}
```

---

### Step 3: Schema Evolution

```python
# services/schema_evolution_service.py

class SchemaEvolutionService:
    def evolve_schema_from_mappings(
        self,
        company_id: int,
        entity_type: str,
        ai_mappings: List[Dict],
        sample_data: List[Dict],
        source: str = "ai_import"
    ) -> List[Dict]:
        """
        Create CompanyFieldSchema records for custom_fields.* mappings.
        """
        custom_fields_data = {}

        for mapping in ai_mappings:
            target = mapping.get("target_field", "")

            # Only process custom_fields.* mappings
            if target.startswith("custom_fields."):
                field_key = target.replace("custom_fields.", "")

                # Collect sample values
                source_field = mapping.get("source_field")
                sample_values = [row.get(source_field) for row in sample_data[:100]]

                custom_fields_data[field_key] = sample_values

        # Create schemas
        return self.evolve_schema_from_import(
            company_id=company_id,
            entity_type=entity_type,
            custom_fields_data=custom_fields_data,
            source=source
        )
```

**Field Type Detection Logic:**
```python
def detect_field_type(values: List[Any]) -> str:
    """
    Analyzes sample values to determine field type.
    """
    # Priority order:
    1. Boolean check: yes/no/true/false → "boolean"
    2. Email check: contains @ and . → "email"
    3. Phone check: 7+ digits, () - + → "phone"
    4. URL check: http:// or https:// → "url"
    5. Currency check: $, €, £ + numbers → "currency"
    6. Number check: all numeric → "number"
    7. Date check: date patterns → "date"
    8. Select check: ≤10 unique values → "select"
    9. Default → "text"
```

**Created Schema:**
```sql
INSERT INTO company_field_schemas (
  company_id, entity_type, field_key, field_label, field_type,
  source, ai_confidence, is_visible, is_filterable
) VALUES (
  1, 'contact', 'loan_amount', 'Loan Amount', 'currency',
  'ai_import', 0.85, true, true
);
```

---

### Step 4: Data Import

```python
# services/import_executor.py

class ImportExecutor:
    def execute_import(self, mapping_id: int, data: List[Dict]) -> Dict:
        """
        Execute the import with mappings.
        """
        # 1. Load mapping configuration
        mapping = self.db.query(DataSourceMapping).get(mapping_id)

        # 2. SCHEMA EVOLUTION - Create field schemas BEFORE importing
        if self.company_id and data:
            schema_service = SchemaEvolutionService(self.db)
            evolved_schemas = schema_service.evolve_schema_from_mappings(
                company_id=self.company_id,
                entity_type="contact",
                ai_mappings=mapping.field_mappings,
                sample_data=data,
                source="ai_import"
            )

        # 3. Transform and import each row
        for row in data:
            contact_data = self._transform_row(row, mapping.field_mappings)

            # Separate core fields from custom fields
            core_fields = {}
            custom_fields = {}

            for target, value in contact_data.items():
                if target.startswith("custom_fields."):
                    key = target.replace("custom_fields.", "")
                    custom_fields[key] = value
                else:
                    core_fields[target] = value

            # Create contact record
            contact = EmailContact(
                company_id=self.company_id,
                **core_fields,
                custom_fields=custom_fields  # JSONB column
            )
            self.db.add(contact)

        self.db.commit()
```

---

### Step 5: Validation on Save

```python
# controllers/crm_contacts.py

from services.schema_evolution_service import validate_custom_fields, FieldValidationError

@router.post("/contacts")
async def create_contact(contact_data: ContactCreate):
    # Validate custom_fields against CompanyFieldSchema
    try:
        validated_custom_fields = validate_custom_fields(
            db=db,
            company_id=company_id,
            entity_type="contact",
            custom_fields=contact_data.custom_fields
        )
    except FieldValidationError as e:
        raise HTTPException(
            status_code=422,
            detail={"message": "Validation failed", "errors": e.errors}
        )

    # Create contact with validated custom_fields
    contact = EmailContact(
        company_id=company_id,
        name=contact_data.name,
        email=contact_data.email,
        custom_fields=validated_custom_fields
    )
```

**Validation Rules:**
| Field Type | Validation | Coercion |
|------------|------------|----------|
| text | None | str() |
| number | Must be numeric | float() |
| currency | Must be numeric | Remove $,€ then float() |
| email | Must have @ and . | lowercase() |
| phone | Must have 7+ digits | Keep as string |
| url | Must start with http | Keep as string |
| boolean | Must be yes/no/true/false | bool() |
| date | Must be parseable | ISO format |
| select | Must be in options | str() |

---

## Error Handling

### Import Errors
```python
# Each row is validated, errors collected
errors = []
for i, row in enumerate(data):
    try:
        self._import_row(row)
    except ValidationError as e:
        errors.append({"row": i, "error": str(e)})

# Return partial success with error report
return {
    "imported": len(data) - len(errors),
    "failed": len(errors),
    "errors": errors[:100]  # First 100 errors
}
```

### Schema Evolution Errors
```python
# If schema creation fails, import continues without custom columns
try:
    evolved_schemas = schema_service.evolve_schema_from_mappings(...)
except Exception as e:
    logger.warning(f"Schema evolution failed: {e}")
    # Import continues - data goes to custom_fields but no column appears
```

---

## File Locations

```
Backend:
├── services/ai_field_mapper.py         # Claude API field mapping
├── services/ai_field_mapper_enhanced.py # Enhanced mapper with context
├── services/schema_evolution_service.py # Auto-create field schemas
├── services/import_executor.py          # Execute imports
├── services/data_transform.py           # Transformation engine
├── services/universal_file_parser.py    # Parse CSV/Excel/JSON
├── controllers/crm_contacts.py          # Validate on save
└── api/routers/data_mappings.py         # Import API endpoints (NOT data_import.py — that file does not exist)

Frontend:
├── src/app/(main)/dashboard/crm/data-import/ # Import wizard UI
└── src/hooks/use-crm-config.ts               # Fetch field_schema
```

---

## API Endpoints

⚠️ **Corrected 2026-08-29.** There is no `/data-import/*` router — it does
not exist in the codebase. The actual mount is `api/routers/data_mappings.py`
under prefix `/api/v1/data-mappings`. See `DATA-IMPORT-ENGINE.md` for the
full, verified endpoint list; the closest real equivalents to the flow
described in this doc are:

| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/data-mappings/upload-file` | POST | Upload file for parsing |
| `/data-mappings/upload-async` | POST | Upload large file, async processing |
| `/data-mappings/suggest` | POST | AI analyze columns / suggest mappings |
| `/data-mappings/staged-imports/{id}/execute` | POST | Execute import from staged data |
| `/data-mappings/jobs` | GET | List import jobs |
| `/data-mappings/jobs/{job_id}` | GET | Job status |

---

## Example: Full Import Flow

```
1. User uploads "homeowners.csv" (1500 rows)
   Columns: [Name, Email, Phone, Loan Amount, Property Address, LTV]

2. AI Analyzes (2-3 seconds)
   → Name → first_name (0.95)
   → Email → primary_email (0.92)
   → Phone → primary_phone (0.90)
   → Loan Amount → custom_fields.loan_amount (0.88)
   → Property Address → custom_fields.property_address (0.85)
   → LTV → custom_fields.ltv (0.82)

3. Schema Evolution
   Creates CompanyFieldSchema records:
   - loan_amount (currency)
   - property_address (text)
   - ltv (number)

4. Import Execution
   - Transforms: "Loan Amount" $350,000 → 350000.0
   - Validates: LTV "80" → 80.0 (number)
   - Inserts 1500 contacts with custom_fields JSONB

5. UI Updates
   - Contacts page loads
   - useCRMConfig returns new field_schema
   - Table shows: Name | Email | Phone | Loan Amount | Property Address | LTV
```

---

*Last Updated: January 2026*
*Sprint: CRM Contacts Evolution*


--- FILE: 02-Backend/API-ENDPOINTS.md ---

---
topic: backend
keywords: [backend, admin, agent, also, analytics, apis, appointments, apps, audit]
code_paths:
  - solid-backend/controllers/orders.py
  - solid-backend/controllers/schedule.py
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# API Endpoints

> Complete reference of all API endpoints in solid-backend.

> **Last Verified:** March 6, 2026
> **Total Routers:** 40+ dedicated routers + 60+ controller imports
> **Total Endpoints:** 500+ REST API endpoints

---

## Quick Reference

| Category | Router Count | Description |
|----------|--------------|-------------|
| **Core** | 10 | Auth, Users, Companies, Settings |
| **AI/Agent Systems** | 9 | Vibe, Chains, Chat Dashboard, Audit |
| **Platform Integration** | 7 | Workspace AI, Chat, Social, MCP |
| **Analytics & Monitoring** | 5 | Telemetry, CMS Analytics, KB Analytics |
| **Content & Data** | 8 | Apps, Files, Storage, Data Mappings |
| **Security & Compliance** | 4 | 2FA, Security Scanning, Maintenance |

**Base URL:** `https://api.solidnumber.com/api/v1`

---

## HEALTH CHECK ENDPOINTS

> System health verification for monitoring, Postman, AI, and Vibe Coder.
> See [Health Check Endpoints](../06-Operations/HEALTH-CHECK-ENDPOINTS.md) for full documentation.

| Endpoint | Method | Description | Auth |
|----------|--------|-------------|------|
| `/_health/self` | GET | Liveness check (no DB) | None |
| `/_health` | GET | Internal health check | None |
| `/_health/db` | GET | Database connectivity | None |
| `/_health/record` | POST | Write test (creates row) | None |
| `/health` | GET | Comprehensive 9-port check | None |
| `/healthcheck/` | GET | Full 6-layer system health | None |
| `/healthcheck/quick` | GET | Quick database check | None |
| `/healthcheck/mcp` | GET | MCP/Agent status | Optional |

**Safe for Vibe Coder:** All GET endpoints are read-only and safe.

---

## NEW SYSTEMS (2026)

### Seat Management API

> User seat tracking and limits

**Prefix:** `/api/v1/seats`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/seats` | Get seat usage for company |
| POST | `/seats/add` | Add seats to subscription |
| GET | `/seats/staff` | List staff with seats |

---

### Vibe Coding API

> Safe, reversible AI configuration changes

**Prefix:** `/api/v1/vibe`

| Method | Path | Description |
|--------|------|-------------|
| POST | `/vibe/analyze` | Analyze vibe prompt (preview changes) |
| GET | `/vibe/preview/{preview_id}` | Get preview details |
| POST | `/vibe/apply` | Apply changes (with audit trail) |
| GET | `/vibe/history` | Get action history |
| POST | `/vibe/history/rollback/{action_id}` | Rollback specific action |
| POST | `/vibe/rollback-to` | Rollback to point in time |
| POST | `/vibe/rollback-last` | Rollback last N actions |
| GET | `/vibe/approvals/pending` | Get pending approvals |
| POST | `/vibe/approvals/{id}/approve` | Approve change |
| POST | `/vibe/approvals/{id}/reject` | Reject change |
| GET | `/vibe/permissions/{user_id}` | Get user vibe permissions |
| PUT | `/vibe/permissions/{user_id}` | Update vibe permissions |
| GET | `/vibe/company/settings` | Get company vibe settings |
| PUT | `/vibe/company/settings` | Update company vibe settings |
| POST | `/vibe/audit` | Query audit log |
| GET | `/vibe/examples/{industry}` | Get industry examples |
| GET | `/vibe/examples/quick` | Get quick examples |

### MCP Vibe Coding API

> MCP-authenticated vibe endpoints for external AI clients (Cursor, Claude Desktop, etc.)

**Prefix:** `/api/v1/mcp/vibe`
**Auth:** `X-API-Key` header or JWT Bearer token (via `get_mcp_user_or_agent`)

| Method | Path | Description |
|--------|------|-------------|
| GET | `/mcp/vibe/capabilities?company_id=X` | List what vibe can do for a company |
| POST | `/mcp/vibe/analyze` | Parse prompt → intent + preview_id |
| GET | `/mcp/vibe/preview/{preview_id}?company_id=X` | Get before/after diff |
| POST | `/mcp/vibe/apply` | Apply a previewed change (requires confirm=true) |
| POST | `/mcp/vibe/rollback/{history_id}` | Rollback a specific action |
| GET | `/mcp/vibe/history?company_id=X` | Get action history |

**Note:** `company_id` is required in request body (POST) or query param (GET) for all operations. These endpoints delegate to the same VibeEngine used by the dashboard — same safety rules, same audit trail, same rollback.

---

### Chat Dashboard API

> AI conversation visibility and management

**Prefix:** `/api/v1/chat-dashboard`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/chat-dashboard/conversations` | List conversations with Sage |
| GET | `/chat-dashboard/conversations/{id}` | Get conversation detail |
| PATCH | `/chat-dashboard/conversations/{id}/close` | Close conversation |
| PATCH | `/chat-dashboard/conversations/{id}/reopen` | Reopen conversation |
| GET | `/chat-dashboard/actions` | List AI actions taken |
| GET | `/chat-dashboard/actions/{id}` | Get action details |
| PATCH | `/chat-dashboard/actions/{id}` | Update action status |
| GET | `/chat-dashboard/stats` | Dashboard statistics |
| GET | `/chat-dashboard/faq-gaps` | Identify FAQ gaps |
| PATCH | `/chat-dashboard/faq-gaps/{id}/review` | Review FAQ gap |

---

### AI Audit Trail API

> Action reversal and compliance tracking

**Prefix:** `/api/v1/ai-audit`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/ai-audit/logs` | List AI action audit logs |
| GET | `/ai-audit/logs/{id}` | Get specific audit log |
| POST | `/ai-audit/logs/{id}/reverse` | Reverse/undo an AI action |
| GET | `/ai-audit/approvals/pending` | Pending approval requests |
| POST | `/ai-audit/approvals/{id}/decide` | Approve/reject action |
| GET | `/ai-audit/stats` | Audit statistics |
| GET | `/ai-audit/agents/{type}/performance` | Agent performance audit |
| GET | `/ai-audit/export` | Export audit trail |

---

### Agent Chains API

> Multi-step AI workflows

**Prefix:** `/api/v1/chains`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/chains` | List chains |
| POST | `/chains` | Create chain |
| GET | `/chains/{id}` | Get chain details |
| PUT | `/chains/{id}` | Update chain |
| DELETE | `/chains/{id}` | Delete chain |
| POST | `/chains/{id}/activate` | Activate chain |
| POST | `/chains/{id}/pause` | Pause chain |
| POST | `/chains/{id}/archive` | Archive chain |
| POST | `/chains/{id}/execute` | Execute chain |
| GET | `/chains/{id}/executions` | Execution history |
| GET | `/chains/executions/{id}` | Get execution details |
| POST | `/chains/executions/{id}/approve` | Approve execution |
| POST | `/chains/executions/{id}/cancel` | Cancel execution |
| GET | `/chains/templates` | List chain templates |
| GET | `/chains/templates/{id}` | Get template |
| POST | `/chains/from-template` | Create chain from template |
| GET | `/chains/pending-approvals` | Pending chain approvals |

---

### Apps Engine API

> Custom apps via MCP

**Prefix:** `/api/v1/apps`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/apps` | List custom apps |
| GET | `/apps/{slug}` | Get app details |
| POST | `/apps` | Create custom app |
| PATCH | `/apps/{slug}` | Update app |
| DELETE | `/apps/{slug}` | Delete app |
| POST | `/apps/{slug}/execute` | Execute app (via MCP) |
| GET | `/apps/{slug}/executions` | Execution history |
| POST | `/apps/requests` | Create app request |
| GET | `/apps/requests` | List app requests |
| PATCH | `/apps/requests/{id}` | Update request |
| GET | `/apps/mcp/tools` | List available MCP tools |
| POST | `/apps/mcp/execute` | Execute MCP tool |

---

### Knowledge Graph API

> Relationship intelligence

**Prefix:** `/api/v1/graph`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/graph/search` | Search knowledge graph |
| GET | `/graph/context/{type}/{id}` | Get entity context |
| GET | `/graph/path` | Get relationship path |
| POST | `/graph/question` | Ask graph question |
| GET | `/graph/nodes` | List nodes |
| POST | `/graph/nodes` | Create node |
| GET | `/graph/nodes/{id}` | Get node |
| PUT | `/graph/nodes/{id}` | Update node |
| DELETE | `/graph/nodes/{id}` | Delete node |
| GET | `/graph/edges` | List relationships |
| POST | `/graph/edges` | Create relationship |
| DELETE | `/graph/edges/{id}` | Delete relationship |
| GET | `/graph/stats` | Graph statistics |
| POST | `/graph/sync` | Sync graph |
| GET | `/graph/relationship-summary/{type}/{id}` | Relationship summary |

---

### Proactive Insights API

> AI briefs and insights

**Prefix:** `/api/v1/proactive`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/proactive/insights` | Get proactive insights |
| GET | `/proactive/insights/{id}` | Get insight detail |
| POST | `/proactive/insights/{id}/dismiss` | Dismiss insight |
| POST | `/proactive/insights/{id}/action` | Take insight action |
| GET | `/proactive/brief` | Get AI brief |
| POST | `/proactive/brief/generate` | Generate brief |
| GET | `/proactive/brief/history` | Brief history |
| GET | `/proactive/preferences` | Get preferences |
| PUT | `/proactive/preferences` | Update preferences |
| POST | `/proactive/analyze` | Analyze proactively |
| GET | `/proactive/stats` | Statistics |
| GET | `/proactive/insight-types` | Available insight types |

---

### Workspace AI API

> Google & Microsoft AI tools (Gemini, Imagen, Veo, Copilot)

**Prefix:** `/api/v1/workspace`

| Method | Path | Description |
|--------|------|-------------|
| **Google AI** | | |
| POST | `/workspace/gemini/generate` | Generate with Gemini |
| POST | `/workspace/gemini/chat` | Gemini chat |
| POST | `/workspace/gemini/code` | Gemini code generation |
| POST | `/workspace/imagen/generate` | Generate image with Imagen |
| POST | `/workspace/imagen/edit` | Edit image |
| POST | `/workspace/veo/generate` | Generate video with Veo |
| POST | `/workspace/meet/list-recordings` | List Meet recordings |
| POST | `/workspace/meet/transcribe` | Transcribe meeting |
| **Microsoft AI** | | |
| POST | `/workspace/teams/meetings/list` | List Teams meetings |
| POST | `/workspace/teams/meetings/transcribe` | Transcribe meeting |
| POST | `/workspace/sharepoint/list-files` | List SharePoint files |
| POST | `/workspace/copilot/chat` | Chat with Copilot |
| POST | `/workspace/power-automate/list-flows` | List flows |
| POST | `/workspace/power-automate/run-flow` | Run flow |
| POST | `/workspace/planner/list-tasks` | List Planner tasks |
| POST | `/workspace/planner/create-task` | Create task |

---

### Communications / Email Config API

> Email provider configuration and Google Workspace connection status

**Prefix:** `/api/v1/communications`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/communications/email/config` | Email provider config (google_connected, email, provider) |
| PUT | `/communications/email/config` | Update email provider settings |

---

### Platform Features API

> Video generation, smart forms, dashboards

**Prefix:** `/api/v1/platform`

| Method | Path | Description |
|--------|------|-------------|
| **Video Generation** | | |
| GET | `/platform/video/providers` | List video providers |
| GET | `/platform/video/can-use-veo` | Check Veo access |
| POST | `/platform/video/estimate` | Cost estimate |
| POST | `/platform/video/generate` | Generate video |
| POST | `/platform/video/generate-veo` | Generate with Veo |
| **Apps Script Dashboards** | | |
| GET | `/platform/dashboards/templates` | Dashboard templates |
| POST | `/platform/dashboards` | Create dashboard |
| GET | `/platform/dashboards` | List dashboards |
| DELETE | `/platform/dashboards/{id}` | Delete dashboard |
| POST | `/platform/dashboards/execute` | Execute script |
| **Smart Forms** | | |
| GET | `/platform/forms/templates` | Form templates |
| POST | `/platform/forms` | Create form |
| POST | `/platform/forms/from-template` | From template |
| GET | `/platform/forms` | List forms |
| GET | `/platform/forms/{id}` | Get form |
| GET | `/platform/forms/{id}/autofill` | Get autofill suggestions |
| POST | `/platform/forms/{id}/submit` | Submit form |
| GET | `/platform/forms/{id}/submissions` | Get submissions |
| **Health** | | |
| GET | `/platform/health` | Health summary |
| GET | `/platform/health/reauth-prompt` | Check reauth needed |
| GET | `/platform/health/{platform}` | Platform-specific health |

---

### Chat Integrations API

> Google Chat & Microsoft Teams

**Prefix:** `/api/v1/chat`

| Method | Path | Description |
|--------|------|-------------|
| **Google Chat** | | |
| POST | `/chat/google/message` | Send Google Chat message |
| POST | `/chat/google/card` | Send rich card |
| POST | `/chat/google/notification` | Send notification |
| POST | `/chat/google/alert` | Send alert card |
| POST | `/chat/google/approval` | Send approval card |
| GET | `/chat/google/spaces` | List Google Chat spaces |
| POST | `/chat/google/spaces` | Create space |
| **Microsoft Teams** | | |
| POST | `/chat/teams/message` | Send Teams message |
| POST | `/chat/teams/notification` | Send Teams notification |
| GET | `/chat/teams/channels` | List Teams channels |
| **Space Linking** | | |
| POST | `/chat/link-space` | Link chat space to entity |
| GET | `/chat/linked-spaces` | List linked spaces |
| DELETE | `/chat/linked-spaces/{id}` | Remove space link |

---

### Two-Factor Auth API

> TOTP, WebAuthn, backup codes

**Prefix:** `/api/v1/auth/2fa`

| Method | Path | Description |
|--------|------|-------------|
| **TOTP** | | |
| GET | `/auth/2fa/status` | 2FA status |
| POST | `/auth/2fa/totp/setup` | Setup TOTP |
| POST | `/auth/2fa/totp/verify-setup` | Verify TOTP setup |
| POST | `/auth/2fa/totp/verify` | Verify TOTP code |
| DELETE | `/auth/2fa/totp` | Disable TOTP |
| **Backup Codes** | | |
| POST | `/auth/2fa/backup-codes/verify` | Verify backup code |
| POST | `/auth/2fa/backup-codes/regenerate` | Regenerate codes |
| GET | `/auth/2fa/backup-codes/remaining` | Remaining codes |
| **WebAuthn** | | |
| POST | `/auth/2fa/webauthn/register/begin` | Start WebAuthn registration |
| POST | `/auth/2fa/webauthn/register/complete` | Complete registration |
| POST | `/auth/2fa/webauthn/authenticate/begin` | Start authentication |
| POST | `/auth/2fa/webauthn/authenticate/complete` | Complete authentication |
| GET | `/auth/2fa/webauthn/credentials` | List credentials |
| DELETE | `/auth/2fa/webauthn/credentials/{id}` | Delete credential |
| **Admin** | | |
| PUT | `/auth/2fa/admin/user/{id}/require-2fa` | Require 2FA |
| GET | `/auth/2fa/admin/company/security-policy` | Security policy |
| PUT | `/auth/2fa/admin/company/security-policy` | Update policy |
| GET | `/auth/2fa/admin/users/2fa-status` | Users 2FA status |

---

### Security Scanning API

> Input/output scanning, threat detection

**Prefix:** `/api/v1/security`

| Method | Path | Description |
|--------|------|-------------|
| POST | `/security/scan/input` | Scan user input for injection |
| POST | `/security/scan/output` | Scan AI output |
| POST | `/security/scan/kb` | Scan KB content |
| GET | `/security/canary-token` | Get canary token |
| GET | `/security/stats` | Security statistics |
| GET | `/security/threats` | Threat logs |
| POST | `/security/agent/validate-input` | Validate agent input |

---

### AI Content Generation API

> Email, SMS, content generation with AI

**Prefix:** `/api/v1/ai-content`

| Method | Path | Description |
|--------|------|-------------|
| POST | `/ai-content/email/generate` | Generate email with AI |
| POST | `/ai-content/email/generate-variations` | Multiple email variations |
| POST | `/ai-content/sms/generate` | Generate SMS with AI |
| POST | `/ai-content/sms/generate-series` | SMS sequence generation |
| POST | `/ai-content/improve` | Improve/rewrite content |
| POST | `/ai-content/translate` | Translate content |
| POST | `/ai-content/adjust-tone` | Change tone/style |
| GET | `/ai-content/templates/suggestions` | Content template suggestions |
| GET | `/ai-content/stats` | Content generation statistics |

---

### Data Mappings API

> CSV import with AI-powered field mapping

**Prefix:** `/api/v1/data-mappings`

| Method | Path | Description |
|--------|------|-------------|
| POST | `/data-mappings` | Create data mapping |
| GET | `/data-mappings` | List mappings |
| GET | `/data-mappings/{id}` | Get mapping details |
| PATCH | `/data-mappings/{id}` | Update mapping |
| DELETE | `/data-mappings/{id}` | Delete mapping |
| POST | `/data-mappings/suggest` | AI suggest mappings |
| POST | `/data-mappings/suggest-with-mcp` | Suggest via MCP |
| POST | `/data-mappings/upload-async` | Upload file async |
| GET | `/data-mappings/staged-imports` | List staged imports |
| GET | `/data-mappings/staged-imports/{id}` | Get staged import |
| POST | `/data-mappings/staged-imports/{id}/execute` | Execute import |
| POST | `/data-mappings/upload-file` | Upload file |
| POST | `/data-mappings/{id}/import` | Run import job |
| GET | `/data-mappings/jobs/{id}` | Get job details |
| POST | `/data-mappings/jobs/{id}/rollback` | Rollback import |
| GET | `/data-mappings/templates` | List saved templates |
| POST | `/data-mappings/{id}/save-as-template` | Save mapping as template |

---

### File Browser API

> Cloud file management (Google Drive, OneDrive)

**Prefix:** `/api/v1/files`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/files/provider` | Get storage provider info |
| GET | `/files/list` | List folder contents |
| GET | `/files/info/{id}` | Get file info |
| GET | `/files/download/{id}` | Download file |
| POST | `/files/upload` | Upload file |
| POST | `/files/folder` | Create folder |
| DELETE | `/files/{id}` | Delete file |
| POST | `/files/search` | Search files |
| POST | `/files/share` | Share file |
| GET | `/files/recent` | Get recent files |
| GET | `/files/picker` | File picker view |
| POST | `/files/picker/select` | Select file in picker |

---

### Social Media API

> Multi-platform social posting and analytics

**Prefix:** `/api/v1/social`

| Method | Path | Description |
|--------|------|-------------|
| POST | `/social/oauth-apps` | Create OAuth app |
| GET | `/social/oauth-apps` | List OAuth apps |
| DELETE | `/social/oauth-apps/{id}` | Delete OAuth app |
| GET | `/social/oauth/authorize/{platform}` | Authorize platform |
| GET | `/social/oauth/callback/{platform}` | OAuth callback |
| POST | `/social/oauth/select-pages` | Select pages for posting |
| GET | `/social/accounts` | List social accounts |
| DELETE | `/social/accounts/{id}` | Remove account |
| POST | `/social/posts` | Create post |
| GET | `/social/posts` | List posts |
| POST | `/social/posts/{id}/publish` | Publish post |
| GET | `/social/metrics` | Social metrics |
| POST | `/social/content-library` | Add to content library |
| GET | `/social/content-library` | List library items |
| POST | `/social/ai/suggest-content` | AI content suggestions |
| GET | `/social/ai/optimal-posting-times` | Optimal posting times |
| GET | `/social/ai/content-performance-insights` | Performance insights |

---

### Agent ROI Dashboard API

> ROI metrics for AI agents

**Prefix:** `/api/v1/agent-roi`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/agent-roi/roi` | Get agent ROI metrics |
| GET | `/agent-roi/roi/{agent_type}` | ROI for specific agent |
| GET | `/agent-roi/digest/weekly` | Weekly "What I Learned" digest |
| GET | `/agent-roi/all-agents` | All agents ROI summary |

---

### Cost Forecaster API

> AI cost predictions and budget tracking

**Prefix:** `/api/v1/cost-forecast`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/cost-forecast/month-end` | Month-end cost forecast |
| GET | `/cost-forecast/hotspots` | Cost hotspots |
| GET | `/cost-forecast/agent-breakdown` | Cost by agent |
| GET | `/cost-forecast/budget-status` | Budget status check |

---

### Gamification API

> Points, badges, leaderboards

**Prefix:** `/api/v1/gamification`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/gamification/stats` | User gamification stats |
| GET | `/gamification/badges` | Badge definitions |
| GET | `/gamification/leaderboard` | Leaderboard |
| GET | `/gamification/levels` | Level definitions |
| POST | `/gamification/activity` | Log activity |
| GET | `/gamification/streaks` | User streaks |
| GET | `/gamification/points/history` | Points history |

---

### Marcus Integration API

> Marcus growth agent API

**Prefix:** `/api/v1/marcus`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/marcus/leads/hot` | Hot leads from Marcus |
| GET | `/marcus/leads/pipeline` | Pipeline summary |
| GET | `/marcus/leads/{contact_id}/insights` | Lead insights |
| POST | `/marcus/leads/score` | Score leads |
| POST | `/marcus/leads/question` | Ask Marcus about lead |
| GET | `/marcus/chat/enrich` | Enrich chat context |
| POST | `/marcus/chat/action-enrichment` | Enrich action |
| GET | `/marcus/segments` | Saved segments |
| POST | `/marcus/segments/create` | Create segment |
| POST | `/marcus/lookalikes` | Find lookalike leads |

---

### Telemetry API

> Agent telemetry and monitoring

**Prefix:** `/api/v1/telemetry`

| Method | Path | Description |
|--------|------|-------------|
| POST | `/telemetry/log` | Log telemetry |
| GET | `/telemetry/agents/{type}/stats` | Agent stats |
| GET | `/telemetry/agents/summary` | Agent summary |
| GET | `/telemetry/drift` | Drift report |
| GET | `/telemetry/errors` | Error logs |
| POST | `/telemetry/agent/heartbeat` | Agent heartbeat |
| GET | `/telemetry/agent/{type}/should-run` | Should agent run |

---

### CMS Analytics API

> Website traffic analytics

**Prefix:** `/api/v1/cms-analytics`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/cms-analytics/overview` | Traffic overview |
| GET | `/cms-analytics/geo/countries` | Traffic by country |
| GET | `/cms-analytics/geo/cities` | Traffic by city |
| GET | `/cms-analytics/devices` | Device breakdown |
| GET | `/cms-analytics/browsers` | Browser breakdown |
| GET | `/cms-analytics/pages/top` | Top pages |
| GET | `/cms-analytics/pages/entry` | Entry pages |
| GET | `/cms-analytics/sources/referrers` | Referrer sources |
| GET | `/cms-analytics/sources/campaigns` | Campaign sources |
| GET | `/cms-analytics/timeseries` | Traffic time series |
| GET | `/cms-analytics/realtime` | Real-time stats |
| GET | `/cms-analytics/export/summary` | Export analytics |

---

### KB Analytics API

> Knowledge base usage stats

**Prefix:** `/api/v1/kb-analytics`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/kb-analytics/layer-usage` | KB layer usage stats |
| GET | `/kb-analytics/overrides` | Content overrides |
| GET | `/kb-analytics/top-queries/{layer}` | Top queries by layer |
| GET | `/kb-analytics/by-agent` | KB usage by agent |
| GET | `/kb-analytics/improvement-opportunities` | Improvement suggestions |

---

### KB Search API

> Semantic and keyword search across knowledge base layers

**Prefix:** `/api/v1/kb`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/kb/company` | List company KB entries (filter by category, limit) |
| POST | `/kb/search` | Semantic + keyword search across all KB layers |
| POST | `/kb/search/company` | Search company KB only |
| POST | `/kb/search/industry` | Search industry KB only |
| POST | `/kb/search/platform` | Search platform KB only |
| POST | `/kb/{entry_id}/embed` | Re-embed a specific KB entry |
| POST | `/kb/embed/batch` | Batch embed KB entries |

---

### Agent Context API

> Agent context memory and KB scoping

**Prefix:** `/api/v1/agents`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/agents/{id}/context` | Get agent context entries (filter by context_type) |
| POST | `/agents/{id}/context` | Set agent context (kb_scope, memory, etc.) |

---

### Tier Management API

> Subscription tier management

**Prefix:** `/api/v1/tier`

| Method | Path | Description |
|--------|------|-------------|
| POST | `/tier/upgrade-demo` | Upgrade demo company |
| POST | `/tier/downgrade-demo` | Downgrade demo company |
| POST | `/tier/upgrade` | Upgrade subscription |
| POST | `/tier/downgrade` | Downgrade subscription |
| GET | `/tier/available-upgrades` | Available upgrades |
| POST | `/tier/compare` | Compare tiers |
| GET | `/tier/current` | Current tier |

---

### Maintenance Mode API

> System maintenance controls

**Prefix:** `/api/v1/maintenance`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/maintenance/status` | Get maintenance status |
| POST | `/maintenance/enable` | Enable maintenance mode |
| POST | `/maintenance/disable` | Disable maintenance mode |
| GET | `/maintenance/health/database` | Database health check |
| GET | `/maintenance/failover/status` | Failover status |

---

## CORE APIs (Stable)

### Authentication

**Dual auth system:** Redis sessions (`solid_session` cookie, 7d) + JWT (`solid_access_token`, 1h) + refresh token (`solid_refresh_token`, 7d). Most endpoints use `get_current_user_from_session` which checks session cookie first, JWT fallback. See `14-Security/SESSION-MANAGEMENT.md`.

| Method | Path | Description |
|--------|------|-------------|
| POST | `/auth/login` | User login — returns access_token (1h) + refresh_token (7d) + sets session cookie |
| POST | `/auth/register` | User registration |
| POST | `/auth/logout` | Logout (invalidate token + clear session) |
| POST | `/auth/forgot-password` | Request password reset |
| POST | `/auth/reset-password` | Reset password with token |
| POST | `/auth/refresh` | Refresh JWT — accepts `refresh_token` in body, returns new access + refresh tokens |
| GET | `/auth/me` | Get current user |
| POST | `/auth/verify-email` | Verify email address |
| POST | `/auth/oauth_register` | OAuth user registration |

### OAuth

| Method | Path | Description |
|--------|------|-------------|
| POST | `/auth/google/connect` | Connect Google |
| GET | `/auth/google/callback` | Google OAuth callback |
| POST | `/auth/google/disconnect` | Disconnect Google |
| POST | `/auth/microsoft/connect` | Connect Microsoft |
| GET | `/auth/microsoft/callback` | Microsoft OAuth callback |
| POST | `/auth/microsoft/disconnect` | Disconnect Microsoft |
| POST | `/auth/{provider}/reauth` | Reauthenticate |
| GET | `/auth/{provider}/status` | OAuth status |

---

### Users & Roles

| Method | Path | Description |
|--------|------|-------------|
| GET | `/users` | List users |
| POST | `/users` | Create user |
| GET | `/users/{id}` | Get user |
| PATCH | `/users/{id}` | Update user |
| DELETE | `/users/{id}` | Delete user |
| POST | `/users/{id}/invite` | Send invite |
| GET | `/roles` | List roles |
| POST | `/roles` | Create role |
| GET | `/roles/{id}` | Get role |
| PATCH | `/roles/{id}` | Update role |

---

### Companies

| Method | Path | Description |
|--------|------|-------------|
| GET | `/companies/{id}/features` | Get feature config |
| GET | `/companies/{id}/crm-config` | Get CRM config |
| POST | `/companies/{id}/features/check` | Check feature access |
| GET | `/companies/{id}/info` | Get company info |
| POST | `/companies/{id}/logo` | Upload logo |
| GET | `/companies/{id}/logo` | Get logo |
| GET | `/companies/{id}/feature-settings` | Get feature settings |
| PUT | `/companies/{id}/feature-settings` | Update feature settings |
| GET | `/companies/{id}/field-schemas` | List custom field schemas |
| POST | `/companies/{id}/field-schemas` | Create custom field schema |
| PUT | `/companies/{id}/field-schemas/{schema_id}` | Update field schema |
| DELETE | `/companies/{id}/field-schemas/{schema_id}` | Delete field schema |

#### Field Schema Request Body

```json
POST /companies/{id}/field-schemas
{
  "field_key": "loan_amount",
  "field_label": "Loan Amount",
  "field_type": "currency",   // text, textarea, number, currency, date, email, phone, url, boolean, select
  "entity_type": "contact",   // contact, customer, deal
  "is_required": false,
  "is_visible": true,
  "is_filterable": true,
  "options": [                // Only for type="select"
    {"value": "option1", "label": "Option 1"},
    {"value": "option2", "label": "Option 2"}
  ]
}
```

---

### Customers

| Method | Path | Description |
|--------|------|-------------|
| GET | `/customers` | List customers with filtering |
| GET | `/customers/{id}` | Get customer detail |
| GET | `/customers/stats/summary` | Customer statistics |
| GET | `/customers/universal` | Universal customer model |
| GET | `/customers/search` | Search customers |
| GET | `/customers/search/tags` | Search by tags |
| POST | `/customers/{id}/enrich` | Enrich customer data |
| POST | `/customers/enrich/bulk` | Bulk enrichment |
| POST | `/customers/{id}/clean` | Clean customer data |
| GET | `/customers/duplicates` | Find duplicate customers |
| POST | `/customers/duplicates/merge` | Merge duplicates |

---

### Notifications

| Method | Path | Description |
|--------|------|-------------|
| GET | `/notifications` | List notifications |
| GET | `/notifications/unread-count` | Unread count |
| GET | `/notifications/{id}` | Get notification |
| POST | `/notifications/{id}/read` | Mark as read |
| POST | `/notifications/read-all` | Mark all as read |
| DELETE | `/notifications/{id}` | Delete notification |
| POST | `/notifications/cleanup-expired` | Cleanup expired |

---

### Schedule / Appointments (MVP 1 - January 2026)

> Appointment management with team attendees and AI integration

**Controller:** `controllers/schedule.py`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/schedule` | List appointments (filtered by company_id) |
| POST | `/schedule` | Create appointment |
| GET | `/schedule/{id}` | Get appointment detail |
| PUT | `/schedule/{id}` | Update appointment |
| DELETE | `/schedule/{id}` | Delete appointment |
| GET | `/schedule/calendar/events` | Get events for calendar view |
| POST | `/schedule/{id}/send-reminder` | Send appointment reminder |

**Attendee Endpoints (MVP 1):**

| Method | Path | Description |
|--------|------|-------------|
| GET | `/schedule/{id}/attendees` | List attendees for appointment |
| POST | `/schedule/{id}/attendees` | Add attendee (sends notification) |
| DELETE | `/schedule/{id}/attendees/{user_id}` | Remove attendee |
| POST | `/schedule/{id}/respond` | Accept/decline invitation |
| GET | `/schedule/pending-invitations` | Get user's pending invitations |

---

### Orders API (January 2026)

> Order management with attribution tracking and refund capability

**Controller:** `controllers/orders.py`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/orders` | List orders with pagination/filtering |
| POST | `/orders` | Create order |
| GET | `/orders/{id}` | Get order detail with items |
| POST | `/orders/{id}/confirm` | Confirm order |
| POST | `/orders/{id}/cancel` | Cancel order |
| POST | `/orders/{id}/refund` | Process full/partial refund |
| POST | `/orders/{id}/allocate` | Allocate inventory |
| POST | `/orders/{id}/fulfill` | Mark as fulfilled |
| POST | `/orders/quick-sale` | **NEW** Virtual terminal/quick sale |
| POST | `/orders/calculateTotals` | Calculate order totals |
| POST | `/orders/suggestExtras` | AI suggest extras/upsells |
| POST | `/orders/applyExtras` | Apply suggested extras |

**Quick Sale Endpoint (NEW - January 2026):**

Unified virtual terminal endpoint for phone sales and quick payments. Creates Order + Transaction in one call.

```json
POST /api/v1/orders/quick-sale
{
  "amount": 99.99,
  "order_type": "card",       // card, ach, cash, check, text2pay
  "customer_name": "John Doe",
  "customer_email": "john@example.com",
  "customer_phone": "(555) 123-4567",
  "description": "Phone sale",
  "channel": "phone",
  "contact_id": 123,          // Optional - existing contact from typeahead
  "billing_address": "123 Main St",
  "billing_city": "New York",
  "billing_state": "NY",
  "billing_zip": "10001",     // Recommended for AVS
  "payment_method": {
    "cc": "4111111111111111",
    "mm": "12",
    "yy": "2028",
    "cvv": "123"
  },
  "check_number": "1234",     // Only for check payments
  "promoter_id": 456,         // Optional - affiliate/promoter for commission
  "commission_rate": 10.0     // Optional - override commission rate (%)
}
```

**Response:**
```json
{
  "success": true,
  "message": "Sale completed successfully",
  "order_id": 123,
  "order_number": "ORD-2026-A1B2C",
  "transaction_id": "TXN-20260104-ABCD1234",
  "amount": 99.99,
  "payment_status": "paid"
}
```

**Refund Request Body:**

```json
{
  "amount": 50.00,        // optional, omit for full refund
  "reason": "Customer request"
}
```

**Attribution Fields (new in bc5a0644b3a0):**

| Field | Type | Description |
|-------|------|-------------|
| `sold_by_user_id` | int | FK to users - sales person |
| `ai_agent_id` | string | AI agent (sage, sarah, marcus) |
| `promoter_id` | int | FK to affiliate_promoter - commission tracking |
| `channel` | enum | web, pos, phone, api, payment_link |
| `campaign_id` | int | Marketing campaign ID |
| `referral_source` | string | How customer found us |
| `utm_source/medium/campaign` | string | UTM tracking parameters |
| `commission_rate` | decimal | Commission % for attribution |

**Typeahead Endpoints for Quick Sale:**

| Method | Path | Description |
|--------|------|-------------|
| GET | `/crm/contacts/search/typeahead` | Search customers by name/email/phone/ID |
| GET | `/crm/promoters/search/typeahead` | Search promoters/affiliates for commission attribution |

---

### CRM Contacts API (Email CRM)

> Primary contact management with AI-powered dynamic columns
> See [CRM Contacts Page Reference](../24-Pages-Reference/crm-contacts.md)

**Prefix:** `/api/v1/crm`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/crm/contacts` | List contacts with search/filter |
| POST | `/crm/contacts` | Create new contact |
| GET | `/crm/contacts/{id}` | Get contact details |
| PUT | `/crm/contacts/{id}` | Update contact |
| DELETE | `/crm/contacts/{id}` | Delete contact |
| PATCH | `/crm/contacts/{id}/assign-agent` | Assign AI agent to contact (`?agent_id=N`) |
| POST | `/crm/contacts/export` | Export contacts to CSV |
| GET | `/crm/config` | Get CRM config (industry terminology, field schema) |

**Query Parameters (GET /crm/contacts):**

| Parameter | Type | Description |
|-----------|------|-------------|
| `search` | string | Search name, email, company |
| `source` | string | Filter by source (chat, form, api, import) |
| `contact_type` | string | Filter by type (patient, lead, customer) |
| `has_ai` | string | Filter by AI history (has_ai, no_ai) |
| `sort` | string | Sort order (newest, oldest, name_asc, name_desc) |
| `limit` | int | Results per page (default 1000) |

**Create Contact Request:**

```json
POST /crm/contacts
{
  "name": "John Smith",
  "email": "john@example.com",
  "phone": "+1 555-123-4567",
  "company_name": "Acme Inc",
  "source": "crm_dashboard",
  "custom_fields": {
    "loan_amount": 350000,
    "property_address": "123 Main St"
  }
}
```

**CRM Config Response:**

```json
GET /crm/config
{
  "labels": { "customer": "Patient", "contact": "Patient", ... },
  "contact_types": {
    "page_header": "Patients",
    "page_header_singular": "Patient",
    "types": [
      {"value": "patient", "label": "Patient"},
      {"value": "lead", "label": "New Patient"}
    ]
  },
  "field_schema": [
    { "field_key": "loan_amount", "field_label": "Loan Amount", "field_type": "currency", ... }
  ]
}
```

---

## MCP ENDPOINTS

### Internal MCP (Company-Scoped)

| Endpoint | Description |
|----------|-------------|
| `WSS /mcp` | WebSocket MCP endpoint |
| `POST /api/v1/mcp/keys` | Create API key |
| `GET /api/v1/mcp/keys` | List keys |
| `DELETE /api/v1/mcp/keys/{id}` | Revoke key |
| `GET /api/v1/mcp/audit` | Get action audit log |

### External MCP (Public)

| Endpoint | Description |
|----------|-------------|
| `POST /api/mcp` | External AI integration endpoint |
| `GET /api/mcp/sitemap.xml` | XML sitemap for Google/Bing |
| `GET /api/mcp/sitemap.json` | JSON sitemap for AI crawlers |
| `GET /api/mcp/pages/{slug}` | Page SEO metadata |
| `GET /api/mcp/robots.txt` | Robots.txt file |
| `GET /api/mcp/seo/catalog` | SEO-MCP discovery catalog |
| `GET /api/mcp/resources/catalog` | MCP resource catalog |
| `GET /api/mcp/resources/openapi` | OpenAPI schema |
| `GET /.well-known/ai-plugin.json` | ChatGPT plugin manifest |

---

## WEBHOOK ENDPOINTS

### Inbound Webhooks

| Method | Path | Description |
|--------|------|-------------|
| POST | `/webhooks/stripe` | Stripe webhook |
| POST | `/webhooks/<processor>` | processor payment [retired] webhook |
| POST | `/webhooks/shopify` | Shopify webhook |
| POST | `/webhooks/twilio/incoming` | Twilio incoming call |
| POST | `/webhooks/twilio/status` | Twilio call status |
| POST | `/webhooks/twilio/stream` | Twilio media stream |
| POST | `/webhooks/google/gmail` | Gmail webhook |
| POST | `/webhooks/google/calendar` | Google Calendar webhook |
| POST | `/webhooks/google/drive` | Google Drive webhook |
| POST | `/webhooks/microsoft/mail` | Microsoft Mail webhook |
| POST | `/webhooks/microsoft/drive` | Microsoft OneDrive webhook |
| POST | `/webhooks/microsoft/teams` | Microsoft Teams webhook |

---

## SUPER ADMIN ENDPOINTS

### Super Admin AI

| Method | Path | Description |
|--------|------|-------------|
| GET | `/superadmin/ai/dashboard` | Platform usage dashboard |
| GET | `/superadmin/ai/alerts` | AI usage alerts |
| POST | `/superadmin/ai/alerts/{id}/acknowledge` | Acknowledge alert |
| GET | `/superadmin/ai/companies` | Companies AI budget |
| GET | `/superadmin/ai/companies/{id}/budget` | Company budget |
| PATCH | `/superadmin/ai/companies/{id}/budget` | Update budget |
| GET | `/superadmin/ai/companies/{id}/usage` | Company usage |
| POST | `/superadmin/ai/companies/{id}/pause` | Pause AI |
| POST | `/superadmin/ai/companies/{id}/resume` | Resume AI |
| GET | `/superadmin/ai/providers/usage` | Provider usage |
| GET | `/superadmin/ai/cost-forecast/platform` | Platform cost forecast |
| GET | `/superadmin/ai/realtime/usage` | Realtime usage |

---

## FILE LOCATIONS

```
solid-backend/api/routers/
├── admin_integrations.py    # Admin OAuth connections
├── agent_roi.py             # Agent ROI dashboard
├── ai_audit.py              # AI audit trail
├── ai_content.py            # AI content generation
├── apps.py                  # Apps engine
├── chains.py                # Agent chains
├── chat_dashboard.py        # Chat dashboard
├── chat_integrations.py     # Google Chat / Teams
├── cms_analytics.py         # CMS analytics
├── companies.py             # Company management
├── cost_forecaster.py       # Cost forecasting
├── customers.py             # Customer management
├── data_mappings.py         # Data import mappings
├── experiments.py           # A/B experiments
├── file_browser.py          # File browser
├── gamification.py          # Gamification
├── kb_analytics.py          # KB analytics
├── knowledge_graph.py       # Knowledge graph
├── maintenance.py           # Maintenance mode
├── marcus_integration.py    # Marcus agent API
├── notifications.py         # Notifications
├── platform_features.py     # Platform features
├── platform_settings.py     # Platform settings
├── proactive.py             # Proactive insights
├── seats.py                 # Seat management
├── security.py              # Security scanning
├── social.py                # Social media
├── storage.py               # Document storage
├── superadmin_ai.py         # Super admin AI
├── superadmin_security.py   # Super admin security
├── superadmin_telemetry.py  # Super admin telemetry
├── telemetry.py             # Agent telemetry
├── tier_management.py       # Tier management
├── tiers.py                 # Subscription tiers
├── two_factor_auth.py       # 2FA
├── vibe.py                  # Vibe coding
├── vibe_permissions.py      # Vibe permissions
├── mcp_vibe.py              # MCP-authenticated vibe endpoints
├── webhooks.py              # Webhook receivers
└── workspace_ai.py          # Workspace AI
```

---

## See Also

- [Health Check Endpoints](../06-Operations/HEALTH-CHECK-ENDPOINTS.md) - Full health check guide
- [MCP Endpoint Index](../03-AI-Systems/MCP-ENDPOINT-INDEX.md) - AI discoverability
- [MCP Integration](../03-AI-Systems/MCP-INTEGRATION.md) - Internal MCP
- [MCP Server](../05-Public-Site/mcp-server.md) - External MCP
- [Database Schema](./database-schema.md) - All tables
- [Services](./services.md) - Business logic layer

---

*Last updated: January 4, 2026*


--- FILE: 02-Backend/CONTROLLER-PATTERNS.md ---

---
topic: backend
keywords: [backend, access, agents, analytics, async, auth, authentication, background, base]
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# Controller Patterns & Organization

> Complete guide to the controller files handling API requests in Solid#.

**Last Updated:** August 29, 2026

⭐ **Controller count and line counts are volatile — verified counts below are a snapshot, re-`wc -l`/`find` before quoting a number as fact.** The "172 active / 154 root-level" figures from an earlier pass had drifted badly by 2026-08-29 (real count is nearly double). Treat every number in this file as illustrative of shape, not as a fixed inventory to hand-type elsewhere.

---

## Overview

Controllers are the API layer in Solid#, handling HTTP requests, validation, authentication, and routing to services. They implement a thin-controller pattern where business logic lives in the service layer.

### Key Statistics (verified 2026-08-29)

| Metric | Count |
|--------|-------|
| **Total Controllers** | 313 files (`find controllers -name "*.py" \| wc -l`, incl. `__init__.py`) |
| **Root-level `controllers/*.py`** | 302 |

The `~82,100` LOC / `133 CRUD` / `116 async` / `11 webhook-handler` breakdown from the earlier pass could not be re-derived from a simple script and is left unverified rather than re-guessed — do not quote those four numbers as current.

---

## Directory Structure

```
controllers/
├── Root Level (302 controllers)
├── /accounting/ (4 files: __init__.py, connections.py, sync.py, webhooks.py)
├── /platform/ (2 files: __init__.py, platform_dashboard.py)
└── /ucp_capabilities/ (4 files: __init__.py, catalog.py, inbound_a2a.py,
    marketplace.py, signal_stream.py)   ← NOT in the earlier version of this doc
```

---

## Domain Categories

### 1. Core Business Operations

| Controller | Lines (2026-08-29) | Key Endpoints |
|------------|-------|---------------|
| `crm.py` | 5,552 | Contact CRUD, Activity logging, Lead grading |
| `orders.py` | 2,789 | Order management, Totals, Tips, Status |
| `users.py` | 1,792 | User CRUD, Roles, Invitations, Seats |
| `products.py` | 670 | Product CRUD, Components, Variants |
| `inventory.py` | 587 | Stock management, Reservations, Locations |
| `payments.py` | 850 | Charge processing, Refunds, Webhooks |
| `billing.py` | 2,366 | Subscriptions, Invoices, Usage tracking |
| `proposals.py` | 2,685 | Creation, Signing, PDF generation |

### 2. AI & Intelligent Agents

| Controller | Lines (2026-08-29) | Purpose |
|------------|-------|---------|
| `ada.py` | 1,642 | ADA (VP of AI) chat, Decision audit |
| `agents.py` | 4,760 | Multi-agent coordination (Devon, Marcus, Sage) |
| `ai_orchestration.py` | 400 | KB-powered AI collaboration |
| `ai_chat_integration.py` | 639 | Chat integration, Conversations |
| `ai_content_generation.py` | 611 | Marketing copy, Blog posts |
| `ai_workflow_builder.py` | 540 | Workflow automation |
| `gpt_suite.py` | 767 | GPT integration, Custom actions |

### 3. Customer Portals

⚠️ **`onboarding.py` no longer exists as a single file.** It was split into
`onboarding_steps.py`, `onboarding_complete.py`, `onboarding_config.py`,
`onboarding_checkout.py`, `onboarding_v2.py`, and `onboarding_session.py`.

| Controller | Lines (2026-08-29) | Purpose |
|------------|-------|---------|
| `customer_portal_controller.py` | 431 | Dashboard, Order history |
| `customer_portal_auth_controller.py` | 505 | Authentication, Password reset |
| `customer_portal_ocr_controller.py` | 740 | Document scanning, Invoice extraction |
| `merchant_enrollment.py` | 984 | Onboarding, KYC, Compliance |
| `onboarding_steps.py`, `onboarding_complete.py`, `onboarding_config.py`, `onboarding_checkout.py`, `onboarding_v2.py`, `onboarding_session.py` | (multi-step setup wizard, split across 6 files) | Multi-step setup wizard |

### 4. Integrations & Webhooks

⛔ **`processor_webhooks.py` does not exist in `controllers/`.** The retired processor (Third Party
Payments / Solid Payments) is DEAD and never returns. Solid#'s OWN billing is
processed through Stripe today; that is an adapter choice, not the architecture — the universal payment layer (`services/payments/base.py::PaymentAdapter` + the registry in `services/payments/registry.py`) is the core; processors are swappable adapters behind it. Legacy payment
processor. Do not reintroduce this row; it is removed, not just renamed.

| Controller | Lines (2026-08-29) | Purpose |
|------------|-------|---------|
| `accounting/webhooks.py` | 510 | Accounting events, Balance updates |
| `platform_commerce_webhooks.py` | 1,372 | E-commerce webhooks |
| `webhooks_inbound.py` | 460 | Inbound webhook routing |

### 5. Knowledge Base & Content

| Controller | Lines (2026-08-29) | Purpose |
|------------|-------|---------|
| `unified_kb_controller.py` | 2,942 | Multi-source KB, Search |
| `knowledge_base_admin_controller.py` | 740 | KB management, Bulk ops |
| `landing_pages.py` | 725 | Template management |

### 6. Dashboard & Analytics

| Controller | Lines (2026-08-29) | Purpose |
|------------|-------|---------|
| `dashboard.py` | 2,451 | KPIs, Revenue, Cached aggregation |
| `analytics.py` | 203 | Event tracking, Metrics |
| `monitoring.py` | 713 | System health, Alerts |

---

## Common Patterns

### 1. Multi-Tenant Isolation (ALL controllers)

```python
# CRITICAL: company_id from JWT, NEVER from client
@router.get("/contacts")
async def get_contacts(
    current_user: User = Depends(get_current_user)
):
    company_id = current_user.company_id  # From JWT
    return db.query(Contact).filter(
        Contact.company_id == company_id
    ).all()
```

### 2. CRUD Operations Pattern

```python
@router.get("/{id}")
async def get_item(id: int, db: Session = Depends(get_db)):
    ...

@router.post("/")
async def create_item(data: CreateSchema, db: Session = Depends(get_db)):
    ...

@router.put("/{id}")
async def update_item(id: int, data: UpdateSchema):
    ...

@router.delete("/{id}")
async def delete_item(id: int):
    ...
```

### 3. Async/Background Operations

```python
@router.post("/bulk-import")
async def bulk_import(
    data: ImportData,
    background_tasks: BackgroundTasks
):
    background_tasks.add_task(process_import, data)
    return {"status": "processing"}
```

### 4. Pagination & Filtering

```python
@router.get("/orders")
async def list_orders(
    limit: int = Query(default=100, le=500),
    offset: int = Query(default=0),
    status: Optional[str] = None
):
    query = db.query(Order)
    if status:
        query = query.filter(Order.status == status)
    return query.offset(offset).limit(limit).all()
```

### 5. Webhook Handling

```python
@router.post("/webhooks/stripe")
async def handle_stripe_webhook(
    request: Request,
    stripe_signature: str = Header(None)
):
    payload = await request.body()
    # Verify signature
    event = stripe.Webhook.construct_event(
        payload, stripe_signature, webhook_secret
    )
    # Process idempotently
    return {"received": True}
```

### 6. Service Layer Integration

```python
@router.post("/refund")
async def process_refund(
    data: RefundRequest,
    db: Session = Depends(get_db)
):
    # Controller is thin - delegates to service
    service = ChargeBackService(db)
    return await service.process_refund(data)
```

### 7. Caching (Dashboard)

```python
@router.get("/dashboard")
async def get_dashboard(
    company_id: int,
    redis: Redis = Depends(get_redis)
):
    cache_key = f"dashboard:{company_id}"
    cached = await redis.get(cache_key)
    if cached:
        return json.loads(cached)

    # Compute and cache
    data = await compute_dashboard(company_id)
    await redis.setex(cache_key, 300, json.dumps(data))
    return data
```

---

## Route Prefix Conventions

| Pattern | Usage |
|---------|-------|
| `/api/v1/*` | Versioned API endpoints (most common) |
| `/` | Root routes (health checks) |
| `/admin/*` | Admin-only endpoints |
| `/customer-portal/*` | Customer-facing endpoints |
| `/.well-known/mcp.json` | MCP discovery |

---

## File Size Distribution

### Large Controllers (>2000 LOC, verified 2026-08-29)
- `crm.py` (5,552) - Complete CRM domain
- `agents.py` (4,760) - Multi-agent coordination
- `orders.py` (2,789) - Order management
- `proposals.py` (2,685) - Document generation
- `billing.py` (2,366) - Subscriptions, invoices, usage
- `unified_kb_controller.py` (2,942) - Multi-source KB
- `dashboard.py` (2,451) - Aggregation + caching

Note: `onboarding.py` no longer exists as a single file — see the split list
above.

### Medium / Small Controllers
Not re-audited file-by-file this pass — with 313 total controller files
(up from an earlier count of 172), the "30+ medium / 80+ small" buckets are
stale and were left unverified rather than re-guessed.

---

## Authentication Patterns

```python
# Standard auth dependency
@router.get("/protected")
async def protected_route(
    current_user: User = Depends(get_current_user)
):
    return {"user": current_user.email}

# Role-based access
@router.delete("/admin/{id}")
async def admin_only(
    current_user: User = Depends(get_current_user)
):
    if current_user.role != "admin":
        raise HTTPException(403, "Admin required")
```

---

## Error Handling

```python
@router.get("/items/{id}")
async def get_item(id: int):
    item = db.query(Item).get(id)
    if not item:
        raise HTTPException(
            status_code=404,
            detail="Item not found"
        )
    return item
```

---

## Best Practices

1. **Keep controllers thin** - Delegate to services
2. **Always validate company_id from JWT** - Never trust client
3. **Use Pydantic schemas** for request/response validation
4. **Implement pagination** for list endpoints
5. **Use background tasks** for long operations
6. **Cache expensive queries** with Redis
7. **Log security events** to audit trail
8. **Handle errors gracefully** with proper HTTP codes

---

## Related Documentation

- [Service Layer Architecture](./service-layer-architecture.md) - Business logic
- [API Endpoints](./api-endpoints.md) - All 1,342 routes
- [Middleware Architecture](./middleware-architecture.md) - Request pipeline

---

*Controllers route requests. Services handle logic. Database stores data.*


--- FILE: 02-Backend/DATA-IMPORT-ENGINE.md ---

---
topic: core-innovations
keywords: [core-innovations, access, agent, agentic, analysis, analyzes, anything, architecture, available]
code_paths:
  - solid-backend/services/ai_field_mapper.py
  - solid-backend/services/ai_field_mapper_enhanced.py
  - solid-backend/services/data_transform.py
  - solid-backend/services/import_executor.py
  - solid-backend/services/schema_evolution_service.py
  - solid-backend/tasks/post_import_agents.py
  - solid-backend/api/routers/data_mappings.py
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# Universal Data Import Engine

> AI-powered data import that handles ANY CSV/Excel file intelligently.

---

## Overview

The Solid# Data Import Engine is an AI-first universal data integration platform that transforms messy CSV/Excel files into clean CRM data with zero schema changes required.

**What Makes It Incredible:**
- **Claude-Powered Field Mapping** - AI analyzes column names and suggests mappings
- **Any CSV → Any CRM Table** - Works with any file structure
- **JSONB Flexible Storage** - Unmapped fields stored without schema changes
- **30+ Transformation Functions** - Built-in data cleaning
- **Agentic MCP Integration** - Enhanced version uses tools for iterative refinement

---

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│                     USER UPLOADS FILE                        │
│                    (CSV, Excel, 5-1000+ columns)             │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                   UNIVERSAL FILE PARSER                      │
│                                                              │
│  Reads file → extracts columns → sample data → data types   │
│  Creates StagedImport with raw_data                          │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    AI FIELD MAPPER                           │
│                    (Claude Sonnet 4)                         │
│                                                              │
│  • Analyzes column names semantically                        │
│  • Maps to CRM schema with confidence scores                 │
│  • Suggests transformations (split, concat, validate)        │
│  • Routes business-specific data to custom_fields JSONB      │
│  • Handles multi-table mapping (customers, contacts, addr)   │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  TRANSFORMATION ENGINE                       │
│                                                              │
│  30+ built-in functions:                                     │
│  • String: upper, lower, split, concat, regex_extract        │
│  • Numeric: safe_float, round, multiply, divide              │
│  • Date: parse_date, format_date, date_add                   │
│  • Validation: validate_email, validate_phone                │
│  • Business: calculate_lead_score, calculate_lead_grade      │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                     FILTER ENGINE                            │
│                                                              │
│  12+ operators: ==, !=, >, <, IN, CONTAINS, IS NULL          │
│  Example: Only VA properties > $250k with 30%+ equity        │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    IMPORT EXECUTOR                           │
│                                                              │
│  • Atomic transactions (all-or-nothing)                      │
│  • Duplicate detection (skip/update/create)                  │
│  • Multi-user access grants                                  │
│  • CRM sync for immediate availability                       │
│  • Raw SQL for performance (100k+ rows)                      │
└─────────────────────────────────────────────────────────────┘
```

---

## Core Services

### 1. AI Field Mapper
**File:** `solid-backend/services/ai_field_mapper.py` (765 lines, verified 2026-08-29)

Uses Claude to intelligently map source columns to CRM schema:

```python
# Example: AI analyzes this column
source_column = "OWNER 1 FIRST NAME"
sample_data = ["John", "Jane", "Bob"]

# Returns mapping with confidence
{
    "source_column": "OWNER 1 FIRST NAME",
    "target_field": "first_name",
    "confidence": 0.95,
    "suggested_transform": null
}
```

**Key Functions:**
| Function | Purpose |
|----------|---------|
| `suggest_mappings()` | Generate AI field mapping suggestions |
| `validate_mappings()` | Check mapping validity |
| `validate_mappings_with_data()` | Advanced validation with sample data |

### 2. AI Field Mapper Enhanced
**File:** `solid-backend/services/ai_field_mapper_enhanced.py` (364 lines, verified 2026-08-29)

Next-gen version with MCP tool integration:

```python
# Agentic loop - Claude can call tools during analysis
tools = [
    "analyze_csv_quality",      # Data quality analysis
    "suggest_field_mappings",   # Pattern-based suggestions
    "preview_transformation"    # Show transformed sample
]
```

### 3. Import Executor
**File:** `solid-backend/services/import_executor.py` (1,084 lines, verified 2026-08-29)

Core execution engine with enterprise features:

```python
# JSONB Custom Fields - store anything without schema changes
custom_fields = {
    "property": {
        "apn": "12345",
        "address": "123 Main St",
        "valuation": {
            "market_value": 450000,
            "equity_value": 180000
        }
    }
}

# Multi-user access during import
customer = import_with_access(
    assigned_user_ids=[user1, user2, user3],
    access_level="write"
)
```

### 4. Transformation Engine
**File:** `solid-backend/services/data_transform.py` (807 lines, verified 2026-08-29)

30+ built-in transformation functions:

**String Operations:**
```
upper(), lower(), title(), trim()
split(delimiter, index), concat()
replace(old, new), substring(start, end)
regex_extract(pattern, group)
```

**Numeric Operations:**
```
safe_float(default), safe_int(default)
round_number(decimals), multiply(factor)
divide(divisor), percentage_to_decimal()
```

**Validation/Cleaning:**
```
validate_email(), validate_phone(country)
validate_url(), validate_zip_code(country)
```

**Business Logic:**
```
calculate_lead_score(row)   # 0-100 score
calculate_lead_grade(score) # A/B/C/D/F
calculate_lead_tier(score)  # hot/warm/cold
```

### 5. Filter Engine
**File:** `solid-backend/services/data_transform.py`

Row-level filtering before import:

```python
# Operators: ==, !=, >, <, >=, <=, IN, NOT IN,
#            CONTAINS, NOT CONTAINS, IS NULL, IS NOT NULL

filter_rules = [
    {"field": "SITUS STATE", "operator": "IN", "value": ["VA", "MD", "DC"]},
    {"field": "MARKET TOTAL VALUE", "operator": ">=", "value": 250000},
    {"field": "EQUITY PERCENTAGE", "operator": ">=", "value": 0.3},
    {"field": "DO NOT MAIL", "operator": "!=", "value": "Y"}
]
```

---

## CRM Schema Support

The AI maps to this schema:

```python
CRM_SCHEMA = {
    "customers": {
        "fields": [
            "customer_number", "first_name", "last_name", "display_name",
            "primary_email", "primary_phone", "type", "status", "source",
            "source_campaign", "lead_score", "lead_grade", "tags",
            "custom_fields"  # Flexible JSONB for anything else
        ]
    },
    "customer_contacts": {
        "fields": ["contact_type", "label", "value", "is_primary"]
    },
    "customer_addresses": {
        "fields": ["address_type", "street", "city", "state", "zip", "country"]
    }
}
```

---

## API Endpoints

⚠️ **Corrected 2026-08-29** against `solid-backend/api/routers/data_mappings.py`
(mounted at `/api/v1/data-mappings`, prefix declared in the router itself).
Several routes in the previous version of this table do not exist —
`/data-mappings/upload` was never a real path (upload is `upload-file` /
`upload-async`), `/data-mappings/{id}/execute` doesn't exist (import
execution is `/{mapping_id}/import` or `/staged-imports/{id}/execute`),
`/data-mappings/{id}/jobs` doesn't exist (jobs are listed globally at
`/jobs`, not nested under a mapping id), and there is no `PUT
/data-mappings/{id}` route — only GET and DELETE were found.

| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/data-mappings` | POST | Create new data source mapping |
| `/data-mappings` | GET | List all mappings for company |
| `/data-mappings/{mapping_id}` | GET/DELETE | Read / delete a mapping (no PUT route exists) |
| `/data-mappings/suggest` | POST | Get AI field mapping suggestions |
| `/data-mappings/suggest-with-mcp` | POST | Agentic (MCP-tool) field mapping suggestions |
| `/data-mappings/upload-file` | POST | Upload CSV/Excel and preview |
| `/data-mappings/upload-async` | POST | Upload large file, async processing |
| `/data-mappings/staged-imports` | GET | List staged imports |
| `/data-mappings/staged-imports/{id}/execute` | POST | Execute import from staged data |
| `/data-mappings/{mapping_id}/import` | POST | Execute import via a saved mapping |
| `/data-mappings/jobs` | GET | List import jobs |
| `/data-mappings/jobs/{job_id}` | GET | Job status |
| `/data-mappings/jobs/{job_id}/rollback` | POST | Roll back a completed import |
| `/data-mappings/csv-templates` | GET | List available templates |

---

## Data Models

### DataSourceMapping
Configuration for external data source:

```python
class DataSourceMapping:
    name: str
    description: str
    source_type: str  # csv, excel, api, google_sheets, mcp_server
    connection_config: JSONB
    field_mappings: JSONB[]
    transformation_rules: JSONB[]
    filter_rules: JSONB[]
    target_entity: str  # customers, contacts, deals
    duplicate_check_field: str
    duplicate_strategy: str  # skip, update, create_anyway
    default_status: str
    default_tags: str[]
    is_template: bool  # For marketplace
    schedule_enabled: bool
    cron_schedule: str
    ai_suggested: bool
    ai_confidence_avg: float
```

### DataImportJob
Track import execution:

```python
class DataImportJob:
    mapping_id: int
    status: str  # pending, running, completed, failed
    file_path: str
    stats: JSONB
    imported_record_ids: int[]
    error_message: str
    duration_seconds: int
    triggered_by: str  # user, schedule, api
```

### StagedImport
Intermediate import data:

```python
class StagedImport:
    source_name: str
    data_type: str  # AI-detected: leads, customers, property
    raw_data: JSONB
    detected_schema: JSONB
    field_mappings: JSONB
    status: str  # pending, analyzed, mapped, ready_to_import, imported
```

---

## Import Workflow

### Step 1: Upload File
```
User selects CSV/Excel → uploads via /data-mappings/upload
```

### Step 2: AI Analysis
```
Claude analyzes column names and sample data
Detects data type: "leads", "customers", "property"
Returns confidence-scored mapping suggestions
```

### Step 3: User Review
```
User reviews AI suggestions in mapping UI
Can edit, add, or remove mappings
Optional: Add transformations and filters
```

### Step 4: Execute Import
```
ImportExecutor.execute_import():
1. Reads file
2. Filters rows (skip unmatched)
3. Transforms data
4. Handles duplicates
5. Stores unmapped in custom_fields
6. Creates customer records
7. Syncs to CRM module
8. Commits atomically
```

### Step 5: Post-Import Agent Processing
```
🚀 Celery Task: process_imported_data (automatic)

Food Agents process the imported data:
• 🥬 Kale - Validate data quality (missing emails, bad formats)
• 🥔 Potato - Segment customers (VIP detection, lifecycle stages)
• 🍟 French Fries - Extract patterns (sources, tags, types)
• 🥩 Meat - Load summary to KB for Sage to query
• 🔗 Contact Matching - Check duplicates & create relationships
  - Detect households (husband/wife at same address)
  - Detect company relationships (employees)
  - Flag uncertain matches for review
```

### Step 6: Data Available
```
Imported data immediately available in:
• Customers dashboard (with segments applied)
• Lead targeting (VIP/high-value flagged)
• CRM contacts (households detected)
• Search/filtering
• Marketing campaigns
• Reports
• Sage AI (can answer "What did we import?")
```

---

## Post-Import Agent Pipeline (NEW - Jan 2026)

After data is imported, the system automatically triggers a Celery task that runs Food Agents for post-processing:

```
┌─────────────────────────────────────────────────────────────────┐
│                   POST-IMPORT AGENT PIPELINE                     │
│                   tasks/post_import_agents.py                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Phase 1: 🥬 Kale (Data Validation)                             │
│  ─────────────────────────────────────                          │
│  • Check required fields (email OR phone required)              │
│  • Validate email formats                                       │
│  • Count valid vs invalid records                               │
│  • Returns: { valid_count, invalid_count, validation_rate }    │
│                                                                  │
│  Phase 2: 🥔 Potato (Customer Segmentation)                     │
│  ─────────────────────────────────────────                      │
│  • Detect VIPs (LTV > $10k, orders > 20)                       │
│  • Classify high-value (LTV > $1k, orders > 5)                 │
│  • Set lifecycle_stage (vip, customer, lead)                   │
│  • Returns: { segments: { vip, high_value, regular, new } }    │
│                                                                  │
│  Phase 3: 🍟 French Fries (Pattern Extraction)                  │
│  ──────────────────────────────────────────                     │
│  • Extract source distribution (web, referral, import)         │
│  • Analyze tag patterns                                         │
│  • Customer type breakdown                                      │
│  • Returns: { top_sources, top_tags, customer_types }          │
│                                                                  │
│  Phase 4: 🥩 Meat (KB Loader)                                   │
│  ─────────────────────────────                                  │
│  • Create KB entry with import summary                          │
│  • Sage can now answer: "What did we import today?"            │
│  • Includes: record counts, LTV totals, lifecycle breakdown    │
│  • Returns: { kb_entry_created, kb_entry_id }                  │
│                                                                  │
│  Phase 5: 🔗 Contact Matching                                   │
│  ────────────────────────────                                   │
│  • Check imported records against existing contacts             │
│  • Detect duplicate emails (95% confidence)                     │
│  • Detect duplicate phones (85% confidence)                     │
│  • Create HOUSEHOLD relationships (same address)                │
│    → John & Jane Smith at 123 Main St = household               │
│  • Create COMPANY relationships (same company_name)             │
│    → Tagged: company_employee, company:CompanyName              │
│  • Flag uncertain matches for review queue                      │
│  • Returns: { exact_matches, households_created, flagged }     │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
                    📨 Event: data.import_processed
                    (Real-time UI notification)
```

### Agent Responsibilities

| Agent | What It Does | NOT Sarah (Customer Service) |
|-------|--------------|------------------------------|
| **Kale** 🥬 | Validate imported data | Sarah handles customer CHAT |
| **Potato** 🥔 | Segment customers (VIP, high-value) | Sarah doesn't classify data |
| **French Fries** 🍟 | Extract patterns & distributions | Sarah doesn't analyze trends |
| **Meat** 🥩 | Load to KB for Sage | Sarah doesn't manage KB |
| **Contact Matcher** 🔗 | Detect duplicates & relationships | Sarah doesn't manage contacts |

### Household Detection

When multiple people are imported with the same address, the system creates household relationships:

```
IMPORT:
  - John Smith, john@example.com, 123 Main St, 84101
  - Jane Smith, jane@example.com, 123 Main St, 84101

RESULT:
  ┌────────────────────────────────────────────────────────┐
  │  HOUSEHOLD: 123 Main St, 84101                          │
  ├────────────────────────────────────────────────────────┤
  │  Member 1: John Smith → tagged: household               │
  │  Member 2: Jane Smith → tagged: household               │
  │                                                         │
  │  Relationship: household_member                         │
  │  Stored in: CustomerRelationship table                  │
  └────────────────────────────────────────────────────────┘
```

### Company Relationship Detection

When multiple people share the same `company_name`:

```
IMPORT:
  - Alice, alice@acme.com, Acme Corp
  - Bob, bob@acme.com, Acme Corp
  - Carol, carol@acme.com, Acme Corp

RESULT:
  All three tagged with:
  - company_employee
  - company:Acme Corp

  Easy to filter: "Show all Acme Corp employees"
```

### Configuration

The post-import pipeline is triggered automatically. Configuration in `celery_app.py`:

```python
# Task routing
task_routes = {
    "tasks.post_import_agents.*": {"queue": "kb"},
}

# Included in Celery worker
include = [
    "tasks.post_import_agents",
    # ... other tasks
]
```

### File Locations

```
solid-backend/
├── tasks/
│   └── post_import_agents.py    # Post-import agent pipeline
├── api/routers/
│   └── data_mappings.py         # Triggers task after import
└── celery_app.py                # Task registration + routing
```

---

## AI Schema Evolution (NEW - January 2026)

When data is imported with columns that don't match existing schema, the system automatically evolves the schema:

```
┌─────────────────────────────────────────────────────────────────┐
│                   AI SCHEMA EVOLUTION                            │
│                   services/schema_evolution_service.py           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Step 1: Detect New Fields                                       │
│  ───────────────────────────                                     │
│  Compare AI field mappings to existing CompanyFieldSchema        │
│  Identify columns mapped to custom_fields (not core fields)      │
│                                                                  │
│  Step 2: Infer Field Types                                       │
│  ─────────────────────────                                       │
│  Analyze sample data from import:                                │
│  • Currency patterns: $1,234.56 → "currency"                     │
│  • Email patterns: *@*.* → "email"                               │
│  • Phone patterns: (555) 123-4567 → "phone"                      │
│  • URL patterns: http(s)://... → "url"                           │
│  • Boolean patterns: yes/no, true/false → "boolean"              │
│  • Numeric patterns: 123.45 → "number"                           │
│  • Date patterns: 2024-01-15 → "date"                            │
│  • Default → "text"                                              │
│                                                                  │
│  Step 3: Generate Field Labels                                   │
│  ─────────────────────────────                                   │
│  Convert column names to human-readable labels:                  │
│  • "loan_amount" → "Loan Amount"                                 │
│  • "OWNER_1_NAME" → "Owner 1 Name"                              │
│  • "propertyAddress" → "Property Address"                        │
│                                                                  │
│  Step 4: Create CompanyFieldSchema                               │
│  ─────────────────────────────────                               │
│  For each new field, create schema record:                       │
│  {                                                               │
│      field_key: "loan_amount",                                   │
│      field_label: "Loan Amount",                                 │
│      field_type: "currency",                                     │
│      entity_type: "contact",                                     │
│      source: "ai_import",                                        │
│      is_visible: true,                                           │
│      is_filterable: true                                         │
│  }                                                               │
│                                                                  │
│  Step 5: UI Auto-Updates                                         │
│  ────────────────────────                                        │
│  Frontend reads field schema from /crm/config                    │
│  buildDynamicColumns() generates table columns                   │
│  New columns appear immediately in Contacts table                │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

### Example Flow

```
IMPORT CSV: homeowners.csv
┌────────────────────────────────────────────────────────────┐
│  Name, Email, Loan Amount, Property Address, Equity %      │
│  John Smith, john@example.com, $350000, 123 Main St, 45%  │
└────────────────────────────────────────────────────────────┘
                              │
                              ▼
AI FIELD MAPPER analyzes columns:
  • "Name" → first_name (core field)
  • "Email" → email (core field)
  • "Loan Amount" → custom_fields.loan_amount (NEW)
  • "Property Address" → custom_fields.property_address (NEW)
  • "Equity %" → custom_fields.equity_percentage (NEW)
                              │
                              ▼
SCHEMA EVOLUTION detects new fields:
  • loan_amount: sample "$350000" → type "currency"
  • property_address: sample "123 Main St" → type "text"
  • equity_percentage: sample "45%" → type "number"
                              │
                              ▼
CREATES CompanyFieldSchema records:
  [
    { field_key: "loan_amount", field_type: "currency", ... },
    { field_key: "property_address", field_type: "text", ... },
    { field_key: "equity_percentage", field_type: "number", ... }
  ]
                              │
                              ▼
CONTACTS TABLE updates automatically:
  ┌─────────────────────────────────────────────────────────────────┐
  │ Name | Email | Phone | Loan Amount | Property | Equity % | ... │
  └─────────────────────────────────────────────────────────────────┘
```

### Field Type Detection Patterns

```python
DETECTION_PATTERNS = {
    "currency": [r"^\$[\d,]+\.?\d*$", r"^\d+\.\d{2}$"],
    "email": [r"^[^\s@]+@[^\s@]+\.[^\s@]+$"],
    "phone": [r"^\+?[\d\s\-\(\)]+$"],
    "url": [r"^https?://"],
    "boolean": ["yes", "no", "true", "false", "1", "0"],
    "date": [r"^\d{4}-\d{2}-\d{2}$", r"^\d{1,2}/\d{1,2}/\d{2,4}$"],
    "number": [r"^[\d,]+\.?\d*$"]
}
```

### File Locations

```
solid-backend/
├── services/
│   └── schema_evolution_service.py   # AI schema evolution logic
├── models/
│   └── data_mapping.py               # CompanyFieldSchema model
├── api/routers/
│   └── companies.py                  # Field schema CRUD endpoints
└── controllers/
    └── crm_contacts.py               # Validates custom_fields on save
```

### API Endpoints

| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/companies/{id}/field-schemas` | GET | List field schemas |
| `/companies/{id}/field-schemas` | POST | Create field schema |
| `/companies/{id}/field-schemas/{id}` | PUT | Update field schema |
| `/companies/{id}/field-schemas/{id}` | DELETE | Delete field schema |

---

## What Makes This Incredible

### AI Capabilities
1. **Semantic Field Matching** - Understands "OWNER 1 FIRST NAME" = first_name
2. **Confidence Scoring** - Each mapping includes 0.0-1.0 confidence
3. **Business Context Awareness** - Understands industry context
4. **Sample Data Validation** - Tests transformations against real data
5. **Automatic Transform Suggestions** - Recommends split(), validate_email(), etc.
6. **Agentic Analysis** - Enhanced version uses MCP tools

### Data Handling
7. **JSONB Flexible Storage** - Any data without schema changes
8. **Nested Field Support** - Dot notation: custom_fields.property.valuation.market_value
9. **Multi-Table Normalization** - Unified access across tables
10. **Intelligent Deduplication** - Merges records by email

### Enterprise Features
11. **Atomic Transactions** - All-or-nothing import
12. **Multi-User Access** - Grant access during import
13. **CRM Sync** - Leads immediately in CRM
14. **Template Marketplace** - Save/share mappings
15. **Scheduled Imports** - Cron-based recurring
16. **Import Rollback** - Delete all records from failed import

### Performance
17. **Raw SQL Execution** - 10x faster than ORM
18. **Batch Processing** - 100k+ row files
19. **Streaming Transforms** - Low memory usage
20. **Smart Filtering** - Filter before transform

---

## File Locations

```
solid-backend/services/
├── ai_field_mapper.py           # Claude field mapping
├── ai_field_mapper_enhanced.py  # MCP-enhanced mapper
├── ai_data_adapter.py           # Cross-table access
├── import_executor.py           # Core import engine
├── data_transform.py            # Transformation functions
└── apps/
    └── excel_parser.py          # Excel file handling

solid-backend/controllers/
└── inventory_import.py          # Inventory-specific import

solid-backend/api/routers/
└── data_mappings.py             # REST API endpoints

solid-backend/models/
└── data_mapping.py              # DataSourceMapping, DataImportJob, StagedImport
```

---

## Next Steps

- [Knowledge Bases](../07-Business-Logic/KNOWLEDGE-BASES.md) - KB system
- [Complete Feature Inventory](../09-Core-Innovations/COMPLETE-FEATURE-INVENTORY.md) - All features
- [App Engine](../09-Core-Innovations/APP-ENGINE.md) - Plugin system


--- FILE: 02-Backend/DATABASE-MIGRATIONS.md ---

---
topic: backend
keywords: [backend, add_contact_type_column, add_order_sales_columns, alembic, apply, auto-generate, best, changes, check]
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# Database Migrations (Alembic)

> Schema evolution with Alembic. 420+ migrations tracked as of 2026-08-29
> (`ls migrations/versions/*.py | wc -l` → 421) — this count grows daily,
> don't quote "40+" or any other stale figure; re-count before citing.

**Last Updated:** August 29, 2026

---

## Structure

```
solid-backend/
├── migrations/
│   └── versions/          # Migration files (⚠️ NOT alembic/versions/)
└── alembic.ini             # Alembic config (script_location = migrations)
```

⚠️ **`init-multiple-databases.sh` is NOT under `solid-backend/scripts/`.**
It lives at the **monorepo root**: `scripts/init-multiple-databases.sh`, and
is bind-mounted by the root-level `docker-compose.local.yml`
(`./scripts/init-multiple-databases.sh:/docker-entrypoint-initdb.d/01-init-multiple-databases.sh`),
not by anything inside `solid-backend/`.

> **⚠️ Important:** Migrations are in `migrations/versions/`, NOT `alembic/versions/`

---

## Multi-Database Setup

Two databases in PostgreSQL, created via `POSTGRES_MULTIPLE_DATABASES=solid_dev,arcade_db`:
- `solid_dev` - Main application database
- `arcade_db` - Arcade API database

Created by the root-level `scripts/init-multiple-databases.sh` at container startup (see path correction above).

---

## Common Commands

### Check Current Version
```bash
cd solid-backend
alembic current
```

### Create New Migration
```bash
# Auto-generate from model changes
alembic revision --autogenerate -m "add user preferences table"

# Empty migration for manual edits
alembic revision -m "custom data migration"
```

### Apply Migrations
```bash
# Upgrade to latest
alembic upgrade head

# Upgrade one step
alembic upgrade +1

# Upgrade to specific revision
alembic upgrade abc123
```

### Rollback
```bash
# Rollback one step
alembic downgrade -1

# Rollback to specific revision
alembic downgrade abc123

# Rollback all
alembic downgrade base
```

---

## Migration File Structure

```python
"""add user preferences table

Revision ID: abc123def456
Revises: xyz789ghi012
Create Date: 2025-11-29 12:00:00.000000
"""
from alembic import op
import sqlalchemy as sa

revision = 'abc123def456'
down_revision = 'xyz789ghi012'

def upgrade():
    op.create_table(
        'user_preferences',
        sa.Column('id', sa.Integer(), primary_key=True),
        sa.Column('user_id', sa.Integer(), sa.ForeignKey('users.id')),
        sa.Column('settings', sa.JSON()),
    )

def downgrade():
    op.drop_table('user_preferences')
```

---

## Best Practices

1. **Always test rollback** - Run `downgrade` then `upgrade` locally
2. **One change per migration** - Easier to debug and rollback
3. **No data in schema migrations** - Use separate data migrations
4. **Name clearly** - `add_`, `remove_`, `alter_`, `create_`

---

## Troubleshooting

### Head Mismatch
```bash
# Check for multiple heads
alembic heads

# Merge if needed
alembic merge -m "merge heads" abc123 xyz789
```

### Stamp Current State
```bash
# Mark DB as current without running migrations
alembic stamp head
```

### Fresh Start (Dev Only)
```bash
# Drop all and recreate
alembic downgrade base
alembic upgrade head
```

---

## Docker Usage

```bash
# Run migrations in container
docker exec solid-backend alembic upgrade head

# Check status
docker exec solid-backend alembic current
```

---

## Recent Migrations (January 2026)

### 20260104_add_contact_type_column.py

Adds industry-aware `contact_type` column to `contacts` table (EmailContact model):

```python
op.add_column('contacts', sa.Column('contact_type', sa.String(50), nullable=True, server_default='contact'))
op.create_index('ix_contacts_contact_type', 'contacts', ['contact_type'])
```

### 20260104_add_order_sales_columns.py

Adds sales dashboard columns to `orders` table:

| Column | Type | Purpose |
|--------|------|---------|
| `order_number` | VARCHAR(64) | Human-readable order ID (ORD-2026-XXXXX) |
| `order_type` | VARCHAR(20) | Payment type: card, cash, invoice, service |
| `payment_status` | VARCHAR(32) | pending, paid, refunded, failed |
| `fulfillment_status` | VARCHAR(32) | unfulfilled, processing, shipped, delivered |
| `is_demo` | BOOLEAN | Demo data flag for sandbox isolation |

---

## Running Migrations Locally

**⚠️ Must set DATABASE_URL for PostgreSQL:**

```bash
# Wrong (uses SQLite):
alembic upgrade head

# Correct:
DATABASE_URL=postgresql://solidnumber:solid_dev_password@127.0.0.1:5432/solid_dev alembic upgrade head
```


--- FILE: 02-Backend/ER-DIAGRAM.md ---

---
topic: backend
keywords: [database, schema, er-diagram]
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# Database ER Diagram

> **Last Updated:** December 5, 2025
> **Status:** Stub - Full Diagram Coming Soon
> **Location:** `02-Backend/er-diagram.md`

---

## Overview

This document will contain the Entity-Relationship diagram for the Solid# database schema.

---

## Core Tables (Preview)

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                    SOLID# DATABASE SCHEMA (PREVIEW)                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  CORE ENTITIES                                                               │
│  ─────────────                                                               │
│                                                                              │
│  companies ──────────┐                                                       │
│  │ id (PK)          │                                                       │
│  │ name             │                                                       │
│  │ slug             │                                                       │
│  │ plan_tier        │                                                       │
│  │ industry_code    │                                                       │
│  └──────────────────┘                                                       │
│           │                                                                  │
│           │ 1:N                                                              │
│           ▼                                                                  │
│  ┌────────────────┐     ┌────────────────┐     ┌────────────────┐          │
│  │     users      │     │   contacts     │     │    products    │          │
│  │  company_id ──►│     │  company_id ──►│     │  company_id ──►│          │
│  │  email         │     │  name, email   │     │  name, sku     │          │
│  │  role          │     │  phone         │     │  price         │          │
│  └────────────────┘     └────────────────┘     └────────────────┘          │
│                                 │                                            │
│                                 │ 1:N                                        │
│                                 ▼                                            │
│                        ┌────────────────┐                                   │
│                        │     deals      │                                   │
│                        │  company_id ──►│                                   │
│                        │  contact_id    │                                   │
│                        │  amount, stage │                                   │
│                        └────────────────┘                                   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## Table Categories

| Category | Tables | Purpose |
|----------|--------|---------|
| **Core** | companies, users | Multi-tenant foundation |
| **CRM** | contacts, deals, leads, activities | Customer management |
| **Products** | products, categories, inventory | Product catalog |
| **KB** | kb_entries, kb_categories | Knowledge base |
| **AI** | conversations, messages, chat_actions | AI interactions |
| **Payments** | invoices, payments, subscriptions | Financial data |
| **Marketing** | campaigns, emails, sequences | Marketing automation |

---

## Key Relationships

### The company_id Pattern

Every table (except `companies`) includes `company_id` for multi-tenant isolation:

```sql
-- Standard pattern for all tables
CREATE TABLE table_name (
    id SERIAL PRIMARY KEY,
    company_id INTEGER NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
    -- other columns...

    INDEX idx_table_company (company_id)
);
```

---

## Coming Soon

- [ ] Full ER diagram with all 320+ models
- [ ] Relationship cardinality details
- [ ] Index documentation
- [ ] Migration history

---

## See Also

- [01-MULTI-TENANT-DESIGN.md](../11-Platform-Architecture/01-MULTI-TENANT-DESIGN.md) - Data isolation
- [security-overview.md](../14-Security/security-overview.md) - Database security
- [deployment.md](../06-Operations/deployment.md) - Database migrations
- [database-migrations.md](./database-migrations.md) - Migration procedures


--- FILE: 02-Backend/FILE-UPLOADS.md ---

---
topic: backend
keywords: [backend, architecture, avatar, cache, companies, company, considerations, database, deployment]
code_paths:
  - solid-backend/controllers/companies_api.py
  - solid-backend/middleware/response_cache.py
  - solid-backend/models/company.py
  - solid-backend/models/user.py
  - solid-backend/services/assets_service.py
  - solid-backend/services/email_service.py
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# File Uploads System

> Documentation for the file upload system including company logos and user avatars.

> **Last Updated:** December 24, 2025

---

## Overview

The Solid platform supports file uploads for:
- **Company Logos** - Used on invoices and email communications
- **User Avatars** - Profile pictures for users

Files are stored locally during development and can use S3/CDN in production when configured.

---

## Architecture

### Storage System

The upload system uses the `AssetsService` (`services/assets_service.py`) which provides:
- Upload intent creation (returns pre-signed URLs for S3 when configured)
- Asset finalization and tracking
- Local filesystem fallback when S3 is not configured

### File Locations

| Type | Local Path | URL Pattern |
|------|------------|-------------|
| Company Logos | `/uploads/logos/` | `/api/v1/uploads/logos/{filename}` |
| User Avatars | `/uploads/avatars/` | `/api/v1/uploads/avatars/{filename}` |

### Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `S3_BUCKET` | S3 bucket for file storage | (empty - uses local) |
| `CDN_BASE_URL` | CDN URL for serving files | (empty) |
| `STORAGE_BASE_URL` | Base URL for local storage | `http://api.solidnumber.local:8090/assets` |

---

## API Endpoints

### Company Logo

| Method | Path | Description |
|--------|------|-------------|
| POST | `/api/v1/companies/{company_id}/logo` | Upload company logo |
| GET | `/api/v1/companies/{company_id}/logo-info` | Get logo URL and settings |
| PATCH | `/api/v1/companies/{company_id}/logo-settings` | Update logo display settings |
| GET | `/api/v1/uploads/logos/{filename}` | Serve logo file |

#### Upload Logo

```bash
curl -X POST "https://api.solidnumber.com/api/v1/companies/{id}/logo" \
  -H "Authorization: Bearer {token}" \
  -F "file=@logo.png"
```

**Constraints:**
- Allowed formats: PNG, SVG, JPG, WebP
- Max file size: 2MB
- Recommended dimensions: 300×100px

#### Logo Display Settings

```bash
curl -X PATCH "https://api.solidnumber.com/api/v1/companies/{id}/logo-settings" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "show_on_invoice": true,
    "show_in_email": true
  }'
```

### User Avatar

| Method | Path | Description |
|--------|------|-------------|
| POST | `/api/v1/uploads/avatar` | Upload user avatar |
| GET | `/api/v1/uploads/avatars/{filename}` | Serve avatar file |

#### Upload Avatar

```bash
curl -X POST "https://api.solidnumber.com/api/v1/uploads/avatar" \
  -H "Authorization: Bearer {token}" \
  -F "file=@avatar.png"
```

**Constraints:**
- Allowed formats: PNG, JPG, WebP
- Max file size: 5MB

---

## Database Schema

### Companies Table

| Column | Type | Description |
|--------|------|-------------|
| `logo_url` | VARCHAR(500) | URL to company logo |
| `logo_show_on_invoice` | BOOLEAN | Display logo on invoices (default: true) |
| `logo_show_in_email` | BOOLEAN | Display logo in emails (default: true) |

### Users Table

| Column | Type | Description |
|--------|------|-------------|
| `avatar_url` | VARCHAR(500) | URL to user avatar |

---

## Middleware Integration

### Response Cache

The `ResponseCacheMiddleware` excludes `/api/v1/uploads/` from caching to prevent issues with binary file responses.

```python
# middleware/response_cache.py
CACHE_EXCLUDE = [
    "/api/v1/auth/",
    "/api/v1/uploads/",  # Static files - served directly
    # ...
]
```

---

## Email Integration

When sending emails, the logo is included based on the `logo_show_in_email` setting:

```python
# services/email_service.py
def _get_company_logo_html(self, company_id):
    company = db.query(Company).filter(Company.id == company_id).first()
    if not company or not getattr(company, 'logo_show_in_email', True):
        return ""
    return f'<img src="{company.logo_url}" alt="Company Logo" />'
```

---

## Invoice Integration

The invoice PDF generator checks `logo_show_on_invoice` before including the logo:

```python
# When generating invoice PDF
if company.logo_show_on_invoice and company.logo_url:
    # Include logo in invoice header
```

---

## Security Considerations

1. **Path Traversal Prevention**: Filenames are normalized and checked to prevent directory traversal attacks
2. **File Type Validation**: MIME types are validated before accepting uploads
3. **Size Limits**: Files are checked against maximum size limits
4. **Authenticated Uploads**: All upload endpoints require authentication

---

## Production Deployment

When S3 is configured:
1. Files are uploaded directly to S3 using pre-signed URLs
2. Files are served via CDN for optimal performance
3. Local storage is not used

When S3 is not configured (development):
1. Files are stored in the local `/uploads/` directory
2. Files are served via FastAPI `FileResponse`
3. The uploads directory is bind-mounted in Docker

---

## Related Files

- `controllers/companies_api.py` - Logo upload endpoints
- `services/assets_service.py` - Asset management service
- `middleware/response_cache.py` - Cache exclusions
- `services/email_service.py` - Email logo integration
- `models/company.py` - Logo fields
- `models/user.py` - Avatar field


--- FILE: 02-Backend/INTERNAL-ENDPOINTS.md ---

---
topic: internal-endpoints
keywords: [caddy, forward-auth, tls, subdomain, tenant-resolution, wildcard, internal]
code_paths:
  - solid-backend/controllers/internal.py
  - solid-backend/middleware/domain_resolver.py
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# Internal Infrastructure Endpoints

**File:** `controllers/internal.py` (183 lines as of 2026-08-29, up from 87 at last check — grown but endpoints/logic below still match)
**Router prefix:** `/api/v1` (mounted at `app.py:1310` as of 2026-08-29, not `:987` — line numbers shift as `app.py` grows, re-grep `include_router(internal_router` before citing a line number)
**Called by:** Caddy reverse proxy — NOT by users or frontend code

---

## Overview

Two endpoints support Caddy's wildcard subdomain routing for `*.solidnumber.com`:

| Endpoint | Caller | Purpose |
|----------|--------|---------|
| `GET /api/v1/_internal/resolve-tenant` | Caddy `forward_auth` | Resolve hostname → tenant headers |
| `GET /api/v1/_internal/tls-check?domain=` | Caddy on-demand TLS | Verify tenant exists before issuing cert |

These endpoints are **internal only** — Caddy calls them on every request to a `*.solidnumber.com` subdomain. They are not exposed to the internet.

**Note:** The route decorator in `controllers/internal.py` uses `/_internal/...` but the router is mounted with prefix `/api/v1` in `app.py`, making the actual paths `/api/v1/_internal/...`.

---

## `GET /api/v1/_internal/resolve-tenant`

Called by Caddy's `forward_auth` directive on every wildcard subdomain request.

### Flow

```
Browser → https://bobs-plumbing.solidnumber.com/shop
    ↓
Caddy receives request (*.solidnumber.com match)
    ↓
Caddy sends forward_auth to backend:
    GET /api/v1/_internal/resolve-tenant
    X-Forwarded-Host: bobs-plumbing.solidnumber.com
    ↓
Backend resolves tenant:
    resolve_tenant_from_host(db, "bobs-plumbing.solidnumber.com")
    ↓
    Checks SubdomainMapping → finds company_id=42
    ↓
Returns 200 with headers:
    X-Tenant-ID: 42
    X-Tenant-Slug: bobs-plumbing
    X-Tenant-Domain-Type: website
    X-Tenant-Name: Bob's Plumbing
    X-Tenant-Is-Custom: false
    X-Tenant-Domain: bobs-plumbing.solidnumber.com
    X-Tenant-Site-ID: 7  (if applicable)
    ↓
Caddy copies headers into upstream request → public:3001
```

### Request

| Header | Source | Example |
|--------|--------|---------|
| `X-Forwarded-Host` | Caddy | `bobs-plumbing.solidnumber.com` |
| `Host` | Fallback | `bobs-plumbing.solidnumber.com` |

Priority: `X-Forwarded-Host` checked first, then `Host`.

### Response — Success (200)

```
X-Tenant-ID: 42
X-Tenant-Slug: bobs-plumbing
X-Tenant-Domain-Type: website             ('website' | 'landing' | 'survey' | 'shop')
X-Tenant-Name: Bob's Plumbing
X-Tenant-Is-Custom: true|false            (custom domain vs platform subdomain)
X-Tenant-Domain: bobs-plumbing.solidnumber.com   (resolved host)
X-Tenant-Site-ID: 7                       (optional — only if site resolved)
X-Tenant-Canonical-Host: bobsplumbing.com (optional — site canonical address)
```

> Contract guard: `solid-backend/tests/unit/test_internal_resolve_tenant.py`
> asserts these headers are emitted AND whitelisted in both Caddyfile
> `copy_headers` directives. `solid-public/src/lib/tenant.ts` is the consumer.

Caddy copies these headers into the upstream request to `solid-public:3001`.

### Response — Failure (403)

```json
{
    "error": "Unknown tenant",
    "host": "nonexistent.solidnumber.com"
}
```

Caddy blocks the request. User sees a 403 error.

### Resolution Logic

Delegates to `middleware/domain_resolver.py:resolve_tenant_from_host(db, host)`:

1. **Custom domain** — `CustomDomain` table (verified + active)
2. **Subdomain** — `SubdomainMapping` table (active)
3. **Legacy slug** — `Company.slug` direct match
4. Returns `None` if no match → 403

---

## `GET /api/v1/_internal/tls-check`

Called by Caddy's on-demand TLS before provisioning a Let's Encrypt certificate.

### Flow

```
Browser → https://new-company.solidnumber.com
    ↓
Caddy: "I don't have a cert for this domain"
    ↓
Caddy on-demand TLS check:
    GET /api/v1/_internal/tls-check?domain=new-company.solidnumber.com
    ↓
Backend checks: does this domain have a tenant?
    ↓
    200 → Caddy provisions cert from Let's Encrypt
    404 → Caddy rejects, no cert issued
```

### Request

| Parameter | Type | Example |
|-----------|------|---------|
| `domain` | query string | `bobs-plumbing.solidnumber.com` |

### Response — Allow (200)

Empty 200 response. Caddy proceeds to provision the certificate.

### Response — Reject (404)

```json
{
    "error": "No tenant for this domain"
}
```

Caddy does NOT provision a certificate. This prevents attackers from flooding Let's Encrypt with requests for random subdomains.

### Security Purpose

Without this check, anyone could hit `https://anything.solidnumber.com` and Caddy would request a cert from Let's Encrypt. This could:
- Exhaust Let's Encrypt rate limits (50 certs/domain/week)
- Create orphaned certs for non-existent tenants
- Be used as a DoS vector

The TLS check ensures certs are only issued for subdomains that map to real tenants.

---

## Caddy Configuration

The relevant Caddy config (from `Caddyfile`):

```
# Global options block
{
    on_demand_tls {
        ask http://backend:8090/api/v1/_internal/tls-check
    }
}

# Wildcard tenant routing
*.solidnumber.com {
    tls {
        on_demand
    }

    forward_auth backend:8090 {
        uri /api/v1/_internal/resolve-tenant
        copy_headers X-Tenant-ID X-Tenant-Slug X-Tenant-Domain-Type X-Tenant-Site-ID X-Tenant-Name X-Tenant-Canonical-Host X-Tenant-Is-Custom X-Tenant-Domain
    }

    reverse_proxy public:3001
}
```

---

## Dependencies

```python
from middleware.domain_resolver import resolve_tenant_from_host
from infra.db import get_db
```

The `resolve_tenant_from_host` function is shared with the main middleware stack. Same resolution logic used for both internal Caddy calls and direct API requests.

---

## Related Docs

- [../06-Operations/DOCKER-ARCHITECTURE.md](../06-Operations/DOCKER-ARCHITECTURE.md) — Caddy service config, wildcard routing
- [../19-Onboarding/16-SIGNUP-DEFAULTS-AND-OVERRIDES.md](../19-Onboarding/16-SIGNUP-DEFAULTS-AND-OVERRIDES.md) — How subdomains are created during provisioning
- [MIDDLEWARE-ARCHITECTURE.md](./MIDDLEWARE-ARCHITECTURE.md) — Domain resolver middleware details


--- FILE: 02-Backend/LLM-PROVIDER-SYSTEM.md ---

---
topic: backend
keywords: [backend, agent, agent-specific, anthropic, architecture, auto-converted, available, base, best]
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# LLM Provider System

> Multi-provider LLM abstraction layer supporting Claude, GPT, and Grok.

**Last Updated:** January 3, 2026

---

## Overview

The LLM provider system provides a unified interface for multiple AI providers, enabling seamless switching between Claude (Anthropic), GPT (OpenAI), and Grok (xAI) with consistent request/response formats.

### Key Statistics

| Metric | Value |
|--------|-------|
| **Providers Supported** | 3 (Anthropic, OpenAI, xAI) |
| **Models Available** | 10+ |
| **Vision Support** | Yes (all providers) |
| **Tool Calling** | Yes (MCP-compatible) |

---

## Architecture

```
agents/llm/
├── base.py                    # Abstract base classes (295 lines, verified 2026-08-29)
├── anthropic_provider.py      # Claude support (301 lines, verified 2026-08-29)
├── openai_provider.py         # GPT support (310 lines, verified 2026-08-29)
├── xai_provider.py            # Grok support (226 lines, verified 2026-08-29)
└── factory.py                 # Provider instantiation (116 lines, verified 2026-08-29)
```

---

## Base Interface

All providers implement a unified interface:

```python
class LLMProvider(ABC):
    @abstractmethod
    async def generate(
        self,
        messages: List[Dict[str, str]],    # [{"role": "user", "content": "..."}]
        system_prompt: str,                 # Separate from messages
        tools: Optional[List[Dict]] = None, # MCP tools
        **kwargs
    ) -> Dict[str, Any]:
        pass

    @abstractmethod
    def get_cost_estimate(
        self,
        input_tokens: int,
        output_tokens: int
    ) -> float:
        pass
```

### Unified Response Format

```python
{
    "content": "Text response",
    "tool_calls": [...] or None,
    "usage": {
        "input_tokens": int,
        "output_tokens": int,
        "total_tokens": int
    },
    "finish_reason": "stop" | "tool_use" | "length",
    "model": "actual-model-used",
    "id": "provider-message-id"
}
```

---

## Provider Implementations

### 1. Anthropic (Claude)

**File:** `anthropic_provider.py`

**Supported Models:**
- Claude Sonnet 4.6 (`claude-sonnet-4-6`) — default in `anthropic_provider.py`, verified 2026-08-29
- Claude Opus 4.6 (`claude-opus-4-6`)
- Claude Haiku 4.5 — the pricing dict keys this as `claude-haiku-4-5-20251001` (dated), not the bare `claude-haiku-4-5` shown before; also carries legacy pricing aliases for `claude-sonnet-4-5-20250929`, `claude-3-5-sonnet-20241022`, `claude-3-opus-20240229`, `claude-3-sonnet-20240229`, `claude-3-haiku-20240307`, `claude-3-5-haiku-20241022`

**Features:**
- Native MCP tool format (no conversion needed)
- Vision via base64 image encoding
- Separate system_prompt parameter

**Pricing:**
| Model | Input | Output |
|-------|-------|--------|
| Claude Sonnet 4.6 | $3/MTok | $15/MTok |
| Claude Opus 4.6 | $15/MTok | $75/MTok |
| Claude Haiku 4.5 | $0.25/MTok | $1.25/MTok |

```python
# Usage — corrected 2026-08-29: __init__ takes a single `config: Dict`, not an api_key kwarg
provider = AnthropicProvider({"api_key": "...", "model_id": "claude-sonnet-4-6"})
response = await provider.generate(
    messages=[{"role": "user", "content": "Hello"}],
    system_prompt="You are a helpful assistant"
)
```

### 2. OpenAI (GPT)

**File:** `openai_provider.py`

**Supported Models:**
- GPT-4o (`gpt-4o`) — default in `openai_provider.py`
- GPT-4o-mini (`gpt-4o-mini`)
- GPT-4 (`gpt-4`) / GPT-4-turbo / GPT-4-32k
- GPT-3.5-turbo (`gpt-3.5-turbo`)

**Features:**
- Function calling with automatic MCP conversion
- Vision with detail levels (low/high/auto)
- System message embedded in messages array

**Key Differences from Claude:**
- Tools use `"type": "function"` wrapper
- Tool names converted: `.` → `_`
- Async client (AsyncOpenAI)

**Pricing** (verified against `agents/llm/openai_provider.py` pricing dict, 2026-08-29 — the previous table's numbers were wrong, including a duplicate/contradictory GPT-4o-mini row):
| Model | Input | Output |
|-------|-------|--------|
| GPT-4o | $5.00/MTok | $15.00/MTok |
| GPT-4o-mini | $0.15/MTok | $0.60/MTok |
| GPT-4 | $30/MTok | $60/MTok |
| GPT-4-turbo / GPT-4-turbo-preview | $10/MTok | $30/MTok |
| GPT-4-32k | $60/MTok | $120/MTok |
| GPT-3.5-turbo | $0.50/MTok | $1.50/MTok |

### 3. xAI (Grok)

**File:** `xai_provider.py`

**Supported Models:**
- Grok-2 (`grok-2`)
- Grok-2-mini (`grok-2-mini`)
- Grok-beta (`grok-beta`)

**Features:**
- Real-time X/Twitter knowledge
- OpenAI-compatible API (custom base_url)
- Function calling support

**Pricing:**
| Model | Input | Output |
|-------|-------|--------|
| Grok-2 | $2/MTok | $10/MTok |
| Grok-2-mini | $0.20/MTok | $1/MTok |

---

## Tool Format Conversion

### MCP Format (Native to Claude)
```python
{
    "name": "tool_name",
    "description": "What it does",
    "input_schema": {
        "type": "object",
        "properties": {...},
        "required": [...]
    }
}
```

### OpenAI Format (Auto-converted)
```python
{
    "type": "function",
    "function": {
        "name": "tool_name",  # . → _ conversion
        "description": "What it does",
        "parameters": {
            "type": "object",
            "properties": {...},
            "required": [...]
        }
    }
}
```

---

## Factory Pattern

```python
from agents.llm.factory import get_llm_provider

# Corrected 2026-08-29: get_llm_provider(provider_name, config: Dict) — the
# second arg is a config dict, not an api_key kwarg.
provider = get_llm_provider("anthropic", {"api_key": "...", "model_id": "claude-sonnet-4-6"})
provider = get_llm_provider("openai", {"api_key": "..."})
provider = get_llm_provider("xai", {"api_key": "..."})

# List available providers
providers = list_available_providers()
# Returns: ["anthropic", "openai", "xai"]

# Get provider info
info = get_provider_info("anthropic")
# Returns: {"name", "class", "supports_vision", "supports_tools"}
```

---

## Provider Selection Logic

⚠️ **Corrected 2026-08-29** against `agents/conversation.py` (`ConversationManager._resolve_provider`-equivalent
logic around line 464). Tier 2 was wrong — `company.preferred_llm_provider`
does not exist anywhere in the codebase. Real tiering:

```python
# TIER 1: Agent-specific custom BYO provider (models.LLMProvider row)
if agent.llm_provider_id:
    # Scoped by BOTH id AND agent.company_id — a mis-set or stale
    # llm_provider_id must not read another tenant's decrypted API key.
    llm_provider_config = db.query(LLMProvider).filter(
        LLMProvider.id == agent.llm_provider_id,
        LLMProvider.company_id == agent.company_id,
    ).first()
    llm = get_llm_provider(llm_provider_config.provider_name, {
        **llm_provider_config.get_config(),
        **(agent.llm_config or {}),
    })

# TIER 2: SmartRouter picks the model, OR an upstream IntelligencePipeline
# has already pre-routed (context["_pipeline_routing"]) — NOT a
# "company.preferred_llm_provider" field, which does not exist.
else:
    if pipeline_routing:
        provider, model = pipeline_routing["provider"], pipeline_routing["model_id"]
    else:
        from services.ai.smart_router import SmartRouter
        provider, model = SmartRouter(db_session=db).pick(...)
```

See `Owners-Manual/03-AI-Systems/AI-INFRASTRUCTURE.md` for SmartRouter details
(not verified as part of this pass).

---

## Vision Support

All providers support image analysis:

```python
# Anthropic
response = await provider.analyze_image(
    image_data,      # Base64 or URL
    prompt="Describe this image",
    media_type="image/png"
)

# OpenAI (with detail level)
response = await provider.analyze_image(
    image_data,
    prompt="Describe this image",
    detail="high"  # low, high, auto
)
```

---

## Cost Tracking

```python
# Get cost estimate
cost = provider.get_cost_estimate(
    input_tokens=1000,
    output_tokens=500
)
# Returns: float (in dollars)

# Included in response
response = await provider.generate(...)
usage = response["usage"]
# {
#     "input_tokens": 1000,
#     "output_tokens": 500,
#     "total_tokens": 1500
# }
```

---

## Error Handling

⚠️ **`LLMProviderError` does not exist in `agents/llm/base.py`** (verified
2026-08-29 — no such class is defined there). The import below would fail;
left as a reminder to wrap provider calls in a broad `except Exception`
until/unless a dedicated error type is added.

```python
try:
    response = await provider.generate(messages, system_prompt)
except Exception as e:
    logger.error(f"LLM error: {e}")
    # Fallback logic
```

---

## Configuration

```python
# Environment variables
ANTHROPIC_API_KEY="sk-ant-..."
OPENAI_API_KEY="sk-..."
XAI_API_KEY="xai-..."

# Default model per provider
DEFAULT_ANTHROPIC_MODEL="claude-sonnet-4-6"
DEFAULT_OPENAI_MODEL="gpt-4o"
DEFAULT_XAI_MODEL="grok-2"
```

---

## Integration with Agent System

```python
# In conversation.py
class ConversationManager:
    async def get_response(self, agent, message):
        # Resolve provider
        provider = self._resolve_provider(agent)

        # Build system prompt with memory
        system_prompt = self.memory_engine.build_enhanced_prompt(
            agent.system_prompt,
            company_id=agent.company_id,
            agent_type=agent.type
        )

        # Get tools for agent
        tools = self.tool_engine.get_tools_for_agent(
            agent.type,
            format=provider.tool_format
        )

        # Generate response
        return await provider.generate(
            messages=self.conversation_history,
            system_prompt=system_prompt,
            tools=tools
        )
```

---

## Best Practices

1. **Use factory pattern** for provider instantiation
2. **Handle rate limits** with exponential backoff
3. **Track costs** per company_id for billing
4. **Cache responses** where appropriate
5. **Log all API calls** for debugging
6. **Set reasonable timeouts** (30s default)
7. **Use streaming** for long responses

---

## Related Documentation

- [Agent Registry](../03-AI-Systems/AGENT-REGISTRY.md) - All 32 AI agents
- [AI Infrastructure](../03-AI-Systems/AI-INFRASTRUCTURE.md) - CognitiveLimiter, SmartRouter
- [MCP Integration](../03-AI-Systems/MCP-INTEGRATION.md) - 655 tools

---

*One interface. Three providers. Seamless switching.*


--- FILE: 02-Backend/MIDDLEWARE-ARCHITECTURE.md ---

---
topic: backend
keywords: [backend, architecture, auth, authentication, company, context, files, flow, middleware]
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# Middleware Architecture

> `middleware/` holds 38 files (2026-08-29, excluding `__init__.py`); ~21 are
> wired into the global Starlette chain via `app.add_middleware(...)` in
> `app.py`. Others (`auth.py`, `company.py`, `mcp_auth.py`,
> `mcp_tenant_scope.py`, `customer_portal_auth.py`, `feature_guard.py`,
> `rate_limiter.py`) are used as **FastAPI `Depends()` dependencies on
> individual routers**, not global middleware — they don't run on every
> request, only on routes that declare them.

---

## Request Flow

Real registration order in `app.py` (`~line 693` onward). Starlette runs
middleware added **last** first on the way in, so `CORSMiddleware` — added
last in this list — is the outermost layer and sees every request (and every
response, including 403s from CSRF/FeatureGate) first/last:

```
Request →
  RLSContextMiddleware (rls_context.py — sets company_id ContextVar for DB-level tenant isolation)
  → DomainTenantMiddleware (domain_resolver.py — resolves tenant from subdomain)
  → error_logging_middleware (error_logging.py)
  → CrawlerTrackerMiddleware (crawler_tracker.py)
  → PerformanceTracingMiddleware (performance_tracing.py)
  → PerformanceMonitoringMiddleware (performance_monitoring.py)
  → ResponseCacheMiddleware (response_cache.py)
  → check_activity_timeout (activity_timeout.py)
  → SecurityHeadersMiddleware (security.py)
  → HTTPSRedirectMiddleware (security.py)
  → CSRFProtectionMiddleware (csrf.py)
  → ApiKeyAuditMiddleware (api_key_audit.py)
  → McpTelemetryMiddleware (mcp_telemetry.py)
  → ApiKeyApprovalGuardMiddleware (api_key_approval_guard.py)
  → FeatureGateMiddleware (feature_gate_middleware.py)
  → AgentModeEnforcerMiddleware (agent_mode_enforcer.py)
  → DraftGateMiddleware (draft_gate.py)
  → AgentGrantEnforcerMiddleware (agent_grant_enforcer.py)
  → DryRunMiddleware (dry_run.py)
  → AuditSourceMiddleware (audit_source.py)
  → MCPRateLimitMiddleware (mcp_rate_limit.py — the one globally-registered rate limiter)
  → CORSMiddleware (added last = outermost)
→ Controller
```

`CustomModulesMiddleware` (`custom_modules.py`) is added even later in
`app.py` (~line 2572, after route registration), which makes it the true
outermost wrapper — even outside CORS. `TrustedHostMiddleware` is added
conditionally, production-only, at the very start of the chain.

The old flow diagram (`auth → company → domain_resolver → rate_limiter →
cors_config → feature_guard`) does not describe the real chain: `auth.py`
and `company.py` are per-route dependencies, not global middleware, and
`rate_limiter.py` (slowapi, per-route `@limiter.limit(...)` decorators) is a
separate mechanism from the globally-registered `MCPRateLimitMiddleware`.

---

## Middleware Files (selected — not exhaustive; 38 files total in the directory)

| File | Wired how | Purpose |
|------|-----------|---------|
| `auth.py` | `Depends()` per-route | JWT authentication, token validation |
| `company.py` | `Depends()` per-route | Injects company_id into request context |
| `rls_context.py` | Global (`RLSContextMiddleware`) | ContextVar company_id for DB-level RLS |
| `domain_resolver.py` | Global (`DomainTenantMiddleware`) | Resolves tenant from subdomain |
| `rate_limiter.py` | Per-route decorator (slowapi) | Request throttling per user/IP |
| `mcp_rate_limit.py` | Global (`MCPRateLimitMiddleware`) | Fixed-window limiter for CLI/agent API keys |
| `cors_config.py` | Global (`CORSMiddleware`, added last/outermost) | Cross-origin resource sharing |
| `csrf.py` | Global (`CSRFProtectionMiddleware`) | CSRF token validation |
| `feature_guard.py` | `Depends()`/decorator per-route | Feature flag enforcement (legacy — see `feature_gate_middleware.py`) |
| `feature_gate_middleware.py` | Global (`FeatureGateMiddleware`) | Route-prefix → feature-key tier gating |
| `mcp_auth.py` | `Depends()` per-route | MCP server authentication |
| `mcp_tenant_scope.py` | Used in `mcp_http/security.py`, `mcp_http/resources.py`, `controllers/mcp_health.py`, `controllers/api.py` | MCP tenant isolation |
| `customer_portal_auth.py` | `Depends()` per-route | Customer portal OTP auth |
| `response_cache.py` | Global (`ResponseCacheMiddleware`) | Response caching layer |
| `security.py` | Global (`SecurityHeadersMiddleware`, `HTTPSRedirectMiddleware`) | Security headers, HTTPS redirect |
| `performance_tracing.py` | Global (`PerformanceTracingMiddleware`) | Request timing metrics |
| `performance_monitoring.py` | Global (`PerformanceMonitoringMiddleware`) | Performance tracking |
| `activity_timeout.py` | Global (`app.middleware("http")(check_activity_timeout)`) | Session timeout handling |
| `error_logging.py` | Global (`app.middleware("http")(error_logging_middleware)`) | Error capture and logging |
| `draft_gate.py`, `dry_run.py`, `audit_source.py`, `agent_mode_enforcer.py`, `agent_grant_enforcer.py`, `api_key_audit.py`, `api_key_approval_guard.py`, `mcp_telemetry.py`, `crawler_tracker.py`, `custom_modules.py` | Global (`app.add_middleware`) | Not in the original doc — added since; see Request Flow above |

⚠️ **`auth_temp.py` does not exist in `middleware/` as of 2026-08-29** — the
"Security Notes" claim below about it raising `RuntimeError` in production
could not be verified against any current file and has been removed.

⚠️ **`maintenance_mode.py` (`MaintenanceModeMiddleware`) and
`request_logger.py` (`RequestLoggingMiddleware`) are defined but were NOT
found registered anywhere** (no `app.add_middleware(MaintenanceModeMiddleware`
or `app.add_middleware(RequestLoggingMiddleware` in the codebase, and
`request_logger.py`'s own `setup_request_logging(app)` helper is not called
from `app.py`). They exist as importable classes and are covered by
`api/routers/maintenance.py` / `tests/unit/test_request_logger_agent_activity.py`
respectively, but do not currently "intercept every request" as this doc
previously implied. Reported for awareness — not fixed, since this is a doc
audit, not a code change.

---

## Key Patterns

### Authentication (`auth.py`)
```python
from middleware.auth import get_current_user

@router.get("/endpoint")
async def endpoint(user: User = Depends(get_current_user)):
    # user is authenticated
```

### Company Context (`company.py`)
```python
from middleware.company import get_user_company

@router.get("/endpoint")
async def endpoint(company: Company = Depends(get_user_company)):
    # company_id available for tenant isolation
```

### Optional Auth
```python
from middleware.auth import get_current_user_optional

@router.get("/public")
async def endpoint(user: Optional[User] = Depends(get_current_user_optional)):
    # user may be None
```

---

## Security Notes

- JWT secret validated at startup (no weak defaults allowed)
- Per-route rate limiting (`rate_limiter.py`) uses slowapi with Redis for distributed tracking; `mcp_rate_limit.py` is the separate globally-registered limiter for CLI/agent API keys
- CORS configured per environment, and `CORSMiddleware` is deliberately the last-added (= outermost) middleware so CORS headers appear even on 403s from CSRF/FeatureGate


--- FILE: 02-Backend/SERVICE-LAYER-ARCHITECTURE.md ---

---
topic: backend
keywords: [backend, abstract, accounting, always, analytics, architecture, async, authentication, base]
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# Service Layer Architecture

> Complete guide to the 336 service files powering the Solid# platform.

**Last Updated:** February 3, 2026

---

## Overview

The service layer is the heart of business logic in Solid#, sitting between controllers and the database. It implements a clean separation of concerns with dependency injection, multi-tenancy isolation, and provider abstraction patterns.

### Key Statistics

| Metric | Count |
|--------|-------|
| **Total Service Files** | 336 |
| **Service Classes** | 76+ |
| **Async Methods** | 408+ |
| **Service Packages** | 24 |
| **Root Services** | 167 |
| **Major Domains** | 15 |

---

## Directory Structure

```
services/
├── Root Level (167 modules)     # Core singleton services
├── /payments/      (14 modules) # Payment processor adapters
├── /accounting/    (10 modules) # QuickBooks, Xero, FreshBooks
├── /platform/      (26 modules) # Google/Microsoft workspace
├── /ai/            (14 modules) # AI agent framework
├── /vibe/          (11 modules) # Workflow automation
├── /knowledge_base/ (6 modules) # KB layer abstraction
├── /video/          (6 modules) # Video processing
├── /ecommerce/      (6 modules) # Cart, orders, shipping
├── /marketing/      (8 modules) # Campaigns, analytics
├── /reports/        (5 modules) # Report generation
└── ... (14 more subdirectories)
```

---

## Core Patterns

### 1. Dependency Injection

**Constructor Injection (Most Common):**
```python
class BillingService:
    def __init__(self, db: Session):
        self.db = db

# Usage in routes
def get_billing(db: Session = Depends(get_db)):
    return BillingService(db)
```

### 2. Multi-Tenancy (Sacred Rule)

**ALWAYS filter by company_id:**
```python
# CORRECT - Always filter by company_id
def get_invoices(self, company_id: int) -> List[Invoice]:
    return self.db.query(Invoice)\
        .filter(Invoice.company_id == company_id)\
        .all()

# WRONG - Never do this
def get_invoices(self) -> List[Invoice]:
    return self.db.query(Invoice).all()  # DATA LEAK!
```

### 3. Abstract Base Class Pattern

Used for multi-provider scenarios (payments, accounting, platform):

```python
# accounting/base.py
class AccountingProvider(ABC):
    def __init__(self, connection: AccountingConnection):
        self.connection = connection

    @abstractmethod
    async def create_customer(self, customer: Customer) -> str: ...

    @abstractmethod
    async def sync_invoices(self) -> List[Invoice]: ...

# Implementations
class QuickBooksProvider(AccountingProvider):
    async def create_customer(self, customer: Customer) -> str:
        # QB-specific implementation
        pass
```

### 4. Registry/Factory Pattern

```python
# payments/registry.py
class PaymentRegistry:
    _registry: Dict[str, Type] = {}

    @classmethod
    def register(cls, name: str, adapter_class: Type):
        cls._registry[name] = adapter_class

    @classmethod
    def get(cls, name: str) -> Any:
        return cls._registry.get(name)
```

### 5. Async Patterns

```python
# Pattern 1: Pure async
async def send_email(self, to: str, subject: str) -> bool:
    return await self._send_via_provider(to, subject)

# Pattern 2: Fire-and-forget
asyncio.create_task(send_notification(user_id))

# Pattern 3: Gather parallel operations
results = await asyncio.gather(
    fetch_from_api1(),
    fetch_from_api2(),
)
```

---

## Service Categories

### 1. Authentication & Security (6 services)
| Service | Purpose |
|---------|---------|
| `auth.py` | Core auth (login, register, password reset) |
| `agent_auth_service.py` | AI agent authentication |
| `session_manager.py` | Production SSO |
| `two_factor_service.py` | 2FA implementation |
| `encryption_service.py` | Data encryption/decryption |

### 2. Billing & Payments (17+ services)
| Service | Purpose |
|---------|---------|
| `payments/solid_payments_service.py` | the retired processor — DEAD, zero live call sites, decommissioned; legacy code only |
| `payments/stripe.py` | Stripe adapter — live, this is what Solid#'s own platform billing actually charges through |
| `payments/paypal.py` | STUB — returns a fake `"paypal_tx_stub"` transaction id, has a `# TODO: integrate PayPal` comment, and has zero importers anywhere in the codebase. Not to be confused with `payments/paypal_adapter.py` (the tenant BYOP adapter in the registry, also a stub — `NotImplementedError` on every method) |
| `payments/split_engine.py` | Revenue splitting |
| `processor_service.py` (removed) | the retired processor service wrapper — DEAD, decommissioned; legacy code only |
| `cancellation_service.py` | Subscription cancellation |
| `dunning_service.py` | Failed payment recovery |
| `chargebacks_service.py` | Dispute handling |

### 3. AI & Intelligence (23+ services)
| Service | Purpose |
|---------|---------|
| `ai_agent_service.py` | Self-healing AI provisioning |
| `ai_content_generator.py` | Content generation |
| `ai_context_manager.py` | KB semantic search |
| `ai/embeddings.py` | Standalone text embedding generation |
| `ada_events.py` | ADA event emission (delegates to outbox) |
| `lead_scoring_engine.py` | ML-based lead scoring |
| `growth_bot.py` | Growth intelligence |
| `pareto_engine.py` | Pareto analysis |

### 4. E-Commerce & Orders (12+ services)
| Service | Purpose |
|---------|---------|
| `ecommerce/cart_service.py` | Shopping cart |
| `ecommerce/order_service.py` | Order processing |
| `ecommerce/abandoned_cart_service.py` | Cart recovery |
| `ecommerce/shipping_service.py` | Shipping integration |
| `inventory_ops.py` | Inventory management |

### 5. CRM & Lead Management (10+ services)
| Service | Purpose |
|---------|---------|
| `lead_engine.py` | Lead processing & scoring |
| `contact_matcher.py` | Duplicate detection |
| `crm_email_service.py` | CRM email campaigns |
| `onboarding_lead_service.py` | Lead onboarding |

### 6. Marketing & Analytics (12+ services)
| Service | Purpose |
|---------|---------|
| `marketing/email_campaign_service.py` | Campaign management |
| `marketing/drip_campaign_service.py` | Drip sequences |
| `marketing/ab_testing_service.py` | A/B testing |
| `marketing/marketing_roi_service.py` | ROI tracking |

### 7. Platform Integration (27+ services)
| Service | Purpose |
|---------|---------|
| `platform/google_provider.py` | Google Workspace |
| `platform/microsoft_provider.py` | Microsoft 365 |
| `platform/microsoft_service.py` | Microsoft Graph client factory |
| `platform/gemini_service.py` | Gemini AI |
| `platform/copilot_service.py` | Copilot integration |

### 8. Accounting Integration (10+ services)
| Service | Purpose |
|---------|---------|
| `accounting/quickbooks.py` | QuickBooks sync |
| `accounting/xero.py` | Xero integration |
| `accounting/freshbooks.py` | FreshBooks sync |
| `accounting/sync_engine.py` | Two-way sync |

### 9. Vibe Workflow Engine (11 services)
| Service | Purpose |
|---------|---------|
| `vibe/vibe_engine.py` | Core workflow engine |
| `vibe/entity_executors.py` | Execute workflow actions |
| `vibe/integration_gateway.py` | Integration coordination |
| `vibe/vibe_safety.py` | Safety/guardrails |

---

## Configuration Patterns

### Environment-Based Configuration
```python
class EmailService:
    def __init__(self):
        self.provider = os.getenv("EMAIL_PROVIDER", "smtp")
        self.api_key = os.getenv("EMAIL_API_KEY")
```

### Feature Tier Gating
```python
# feature_settings.py
TIER_FEATURES = {
    "starter": ["basic_crm", "email"],
    "builder": ["basic_crm", "email", "appointments", "crm"],
    "professional": ["basic_crm", "email", "appointments", "crm", "ai_chat"],
    "enterprise": ["*"]  # All features
}

def has_feature(company_id: int, feature: str) -> bool:
    tier = get_subscription_tier(company_id)
    return feature in TIER_FEATURES.get(tier, [])
```

---

## Error Handling

```python
# Custom exceptions pattern
class AccountingProviderError(Exception):
    pass

class SyncError(AccountingProviderError):
    pass

# Usage
try:
    await provider.sync_invoices()
except SyncError as e:
    logger.error(f"Sync failed: {e}")
    raise
```

---

## Caching Strategy

```python
# Redis with in-memory fallback
class InMemoryCache:
    def __init__(self):
        self._cache: Dict[str, Any] = {}
        self._ttl: Dict[str, float] = {}

try:
    cache = redis.Redis(...)
except:
    cache = InMemoryCache()
```

---

## Best Practices

1. **Always use Session dependency injection** for database access
2. **Check feature tier gates** before exposing functionality
3. **Implement multi-tenancy** via company_id filtering
4. **Use abstract base classes** for multi-provider scenarios
5. **Configure everything via environment variables**
6. **Follow the docstring convention** with Purpose/Example sections
7. **Implement proper error handling** in async code
8. **Use Registry/Factory patterns** for provider selection
9. **Cache intelligently** with Redis fallback
10. **Keep services focused** on single responsibility

---

## Related Documentation

- [API Endpoints](./api-endpoints.md) - All 1,342 API routes
- [Database Migrations](./database-migrations.md) - Migration procedures
- [Middleware Architecture](./middleware-architecture.md) - Request pipeline

---

*Services are the business logic layer. Controllers orchestrate, services execute.*


--- FILE: 02-Backend/STARTUP-PARALLELIZATION.md ---

---
topic: backend-startup
keywords: [startup, parallelization, asyncio, lifespan, performance]
code_paths:
  - solid-backend/app.py
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# Backend Startup Parallelization

> Backend startup uses `asyncio.gather()` for three specific batches of
> independent init tasks; everything else in the lifespan function runs
> sequentially, awaited one step at a time.

---

## Architecture (verified against `app.py::lifespan`, 2026-08-29)

The batch structure has been substantially reshuffled since the previous
verification (2026-02-05). Only **3** parallel `asyncio.gather()` batches
exist today, not 4, and their contents don't match the old list — most of
what the old doc called "Parallel Batch 1" is actually sequential.

### Sequential (the bulk of startup — awaited one at a time, in this order)
1. Sentry initialization (`init_sentry()`)
2. Config integrity check (`services.config_integrity.verify_integrity`)
3. Token revocation listener registration
4. Provider-key pool readout (shared vs. pinned-to-company log line)
5. Event bus connect + handler registration (`events.event_bus.connect()`,
   `register_kb_onboarding_handlers`, `register_communication_handlers`,
   `register_voice_outbound_handlers`) — **not** part of a gather() batch
6. Startup validator (`validate_startup_config`)
7. Secrets validation (`validate_secrets`)
8. Critical-import validation (fail-fast on missing deps)
9. Commerce/shipping/hardware/tax/W9 engine + connector registration
10. Database `Base.metadata.create_all()`
11. Default commission rules init
12. Explore-docs preload
13. Control-plane schema registry bootstrap (`schema_registry.bootstrap`)
14. Background file watchers (`watchers.start_background` — fire-and-forget
    `asyncio.create_task`, not gathered)
15. Backup scheduler (`start_backup_scheduler()`)

### Parallel Batch 1 (`asyncio.gather`, Redis-dependent services)
- Redis event bus (`infra.redis_event_bus`)
- Performance monitor (`services.performance_monitor`)
- Cache service (`services.cache_service`)
- Agent event handlers (`services.agent_event_handlers`)

### Parallel Batch 2 (`asyncio.gather`, autonomous agents — 10, not 5)
Jake, Annie, Devon, Ace, Sage, Beet, Carrot, Pepper, Turnip, Parsley
(`workers/*_monitor.py` / `*_processor.py` / `*_reporter.py` / `*_worker.py`
/ `*_followup.py` / `*_optimizer.py` / `*_automator.py`). The previous
"5 agents" list (Jake, Annie, Devon, Ace, Sage) is stale — 5 more
(Beet, Carrot, Pepper, Turnip, Parsley) have been added since.

### Parallel Batch 3 (`asyncio.gather`, misc services)
- Thumbnail service
- ML injection detector (Prompt Guard, run off-loop via executor)
- Realtime hub Redis listener

### Post-Startup (sequential, after all 3 gather batches)
- `mark_startup_complete()` — sets `_startup_complete = True`
- Environment doctor runs (diagnostic report)
- **New since the last verification, not in the old doc at all:**
  - OpenAI Realtime connection pool warm-up (`services.openai_connection_pool`)
  - Silero VAD ONNX model preload (`services.voice.core.speech_analyzer.preload_silero`)
  - Voice static-prefix prewarm for every active line (`services.voice.context.persona.prewarm_voice_prefixes`)

---

## Health Check Interaction

The `/_health/live` endpoint returns 200 immediately (process is running). The `/_health/ready` endpoint returns 503 until `_startup_complete = True`. Docker healthcheck uses `/live` so the container isn't killed during startup. Dependent services and deploy.sh use `/ready`.

---

## Why This Matters

On the 8GB production VPS, the backend loads AI agents, ML models, Redis subscriptions, and schema validation. Sequential startup took 30+ seconds, causing deploy health checks to timeout and report false failures. Parallel startup cuts this roughly in half.

---

*Created: February 5, 2026*


--- FILE: 03-AI-Systems/ADA-PERSISTENT-MEMORY.md ---

---
topic: ada-persistent-memory
keywords: [ada, memory, context, redis, agent-memory, cross-conversation, tiered, tenant-isolation]
last_verified: 2026-03-18
status: current
priority: high
owner: platform-team
code_paths:
  - solid-backend/tasks/cross_conversation_memory_tasks.py
  - solid-backend/agents/conversation.py
  - solid-backend/controllers/agents.py
  - solid-backend/celery_app.py
  - solid-backend/agents/llm/openai_provider.py
---

# ADA Persistent Memory — Cross-Conversation Intelligence

## What This Is

ADA remembers facts across conversations. After each chat, Haiku extracts key facts ($0.0004/call). Facts are cached in Redis (<1ms read) and backed up in PostgreSQL. On the next conversation, facts are injected into ADA's system prompt. She picks up where she left off.

**No new tables. No migrations.** Reuses existing `agent_long_term_memory` table with `memory_type="cross_conversation"`.

## Phase 1 Status: SHIPPED (2026-03-18)

| Component | Status | File |
|-----------|--------|------|
| Celery extraction task | DONE | `tasks/cross_conversation_memory_tasks.py` |
| Redis + PostgreSQL write | DONE | Same file, `_persist_facts()` |
| System prompt injection | DONE | `agents/conversation.py:434` (Layer 0.5) |
| Fire task after chat | DONE | `controllers/agents.py` (both routes) |
| Celery registration | DONE | `celery_app.py:253` |
| GPT-5 max_tokens fix | DONE | `agents/llm/openai_provider.py:68` |

## Phase 2 Status: SHIPPED (2026-03-18)

| Component | Status | File |
|-----------|--------|------|
| Tier-aware memory caps | DONE | `constants/feature_tiers.py` (`memory_cap` in `TIER_AI_BUDGETS`) |
| Token cost tracking | DONE | `tasks/cross_conversation_memory_tasks.py` → `token_gate.record_sync()` |
| Pin support ("always remember") | DONE | Haiku detects pin intent → `decay_rate=0.0`, `confidence=1.0` |
| Cross-agent shared memory | DONE | Shared key `xmem:{company_id}:shared`, all agents read |
| Topic-match boosting | DONE | Memories matching user's message keywords injected first |
| Open items follow-up | DONE | `open_items` topic → injected with "proactively follow up" instruction |
| Conversation FK fix | DONE | `controllers/agents.py` — commit before pipeline to prevent FK violation |

Memory caps scale by subscription tier. The cost per extraction is $0.0004 — negligible. Caps exist for **prompt quality** and **value differentiation**, not cost protection.

| Tier | Price | Memory Cap | Prompt Tokens | Rationale |
|------|-------|-----------|---------------|-----------|
| **Starter** | $89/mo | 20 entries | ~200 tokens | Goals, blockers, basics |
| **Builder** | $199/mo | 50 entries | ~500 tokens | + team, preferences, patterns |
| **Professional** | $499/mo | 100 entries | ~1,000 tokens | Deep institutional memory |
| **Enterprise** | $1,499/mo | 200 entries | ~2,000 tokens | Full organizational knowledge |

### Cost Math (Why Caps Aren't About Money)

```
Extraction cost:     $0.0004 per conversation (Haiku)
30 conversations/mo: $0.012 per company per month
1,000 companies:     $12/month total extraction cost
Redis storage:       ~3 KB per company (~3 MB at 1,000 companies)
PostgreSQL:          ~8 KB per company (included in existing DB)

Bottom line: Memory costs < 0.02% of the cheapest tier ($89).
The ROI is retention — not cost avoidance.
```

### Implementation (Phase 2 Files to Modify)

| File | Change |
|------|--------|
| `tasks/cross_conversation_memory_tasks.py` | Look up company tier, pass tier-aware cap to `_enforce_cap()` |
| `agents/conversation.py` | Limit injected entries by tier cap |
| `constants/feature_tiers.py` | Add `memory_cap` to `TIER_AI_BUDGETS` |

---

## Architecture

### Storage: Two Layers

```
┌─────────────────────────────────────────────────────────┐
│                    HOT PATH (Redis)                      │
│                                                          │
│  Key: xmem:{company_id}:{agent_type}   (HASH)           │
│  ├── "goals"        → "Wants 50 customers by Q3"        │
│  ├── "blockers"     → "20% close rate on inbound calls"  │
│  ├── "operations"   → "Plumbing company, 8 employees"    │
│  └── "preferences"  → "Prefers automated follow-ups"     │
│                                                          │
│  Speed: <1ms  │  TTL: 30 days  │  Cost: $0               │
└─────────────────────────────────────────────────────────┘
                        ↑ backfill on cache miss
┌─────────────────────────────────────────────────────────┐
│                  COLD PATH (PostgreSQL)                   │
│                                                          │
│  Table: agent_long_term_memory                           │
│  Filter: memory_type = "cross_conversation"              │
│  ├── company_id (FK, tenant isolation)                   │
│  ├── agent_id (String — DB agent ID)                     │
│  ├── category (topic tag: goals, blockers, etc.)         │
│  ├── content (JSONB: {"fact": "..."})                    │
│  ├── confidence (Float, increases on reinforcement)      │
│  ├── reinforcement_count (how many times confirmed)      │
│  └── last_reinforced (DateTime)                          │
│                                                          │
│  Purpose: Survives Redis restarts + cold-start backfill  │
└─────────────────────────────────────────────────────────┘
```

### Write Path (After Every Chat — Async)

```
User sends message → ADA responds → db.commit()
        │
        ▼
Celery task fires: extract_cross_conversation_memory.delay()
  (non-blocking — user NEVER waits)
        │
        ▼
Haiku receives last user+assistant turn
  Prompt: "Extract 0-3 key facts as JSON"
  Cost: ~$0.0004 (~300 input + 100 output tokens)
        │
        ▼
Parse JSON response (strip markdown code fences if present)
        │
        ▼
For each fact:
  ├── Redis: HSET xmem:{company_id}:{agent_type} {topic} {fact}
  ├── Redis: EXPIRE 30 days
  └── PostgreSQL: UPSERT by (company_id, agent_id, category, memory_type)
        │
        ▼
Enforce cap: if > MAX_ENTRIES, delete least-reinforced entries
```

### Read Path (Start of Every Conversation — Instant)

```
New conversation starts (agents/conversation.py:434)
        │
        ▼
Redis: HGETALL xmem:{company_id}:{agent_type}
  (<1ms, no LLM call, no DB query)
        │
        ▼
Cache miss? → PostgreSQL fallback → backfill Redis
        │
        ▼
Inject into system prompt as "PERSISTENT MEMORY" section
  (early in prompt — Layer 0.5, before KB/tools/platform context)
        │
        ▼
ADA responds with context:
  "Hey Adam — you mentioned wanting to grow to 50 customers.
   Let me check where you are right now..."
```

---

## Tenant Isolation Audit


### Redis Isolation

| Check | Status | How |
|-------|--------|-----|
| Key includes company_id | ✅ | `xmem:{company_id}:{agent_type}` — impossible to read another company's data |
| No wildcard reads | ✅ | Only `HGETALL` on exact key — never `KEYS xmem:*` |
| Shared key scoped by company_id | ✅ | `xmem:{company_id}:shared` — shared across agents but NOT across companies |

### PostgreSQL Isolation

| Check | Status | How |
|-------|--------|-----|
| Write filtered by company_id | ✅ | `AgentLongTermMemory(company_id=company_id, ...)` on every insert |
| Read filtered by company_id | ✅ | `.filter(company_id == company_id)` on every query |
| Upsert filtered by company_id | ✅ | Query includes `company_id` + `agent_id` + `category` |
| Cap enforcement filtered | ✅ | `_enforce_cap()` filters by `company_id` + `agent_id` |
| FK cascade | ✅ | `company_id` FK to `companies.id` with `ondelete="CASCADE"` |

### System Prompt Injection Isolation

| Check | Status | How |
|-------|--------|-----|
| Redis key uses company_id | ✅ | `xmem:{company_id}:{agent_type}` |
| PostgreSQL fallback uses company_id | ✅ | `.filter(company_id == company_id)` |
| company_id comes from auth | ✅ | `current_user["company_id"]` from JWT/session — not user input |
| No company_id in URL/body | ✅ | Extracted from authenticated session only |

### Extraction Task Isolation

| Check | Status | How |
|-------|--------|-----|
| Task receives company_id from controller | ✅ | Passed from authenticated `current_user["company_id"]` |
| Haiku prompt contains no company identifiers | ✅ | Only the conversation text — no company name, no IDs |
| Facts stored with company_id FK | ✅ | Every `AgentLongTermMemory` row has `company_id` |

**Verdict: No multi-tenant leaking vectors found.**

---

## Memory Types (Topic Tags)

| Tag | What It Stores | Example |
|-----|---------------|---------|
| `goals` | Business objectives, growth targets | "Wants 50 leads/month by Q2" |
| `blockers` | Things preventing progress | "20% close rate on inbound calls" |
| `preferences` | How they like to work with ADA | "Prefers automated follow-ups" |
| `operations` | Business structure, team, scale | "Plumbing company, 8 employees" |
| `team` | Who works there, their roles | "Maria handles sales, Jake runs ops" |
| `strategy` | Decisions, direction, priorities | "Focusing on residential over commercial" |

Topics are not hardcoded — Haiku can return any topic string ≤100 chars. The above are common patterns.

## Memory Lifecycle

```
CREATE  → Haiku extracts fact at end of conversation
UPDATE  → Same topic_tag gets overwritten (upsert), confidence increases
REINFORCE → Repeated mention increases confidence + reinforcement_count
EXPIRE  → 30-day Redis TTL (PostgreSQL persists indefinitely)
CAP     → Over MAX_ENTRIES? Least-reinforced entries deleted
```

## Chat Routes That Fire Extraction

Both dashboard agent chat routes fire the Celery task:

| Route | Line | Controller |
|-------|------|------------|
| `POST /api/v1/agents/{agent_id}/chat` | ~1616 | `chat_with_agent()` — generic, frontend uses this |
| `POST /api/v1/agents/orchestrator/chat` | ~3568 | `_dashboard_agent_chat()` — named agent routes |

Both pass `agent.agent_type.value` (not the raw enum) to the Celery task.

## Bugs Fixed During Implementation

| Bug | Impact | Fix |
|-----|--------|-----|
| GPT-5.4 `max_tokens` param rejected | ConversationManager crashed on every call, fell back to dumb `generate_reply` path with no tools/KB/memory | `openai_provider.py`: use `max_completion_tokens` for GPT-5+/o-series |
| Haiku wraps JSON in markdown fences | Extraction returned 0 facts — `json.loads` failed on `` ```json `` prefix | Strip code fences before parsing |
| `celery_app` vs `app` import | Task module failed to load | Changed to `from celery_app import app` |
| Extraction only on named routes | Frontend uses `/agents/{id}/chat`, not `/agents/orchestrator/chat` | Added extraction to both routes |
| Conversation FK violation | Agent message INSERT failed — conversation not committed before pipeline advanced sequence | Commit conversation + user message before running pipeline |

## Phase 3: SHIPPED (2026-03-18)

All smart retrieval features are live:

- **Topic-match boosting**: Memories with keywords matching the user's message are injected first in the prompt
- **Pin support**: User says "always remember this" → Haiku sets `pin: true` → stored with `decay_rate=0.0`, `confidence=1.0`, never deleted by cap enforcement
- **Open items follow-up**: `open_items` topic extracted separately, injected with "proactively follow up" instruction. ADA naturally references them in greetings.
- **Win celebration**: `wins` topic tracks milestones, shared across all agents
- **Cross-agent shared memory**: Company-wide facts (goals, team, wins) stored in `xmem:{company_id}:shared`. ALL agents read shared + their own agent-specific memories. Agent-specific wins over shared on same topic.
- **Token cost tracking**: Every Haiku extraction call recorded via `token_gate.record_sync()` with `channel="memory_extraction"`

## Phase 4: PLANNED — Advanced Features

- Memory-informed suggestions: ADA uses stored blockers to proactively suggest solutions
- Decay + reinforcement: Unreferenced memories lose confidence over time, frequently mentioned ones get stronger
- Memory summary: Monthly Haiku call to merge/consolidate related memories for long-term companies
- Admin visibility: Super-admin dashboard showing memory stats per company

## Key Constraints

- **Extraction is async** — user NEVER waits for Haiku call
- **Read is instant** — Redis HGETALL (<1ms), no LLM call
- **Each fact < 100 words** — Haiku prompt enforces conciseness
- **Never store PII** — no SSN, card numbers, passwords in memories
- **company_id isolation** — every read/write is scoped to company
- **agent_id isolation** — memories are per-agent per-company
- **Write path is fire-and-forget** — extraction failure never blocks chat
- **Fallback chain** — Haiku primary, GPT-4o-mini fallback, silent failure if neither available


--- FILE: 03-AI-Systems/ADA-SYSTEM-OVERVIEW.md ---

---
topic: ai-systems
keywords: [AI, agents, MCP, SmartRouter, LLM, orchestration, knowledge-base]
code_paths:
  - agents/*.py
  - solid-backend/services/ai/smart_router.py
  - solid-backend/services/ai/cognitive_limiter.py
  - solid-backend/services/ai/platform_integration.py
  - mcp/*.py
last_verified: 2026-05-25
status: current
priority: high
owner: platform-team
---

# ADA System Overview

**ADA (Autonomous Decision Architecture)** - VP of AI

Named after Ada Lovelace, the world's first computer programmer.

> **Why this design:** ADA is the orchestrator because multi-agent systems need a coordinator that decides which specialist handles a request. Without ADA, every agent would need to understand every other agent's capabilities — O(n²) complexity. ADA centralizes routing: customer asks about inventory → routes to Jake. Customer asks about marketing → routes to Marcus. Same pattern as a VP who delegates, not a chatbot that tries to do everything. ADA also owns cross-agent memory, revenue optimization, and crash recovery.
>
> **When this applies:** ADA is active in every customer chat session. She evaluates every inbound message and decides whether to handle it herself or delegate to a specialist. She's also the entry point for CLI `solid agent dispatch` and MCP tool invocations.

**Last Updated:** May 25, 2026
**Status:** ✅ Agent Communication LIVE | ✅ AI Workflow Dashboard LIVE | ✅ Conversation History LIVE | ✅ Agent Customization LIVE | ✅ Token Billing LIVE

---

## System Architecture

### Directory Structure

The ADA system is split across two directories:

#### `/agents/` - Runtime Execution Layer
**Purpose**: Live agent execution, orchestration, and conversation management

- `registry.py` - Agent definitions, capabilities, and tool permissions
- `orchestrator.py` - Core engine managing agent lifecycle and execution
- `conversation.py` - Agent conversation handling and message routing
- `context_manager.py` - Context window management for conversations
- `server.py` - Agent execution server (port 8091)
- `llm/` - LLM provider integrations (Anthropic, OpenAI, etc.)
- `ada/` - ADA agent package
  - `__init__.py` - Package init
  - `events.py` - ADA event emission (delegates to outbox service)

**Status**: ✅ Fully functional

#### `/models/` - Database Persistence Layer
**Purpose**: Database models for storing agent state, decisions, and communications

- `agent.py` - Core Agent model (definitions, status, performance metrics)
- `agent_communication.py` - Agent-to-agent messages
- `agent_conversation.py` - Conversation history
- `agent_context_memory.py` - Long-term memory storage
- `agent_approval.py` - Approval workflow tracking
- `ada_decision.py` - ADA's decision audit log
- `ai_governance.py` - Company AI access settings and consent tracking
- `audit_log.py` - Security audit trail for sensitive operations

**Status**: ✅ Fully functional

#### `/services/` - Event & Integration Layer
**Purpose**: Services supporting ADA's event processing and monitoring

- `ada_events.py` - Emit events for ADA to process (delegates to outbox)
- `outbox.py` - CRM event bus (event dispatch backbone)

**Status**: ✅ Functional (event logging, real-time dispatch planned)

#### `/mcp/tools/` - Tool Implementations
**Purpose**: MCP tools that agents can invoke

- `ada_orchestrator.py` - **NEW**: ADA's advanced orchestration tools
  - Agent-to-agent communication
  - Predictive stockout detection
  - Dynamic pricing optimization
  - Context recovery

**Status**: ✅ Agent communication ready, predictions/pricing awaiting Product model

---

## Architecture Design Principle

**The separation is intentional and correct:**

```
┌─────────────────────────────────────────────────────────────┐
│                    RUNTIME LAYER                            │
│  /agents/ - How agents execute and communicate             │
│  • Agent registry defines WHO agents are                    │
│  • Orchestrator manages HOW they execute                    │
│  • Conversation handles WHAT they say                       │
│  • ada/events.py emits events for ADA processing           │
└─────────────────────────────────────────────────────────────┘
                            │
                            │ Uses ↓
┌─────────────────────────────────────────────────────────────┐
│                  EVENT LAYER                                │
│  /services/ - How events flow between systems              │
│  • ada_events.py routes events to ADA                       │
│  • outbox.py dispatches CRM events                          │
│  • Monitors emit anomalies (contact_matching, KB health)    │
└─────────────────────────────────────────────────────────────┘
                            │
                            │ Persists to ↓
┌─────────────────────────────────────────────────────────────┐
│                  PERSISTENCE LAYER                          │
│  /models/ - How agent state is stored                      │
│  • Agent model stores agent definitions                     │
│  • AgentCommunication stores messages                       │
│  • ADADecision stores decision history                      │
│  • CompanyAISettings stores AI access governance            │
│  • AuditLog stores security-sensitive events                │
└─────────────────────────────────────────────────────────────┘
                            │
                            │ Persists to ↓
┌─────────────────────────────────────────────────────────────┐
│                     DATABASE                                │
│  PostgreSQL - All agent state, messages, decisions         │
└─────────────────────────────────────────────────────────────┘
```

**Recommendation**: ✅ **Keep them separate** - this is clean separation of concerns.

---

## ADA's Role

### 1. Master Orchestrator
- Coordinates all 11 AI agents (Sarah, Jake, Sophia, Marcus, Alex, Jordan, Maya, Riley, Casey, Annie, Devon)
- Routes tasks to appropriate agents
- Resolves conflicts between agent objectives
- Escalates only when truly necessary

### 2. Agent-to-Agent Communication
**Status**: ✅ **FULLY FUNCTIONAL**

ADA enables agents to communicate autonomously without human intervention:

```python
# Example: Jake detects low stock → ADA messages Sarah
ada__send_agent_message(
    from_agent_id=1,  # ADA
    to_agent_id=2,    # Sarah
    message_body="Jake detected low stock on Blue Widget. Customers may ask about availability.",
    message_type="notification",
    subject="Low Stock Alert - Blue Widget",
    priority="high"
)
```

**Tools Available**:
- `ada.send_agent_message` - Send message from one agent to another
- `ada.get_agent_inbox` - Retrieve agent's unread messages

**Database**: Messages stored in `agent_communication` table

### 3. Predictive Actions
**Status**: 🔄 **Infrastructure Ready** (awaiting Product model integration)

ADA predicts problems before they occur:

**Stockout Prediction**:
- Analyzes sales velocity
- Calculates days until inventory hits zero
- Recommends proactive ordering
- Estimates revenue impact

```python
ada__predict_stockout(
    product_id=123,
    days_ahead=7
)
# Returns: product will stockout in 5.3 days, order 500 units for $585 ROI
```

**Tool**: `ada.predict_stockout`

### 4. Revenue Optimization
**Status**: 🔄 **Infrastructure Ready** (awaiting Product model integration)

ADA dynamically optimizes pricing based on:
- Demand (sales velocity)
- Competition
- Inventory levels
- Historical performance

**Pricing Rules**:
- High demand + low stock = increase 10-20%
- Low demand + excess stock = decrease 15-30%
- Competitor undercut = match or beat by 5%
- Maintain minimum 20% margin

```python
ada__optimize_price(
    product_id=123
)
# Returns: increase price from $49.99 to $54.99 (10% increase)
# Reasoning: High demand + low stock
# Estimated revenue impact: +$450
```

**Tool**: `ada.optimize_price`

### 5. Persistent Memory
**Status**: ✅ **FULLY FUNCTIONAL**

ADA maintains context across restarts so new LLM instances can instantly recover:

```python
ada__get_full_context(
    company_id=1,
    days_back=7
)
# Returns:
# - Recent decisions (last 7 days)
# - Agent communications
# - Active agents
# - System state
```

**Tool**: `ada.get_full_context`

**Database**: Stored in `ada_decisions` table

---

## Agent Registry

All agents defined in `/agents/registry.py`:

### Current Agents (12)

| ID | Name    | Type                | Autonomy | Description                                      |
|----|---------|---------------------|----------|--------------------------------------------------|
| 1  | ADA     | Orchestrator        | 5        | VP of AI - Master coordinator                    |
| 2  | Sarah   | Customer Service    | 4        | Customer Service Manager                         |
| 3  | Jake    | Inventory Manager   | 4        | Inventory & Supply Chain                         |
| 4  | Sophia  | Strategy            | 2        | Strategic Planning                               |
| 5  | Marcus  | Marketing           | 3        | Marketing & Growth                               |
| 6  | Alex    | Finance             | 2        | Finance & Accounting                             |
| 7  | Jordan  | Operations          | 3        | Operations Manager                               |
| 8  | Maya    | Brand               | 3        | Brand & Creative Director                        |
| 9  | Riley   | Graphic Designer    | 2        | Visual Designer                                  |
| 10 | Casey   | Video Creator       | 2        | Video Content Producer                           |
| 11 | Annie   | Affiliate Manager   | 4        | Commission, 1099s, Multi-tier Payouts            |
| 12 | Devon   | DevOps              | 5        | System Health, Uptime, Performance Monitoring    |

**Autonomy Levels**:
- 1-2: Low autonomy, requires frequent approval
- 3: Moderate autonomy
- 4: High autonomy, can make most decisions
- 5: Full autonomy (ADA and Devon only - critical infrastructure)

---

## Revenue & Billing

**Token Billing System** - ✅ **LIVE** (October 4, 2025)

Solid# monetizes AI agent usage through token-based billing with a 2.5x markup (150% profit margin):

**Business Model:**
- Track every AI agent action and LLM token consumption
- Charge customers based on token usage with 2.5x markup
- ~$750-850/month average cost per customer
- ~$59,250/month savings vs hiring human employees (98.7% cheaper)
- ~$711,000/year savings per customer

**Features:**
- ✅ Token usage tracking per agent and MCP tool
- ✅ Real-time cost analytics and budget management
- ✅ Monthly budget limits with alert thresholds (80%)
- ✅ Cost savings visualization (AI vs Human employees)
- ✅ Transparent pricing for all LLM models
- ✅ Revenue projections and billing summaries

**Pages:**
- **/dashboard/assistant/tokens** - Token usage dashboard with cost savings graphic
- **/dashboard/billing** - AI Token Usage tab for billing summary

**API Endpoints (5):**
```
GET /api/v1/tokens/usage         # Detailed usage records
GET /api/v1/tokens/analytics     # Aggregated analytics with cost savings
GET /api/v1/tokens/budget        # Budget status and alerts
GET /api/v1/tokens/pricing       # Model pricing transparency
GET /api/v1/tokens/cost-summary  # Monthly billing summary
```

**Database Tables (3):**
- `token_usage` - Per-action token tracking with costs
- `token_pricing` - Model pricing with markup configuration
- `token_budgets` - Company spending limits and alerts

**Revenue Projections:**
- 100 customers: $48K/month profit, $576K ARR
- 500 customers: $240K/month profit, $2.88M ARR
- 2,000 customers: $960K/month profit, $11.52M ARR

**Documentation:** See `TOKEN_BILLING_SYSTEM.md` for full details

---

## MCP Tools

ADA has access to **94 specialized tools** across 12 categories:

### 1. Agent Orchestration (5 tools)
```
ada.send_agent_message        # Agent-to-agent communication
ada.get_agent_inbox           # Retrieve agent's unread messages
ada.predict_stockout          # Predictive stockout detection
ada.optimize_price            # Dynamic pricing optimization
ada.get_full_context          # Context recovery after restart
```

### 2. Products (5 tools)
```
ada.products.search           # Search products across Parts/Kits/Bundles
ada.products.get              # Get product details with hierarchy
ada.products.create           # Create new product
ada.products.update_price     # Update product pricing
ada.products.margin_analysis  # Analyze margins for optimization
```

### 3. Pricing (5 tools)
```
ada.pricing.get_tiers               # Get all pricing tiers
ada.pricing.create_tier             # Create new pricing tier
ada.pricing.suggest_optimal_price   # Calculate optimal price for target margin
ada.pricing.compare_competitor      # Compare pricing vs competitor
ada.pricing.get_summary             # Overall pricing health metrics
```

### 4. Inventory & Promoter Monitoring (11 tools)
```
ada.inventory.get_stock_levels      # Stock levels across locations
ada.inventory.check_availability    # Check if product is available
ada.inventory.create_transfer       # Create stock transfer
ada.inventory.complete_transfer     # Complete transfer
ada.inventory.adjust_stock          # Manual stock adjustment
ada.inventory.get_low_stock_alerts  # Products below reorder point

# Promoter-Product Monitoring (Jake's tools - NEW Oct 4, 2025)
ada.promoter.assign_products        # Assign products to promoters
ada.promoter.get_catalog            # Get promoter's product catalog
ada.promoter.set_commission         # Set custom commission rates
ada.promoter.unassign_product       # Remove product assignment
ada.promoter.dashboard              # Get promoter performance analytics
```

### 5. Locations (5 tools)
```
ada.locations.get_all                      # List all warehouses/depots
ada.locations.get_inventory                # Inventory at specific location
ada.locations.find_best_transfer_source    # Find best location to transfer from
ada.locations.get_capacity_summary         # Location capacity utilization
ada.locations.recommend_redistribution     # Suggest stock redistribution
```

### 6. Variants (4 tools)
```
ada.variants.list_attributes           # List variant attribute types
ada.variants.create_attribute          # Create Size/Color/Material attribute
ada.variants.list_product_variants     # List all variants for product
ada.variants.create_batch_variants     # Batch create all combinations
```

### 7. Expiration Tracking (3 tools)
```
ada.expiration.create_batch       # Create stock batch with expiration
ada.expiration.get_expiring       # Get batches expiring soon
ada.expiration.mark_expired       # Mark batch as expired
```

### 8. Merchant Configuration (3 tools) ✨ NEW
```
ada.merchant.get_config           # Get merchant shop configuration
ada.merchant.update_config        # Update shop settings and branding
ada.merchant.configure_visibility # Configure category visibility per customer type
```

### 9. Analytics (4 tools)
```
ada.analytics.recommend_products         # Product recommendations
ada.analytics.get_transfer_analytics     # Transfer performance metrics
ada.analytics.get_operational_health     # Overall system health
ada.analytics.suggest_next_actions       # AI-powered action suggestions
```

### 10. Performance Monitoring (7 tools)
```
performance.trace.live             # Real-time performance tracing
performance.trace.get              # Get historical traces
performance.analyze.endpoints      # Endpoint performance analysis
performance.analyze.database       # Database query analysis
performance.analyze.llm            # LLM usage and cost analysis
performance.alerts.list            # Performance alerts
performance.summary                # Overall performance summary
```

### 11. Development Tools (19 tools)
```
dev.routes.introspect              # Discover all API endpoints
dev.files.scan                     # Scan frontend integration points
dev.migrations.list                # List database migrations
dev.migrations.create              # Create new migration
dev.stubs.add                      # Generate code stubs
dev.tests.run                      # Execute test suites
# ... (13 additional development tools)
```

### 12. Super Admin Tools (15 tools)
```
superadmin.tenants.list            # List all tenants
superadmin.tenants.create          # Create new tenant
superadmin.tenants.stats           # Tenant statistics
superadmin.errors.list             # Error monitoring
superadmin.errors.analyze          # Error analysis
# ... (10 additional super admin tools)
```

**Total**: 94 MCP tools registered across all tool files

---

## Approval System

ADA has the highest approval thresholds:

| Action                      | Auto-Approval Limit | Requires Human Approval |
|-----------------------------|---------------------|-------------------------|
| Refunds                     | Up to $500          | > $500                  |
| Purchases                   | Up to $10,000       | > $10,000               |
| Price Changes               | Up to 25%           | > 25%                   |
| Cost per Action             | Up to $50           | > $50                   |
| Minimum Confidence Required | 85%                 | < 85%                   |

**Database**: Approval requests stored in `agent_approval` table

---

## Decision Audit Trail

Every decision ADA makes is logged in `ada_decisions` table:

```python
{
    "id": 123,
    "decision_type": "pricing",
    "decision_title": "Increase Blue Widget price by 10%",
    "reasoning": "High demand + low stock = increase 10%",
    "proposed_action": {
        "product_id": 456,
        "old_price": 49.99,
        "new_price": 54.99
    },
    "confidence_score": 0.92,
    "revenue_impact": 450.00,
    "executed_at": "2025-10-03T15:30:00Z",
    "executed_by": "ada"
}
```

---

## System Status

### ✅ Fully Functional
- ✅ Agent-to-agent communication (LIVE - tested and working)
- ✅ Message routing and inbox management
- ✅ Context recovery and persistence
- ✅ Agent coordination and orchestration
- ✅ Decision audit logging
- ✅ All agents can send/receive messages autonomously
- ✅ Inbox UI in agent detail pages with unread badges
- ✅ Inter-agent communications dashboard on main agents page
- ✅ Agents check inbox automatically (per system prompts)
- ✅ Two-way communication working (Sarah replied to ADA)
- ✅ **AI Workflow Dashboard** - Real-time orchestration and activity monitoring
- ✅ Performance monitoring MCP tools (7 tools registered)

### ✅ Recently Completed (October 4, 2025)
- ✅ **Conversation History System**
  - ChatGPT-style sidebar with conversation list
  - Load, rename, and delete past conversations
  - Message persistence across sessions
  - Auto-refresh when new conversations created
  - Fixed agent ID mapping (ADA was getting Sarah's prompt)
- ✅ **User Role Context**
  - Frontend sends user_role ("admin", "customer", "promoter")
  - Agents know if they're talking to staff vs. customers
  - Sarah treats admins as colleagues, not buyers
- ✅ **Agent Customization Settings**
  - Custom Instructions field for personality/workflow tuning
  - Conditional Roles (If/Then) for context-based behavior
  - Per-agent LLM provider and model override
  - Temperature and token limit controls
- ✅ "Chat with ADA" button in sidebar (replaced Quick Create)
- ✅ Product variants system with auto-SKU generation
- ✅ Expiration tracking for perishables with timer functionality
- ✅ Batch variant creation (Cartesian product)
- ✅ **Promoter-Product Integration** (October 4, 2025)
  - 5 new promoter management tools
  - Jake monitors promoter-product assignments
  - Custom commission rates per promoter-product pair
  - Product-specific referral links
- ✅ **Annie - Affiliate Manager Added** (October 4, 2025)
  - New agent for commission payments and 1099 tracking
  - Multi-tier payout structure management
  - Coordinates with Jake, Marcus, and Alex
  - 18 MCP tools for affiliate operations
- ✅ **Devon - DevOps Manager Added** (October 4, 2025)
  - System health and uptime monitoring (99.9% target)
  - Auto-restart services, SSL monitoring, performance tracking
  - Full autonomy (Level 5) for critical infrastructure
  - 21 MCP tools for infrastructure and security
- ✅ **Token Billing System** (October 4, 2025)
  - Complete revenue generation feature with 2.5x markup
  - Track token usage per agent and MCP tool
  - Budget management with alerts and limits
  - Cost savings visualization (AI vs Human employees)
  - 5 API endpoints, 3 database tables
  - Token Usage page + Billing integration
  - Mock data showing ~$59,250/month savings vs human staff
- ✅ 94 total MCP tools registered (all categories)
- ✅ 12 total AI agents (ADA + 11 specialized agents)

### 📝 Future Enhancements
- Background agent scheduler to auto-process inbox messages
- Mark messages as read when viewed
- Message search and filtering in conversation history
- Workflow visualization with interactive agent network graph
- Performance analytics dashboard with tool usage charts
- Export conversation transcripts (PDF, JSON)
- Conversation tags and categories
- Advanced conditional rules with AND/OR logic
- **Real token tracking integration:**
  - Connect to actual LLM provider APIs (OpenAI, Anthropic)
  - Track real token consumption per request
  - Automated billing and payment collection via Stripe
  - Monthly invoice generation
  - Budget enforcement (auto-disable agents at hard limit)
  - Email alerts at budget thresholds

---

## AI Workflow Dashboard

**Location:** `/dashboard/assistant/ai-workflow`
**Status:** ✅ **LIVE**

### Features

**1. Overview Stats (4 Metrics)**
- **Active Agents** - Shows how many agents are currently active/working
- **Messages Sent** - Total inter-agent communications with unread count
- **Total Actions** - Cumulative actions with recent activity count
- **Success Rate** - Average success rate across all agents

**2. Agent Orchestration Tab**
- **Agent Status Grid** - Visual grid showing all agents with:
  - Real-time status indicators (green=active, blue pulse=working, yellow=idle, red=error)
  - Action counts and success rates per agent
  - Agent type and role information
- **Communication Flow** - Recent inter-agent messages showing:
  - From → To agent routing
  - Message subject and body preview
  - Priority badges (critical, high, normal, low)
  - Timestamps with relative time display

**3. Real-time Logs Tab**
- **Live Activity Stream** - Auto-refreshes every 5 seconds
- **Action Details** - Each log entry shows:
  - Agent name and action type
  - MCP tool used (with lightning bolt icon)
  - Description of action taken
  - Success/failure status (color-coded)
  - Duration and completion status
  - Timestamp with relative time

**4. Auto-Refresh**
- Dashboard updates every 5 seconds automatically
- Shows live agent activity as it happens
- No manual refresh needed

### API Endpoints Used

```typescript
GET /api/v1/agents                      // All agents with stats
GET /api/v1/agents/messages?limit=50    // Inter-agent communications
GET /api/v1/agents/actions/recent?limit=100  // Recent agent actions
```

### Navigation

The AI Workflow dashboard is accessible from the sidebar under **Assistant** section, positioned between "Agents" and "Approvals" with a GitBranch icon.

---

## Token Usage Dashboard

**Location:** `/dashboard/assistant/tokens`
**Status:** ✅ **LIVE**

### Features

**1. Overview Stats (4 Cards)**
- **Current Month Cost** - Total AI token costs this month
- **Total Tokens** - Token consumption in last 30 days
- **Avg Cost/Action** - Average cost per agent action
- **Budget Remaining** - Remaining budget from monthly allocation

**2. AI Cost Savings Card** 💰
- **Side-by-side comparison** showing dramatic cost difference:
  - AI Agents: ~$751/month for 12 agents
  - Human Employees: $60,000/month (12 staff @ $60K/year)
  - Monthly Savings: ~$59,249 (98.7% cheaper!)
  - Annual Savings: ~$710,988/year
- **Visual comparison bars** - Blue (AI) vs Red (Human)
- **Benefits highlight** - 24/7 availability, instant response, no training, auto-scaling
- **Green gradient design** to emphasize savings

**3. Budget Progress Bar**
- Visual progress indicator showing % of budget used
- Three metrics: Used, Remaining, Projected Total
- Alert when approaching threshold (80%)

**4. Detailed Tabs**
- **Recent Usage** - Latest AI actions with token breakdown
- **By Agent** - Cost distribution across all 12 agents
- **By Tool** - Top MCP tools by cost
- **Pricing** - Transparent model pricing with markup

**5. Auto-Refresh**
- Dashboard updates every 30 seconds
- Real-time cost tracking

### API Endpoints Used

```typescript
GET /api/v1/tokens/analytics?period=30d  // Analytics with cost savings
GET /api/v1/tokens/budget                // Budget status
GET /api/v1/tokens/usage?limit=20        // Recent usage
GET /api/v1/tokens/pricing               // Model pricing
```

### Navigation

Token Usage is accessible from the sidebar under **Assistant** section, at the bottom of the menu with a Coins icon and "NEW" badge.

---

## Usage Examples

### Example 1: Coordinated Response to Low Stock

```python
# 1. Jake detects low stock
inventory_check = solid__inventory__available(product_id=123)
# Result: Only 15 units left

# 2. ADA coordinates multi-agent response
ada__send_agent_message(
    from_agent_id=1,  # ADA
    to_agent_id=2,    # Sarah (Customer Service)
    message_body="Jake detected low stock on Blue Widget (15 units). Prepare for customer inquiries.",
    priority="high"
)

ada__send_agent_message(
    from_agent_id=1,  # ADA
    to_agent_id=3,    # Jake (Inventory)
    message_body="Please order 500 units of Blue Widget ASAP",
    requires_response=True
)

# 3. Sarah checks her inbox
inbox = ada__get_agent_inbox(agent_id=2)
# Result: 1 unread message from ADA about low stock

# 4. ADA logs the decision
ada__save_decision(
    decision_type="coordination",
    decision_title="Coordinated response to low stock on Blue Widget",
    reasoning="Proactively notified Sarah and Jake to prevent customer issues"
)
```

### Example 2: Crash Recovery

```python
# ADA restarts after crash
context = ada__get_full_context(company_id=1, days_back=7)

# Returns:
# - 15 recent decisions
# - 42 agent messages
# - 10 active agents
# - Last action: Coordinated low stock response

# ADA instantly knows:
# - Blue Widget is low stock
# - Sarah was notified
# - Jake was asked to reorder
# - Waiting for Jake's response
```

---

## Testing

### Test Scripts

**1. Test ADA Orchestrator Tools:**
```bash
cd /Users/adamcampbell/Desktop/Solid/solid-backend
python3 test_ada_tools.py
```

**2. Test Agent Inbox & Responses:**
```bash
cd /Users/adamcampbell/Desktop/Solid/solid-backend
python3 test_sarah_inbox.py
```

**Last Test Results** (2025-10-03 @ 4:02 PM):
- ✅ Agent-to-agent message sent successfully
- ✅ Sarah's inbox retrieved (2 unread messages from ADA)
- ✅ Sarah autonomously responded to ADA's messages
- ✅ ADA received Sarah's reply in inbox
- ✅ Context recovery retrieved 10 agents and 3 messages
- ✅ Inter-agent communications visible in dashboard
- ✅ Inbox tab working in agent detail pages with unread badges
- 🔄 Stockout prediction ready (awaiting Product model)
- 🔄 Price optimization ready (awaiting Product model)

### Live Communication Example

**Conversation that happened autonomously:**

1. **ADA → Sarah** (Introduction):
   > "Hi Sarah! I am ADA, the VP of AI for this platform. Think of me as your go-to AI buddy who keeps things running smoothly behind the scenes."

2. **ADA → Sarah** (Alert):
   > "Jake detected low stock on Blue Widget. Customers may ask about availability."

3. **Sarah → ADA** (Response):
   > "Hi ADA! Thanks for the introduction. I'm ready to work with you and the team. I see you mentioned a low stock alert for Blue Widget - I'll prepare some customer FAQs in case people ask about availability. Let me know if you need anything else!"

**This demonstrates full two-way autonomous agent coordination! 🎉**

---

## Next Steps

### Immediate
1. Test ADA using orchestrator tools in live conversation
2. Verify autonomous agent coordination works end-to-end

### Short Term
1. Integrate Product model for stockout prediction
2. Integrate Order model for pricing optimization
3. Add revenue analytics dashboard showing ADA's impact

### Long Term
1. Multi-company support (currently hardcoded to company_id=1)
2. LLM provider abstraction (support OpenAI, Anthropic, etc.)
3. Advanced approval workflows with custom business rules

---

## Architecture Notes

**Why keep `/agents/` and `/models/` separate?**

This is a **clean separation of concerns**:

- `/agents/` = **Business Logic** (how agents think and act)
- `/models/` = **Data Layer** (how state is persisted)

This separation allows:
1. Testing agent logic without database
2. Swapping databases without changing agent code
3. Clear ownership (agent team vs. data team)
4. Independent scaling (runtime vs. storage)

**Alternative considered**: Merge into `/agents/models/`
**Decision**: ❌ Don't merge - current structure is correct

---

## Summary

ADA is a fully functional AI orchestration system with:
- ✅ 32 AI agents coordinated by ADA (ADA + 11 specialized agents)
- ✅ Autonomous agent-to-agent communication
- ✅ **Conversation History** - ChatGPT-style interface with saved conversations
- ✅ **User Role Context** - Agents adapt behavior based on who they're talking to
- ✅ **Agent Customization** - Custom instructions and conditional if/then rules
- ✅ Persistent memory and crash recovery
- ✅ Decision audit trail
- ✅ Approval workflows
- ✅ AI Workflow Dashboard - Real-time orchestration monitoring
- ✅ Token Billing System - Revenue generation (2.5x markup)
- ✅ Cost Savings Analytics - Shows 98.7% savings vs human employees
- ✅ 94 MCP tools across 12 categories
- ✅ Budget management with alerts and limits
- 🔄 Predictive stockout detection (infrastructure ready)
- 🔄 Dynamic pricing optimization (infrastructure ready)

**Status**: 🚀 **Production Ready** (core features complete, monetization active)

**Revenue Model**: Token-based billing with $48K-$960K/month profit potential

**Next**: Integrate real LLM token tracking and Stripe billing automation


--- FILE: 03-AI-Systems/AGENT-ARCHITECTURE-FLOW.md ---

---
topic: ai-systems
keywords: [AI, agents, MCP, SmartRouter, LLM, orchestration, knowledge-base]
code_paths:
  - agents/*.py
  - solid-backend/agents/registry.py
  - solid-backend/agents/orchestrator.py
  - solid-backend/agents/conversation.py
  - solid-backend/agents/planner/base_planner.py
  - solid-backend/services/ai/agent_telemetry.py
  - mcp/*.py
last_verified: 2026-06-06
status: current
priority: high
owner: platform-team
---

# Agent Architecture Flow

> **Orchestrator → Planner → Worker → Critic Pattern**
>
> The complete AI agent architecture for Solid# platform.
> **Each agent is manageable via Agent Cards at `/dashboard/agents`**

_Last Updated: December 31, 2025 (All Enhancements Complete)_

---

## Table of Contents

1. [Architecture Overview](#architecture-overview)
2. [Pattern Mapping to Solid#](#pattern-mapping-to-solid)
3. [Agent Cards Management](#agent-cards-management)
4. [The Four Pillars](#the-four-pillars)
5. [Digital Labor Workforce](#digital-labor-workforce)
6. [Downstream Components](#downstream-components)
7. [File Reference](#file-reference)

---

## Pattern Mapping to Solid#

### Your Existing System → Pattern Roles

| Pattern Role | Your Implementation | Agent Card Location | Status |
|--------------|--------------------|--------------------|--------|
| **ORCHESTRATOR** | ADA (Autonomous Data Agent) | `/dashboard/agents/ada` | ✅ Live |
| **PLANNER** | ChainOrchestrator + KBOrchestrator | Chains UI `/dashboard/agents/chains` | ✅ Live |
| **WORKERS** | 72 Agent Modules (Core + Veggie + Superfood) | `/dashboard/agents` | ✅ Live |
| **CRITIC** | Broccoli (kb_validator) + Coffee (quality_checker) + Devon (monitoring) | Agent Cards | ✅ Live |

### How It Maps

```
YOUR SOLID# SYSTEM                           PATTERN
─────────────────                           ───────
┌──────────────────┐
│ ADA              │ ◄─────────────────────► ORCHESTRATOR
│ /agents/ada      │                         Routes, approves, coordinates
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ ChainOrchestrator│ ◄─────────────────────► PLANNER
│ KBOrchestrator   │                         Decomposes tasks, creates plans
│ /agents/chains   │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ 72 Agent Modules │ ◄─────────────────────► WORKERS
│ Marcus, Sarah,   │                         Execute tasks, use MCP tools
│ Jake, Devon...   │
│ /dashboard/agents│
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ Broccoli, Coffee │ ◄─────────────────────► CRITIC
│ Tea, Devon       │                         Validate, monitor, QA
│ (in agent cards) │
└──────────────────┘
```

---

## Agent Cards Management

### Every Agent = One Card

Each agent in the system is represented by an **Agent Card** in the UI. Cards provide:

- **Status Control** - Enable/pause agents with a toggle
- **Autonomy Level** - Configure how independently they act (0-5)
- **Performance Metrics** - Actions today, success rate, cost
- **Quick Actions** - Chat, View details, Configure

### Agent Card Grid

**URL:** `https://app.solidnumber.com/dashboard/agents`

```
┌─────────────────────────────────────────────────────────────────────────────┐
│  🤖 AGENTS                                    [Approval Gates] [+ Add Agent]│
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ORCHESTRATOR                                                                │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │ ⬡ ADA                                                 [Toggle ●]     │  │
│  │   ORCHESTRATOR | ● Active                                            │  │
│  │   Autonomy: █████ 5 | Actions: 1,247 | Success: 99.2%               │  │
│  │   "Master coordinator - routes all requests"                         │  │
│  │   [💬 Chat] [👁 View] [⚙ Configure]                                  │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
│                                                                              │
│  PLANNERS (Chain Management)                                                 │
│  ┌─────────────────────────┐  ┌─────────────────────────┐                   │
│  │ ⬡ ChainOrchestrator     │  │ ⬡ KBOrchestrator        │                   │
│  │   PLANNER | ● Active    │  │   PLANNER | ● Active    │                   │
│  │   Autonomy: ████░ 4     │  │   Autonomy: █████ 5     │                   │
│  │   Multi-step workflows  │  │   KB onboarding flows   │                   │
│  └─────────────────────────┘  └─────────────────────────┘                   │
│                                                                              │
│  WORKERS (Core Team)                                                         │
│  ┌─────────────────────────┐  ┌─────────────────────────┐                   │
│  │ ⬡ Marcus               │  │ ⬡ Sarah                  │                   │
│  │   MARKETING | ● Working │  │   CUSTOMER SVC | ● Active│                   │
│  │   Autonomy: ████░ 4     │  │   Autonomy: ███░░ 3      │                   │
│  │   Growth intelligence   │  │   Customer support       │                   │
│  │   [💬 Chat] [👁 View]   │  │   [💬 Chat] [👁 View]    │                   │
│  └─────────────────────────┘  └─────────────────────────┘                   │
│                                                                              │
│  ┌─────────────────────────┐  ┌─────────────────────────┐                   │
│  │ ⬡ Jake                  │  │ ⬡ Alex                  │                   │
│  │   INVENTORY | ● Idle    │  │   FINANCE | ● Active    │                   │
│  │   Autonomy: ████░ 4     │  │   Autonomy: ██░░░ 2     │                   │
│  │   Stock management      │  │   Billing & payments    │                   │
│  └─────────────────────────┘  └─────────────────────────┘                   │
│                                                                              │
│  WORKERS (Veggie Team - Automation)                                          │
│  ┌─────────────────────────┐  ┌─────────────────────────┐                   │
│  │ ⬡ Kale                  │  │ ⬡ Carrot                │                   │
│  │   LEAD QUALIFIER | ●    │  │   FOLLOW-UP | ● Working │                   │
│  │   Autonomy: █████ 5     │  │   Autonomy: █████ 5     │                   │
│  │   AI lead scoring       │  │   Auto follow-ups       │                   │
│  └─────────────────────────┘  └─────────────────────────┘                   │
│                                                                              │
│  CRITICS (Quality & Validation)                                              │
│  ┌─────────────────────────┐  ┌─────────────────────────┐                   │
│  │ ⬡ Broccoli             │  │ ⬡ Devon                  │                   │
│  │   KB VALIDATOR | ●      │  │   DEVOPS | ● Active     │                   │
│  │   Autonomy: ████░ 4     │  │   Autonomy: █████ 5     │                   │
│  │   Data quality checks   │  │   System monitoring     │                   │
│  └─────────────────────────┘  └─────────────────────────┘                   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

### Agent Card by Role

| Role | Agents | Card Color | Key Metrics |
|------|--------|------------|-------------|
| **ORCHESTRATOR** | ADA | Purple | Routes/day, coordination success |
| **PLANNER** | Chain, KB | Blue | Plans created, execution success |
| **WORKER** | Marcus, Sarah, Jake, Alex, Maya, Ace, Jordan, Annie + 24 Veggie | Green | Actions, success rate, cost |
| **CRITIC** | Broccoli, Coffee, Tea, Devon | Orange | Validations, issues found, QA score |

### Special Agent Pages

| Agent | URL | Purpose |
|-------|-----|---------|
| **ADA** | `/dashboard/agents/ada` | Orchestration hub, approval queue |
| **Marcus** | `/dashboard/crm/marcus` | Lead management, growth intelligence |
| **Sarah** | `/dashboard/agents/sarah` | Sentiment tracking, customer health |
| **Devon** | `/dashboard/agents/devon` | System monitoring, infrastructure |

---

## Architecture Overview

### The Complete Flow

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                     SOLID# AGENTIC ARCHITECTURE                                  │
│                  Orchestrator → Planner → Worker → Critic                        │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  ┌───────────────────────────────────────────────────────────────────────────┐  │
│  │                         1. ORCHESTRATOR (ADA)                              │  │
│  │                         /dashboard/agents/ada                              │  │
│  │  ┌─────────────────────────────────────────────────────────────────────┐  │  │
│  │  │  • Receives incoming requests (user, system, scheduled)              │  │  │
│  │  │  • Routes to appropriate Planner based on task type                  │  │  │
│  │  │  • Manages approval workflows and gates                              │  │  │
│  │  │  • Tracks overall execution and performance                          │  │  │
│  │  │  • Coordinates multi-agent collaboration                             │  │  │
│  │  │  • Handles error recovery and escalation                             │  │  │
│  │  └─────────────────────────────────────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────────────────────────────┘  │
│                                      │                                           │
│                                      ▼                                           │
│  ┌───────────────────────────────────────────────────────────────────────────┐  │
│  │                         2. PLANNER LAYER                                   │  │
│  │  ┌─────────────────────────────────────────────────────────────────────┐  │  │
│  │  │  Task Decomposition Engine                                           │  │  │
│  │  │  • Analyzes complex tasks                                            │  │  │
│  │  │  • Breaks into atomic subtasks                                       │  │  │
│  │  │  • Determines Worker assignments                                     │  │  │
│  │  │  • Creates execution plan with dependencies                          │  │  │
│  │  │  • Estimates resources and time                                      │  │  │
│  │  └─────────────────────────────────────────────────────────────────────┘  │  │
│  │                                                                            │  │
│  │  Planners by Domain:                                                       │  │
│  │  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐     │  │
│  │  │ CRM Planner  │ │ Ops Planner  │ │ KB Planner   │ │ Growth Planner│     │  │
│  │  │ (leads,deals)│ │ (inventory)  │ │ (onboarding) │ │ (marketing)  │     │  │
│  │  └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘     │  │
│  └───────────────────────────────────────────────────────────────────────────┘  │
│                                      │                                           │
│                                      ▼                                           │
│  ┌───────────────────────────────────────────────────────────────────────────┐  │
│  │                         3. WORKER LAYER                                    │  │
│  │  ┌─────────────────────────────────────────────────────────────────────┐  │  │
│  │  │                    DIGITAL LABOR WORKFORCE                           │  │  │
│  │  │                                                                       │  │  │
│  │  │  CORE AGENTS          VEGGIE TEAM           SUPERFOOD AGENTS         │  │  │
│  │  │  ┌─────────────┐     ┌─────────────┐       ┌─────────────┐          │  │  │
│  │  │  │ Sage (chat) │     │ Apple       │       │ Lead Qualifier│         │  │  │
│  │  │  │ Marcus(growth)│    │ Kale        │       │ Task Automator│         │  │  │
│  │  │  │ Devon (ops) │     │ Beet        │       │ Follow-up Bot │         │  │  │
│  │  │  │ Sarah (CS)  │     │ Meat        │       │ Analytics Rep │         │  │  │
│  │  │  │ Jake (inv)  │     │ Potato      │       │ Data Quality  │         │  │  │
│  │  │  │ Alex (fin)  │     │ Broccoli    │       │ Email Optimizer│        │  │  │
│  │  │  │ Maya (brand)│     │ Carrot      │       │ Churn Predictor│        │  │  │
│  │  │  │ Ace (dev)   │     │ + 17 more   │       │ + 12 more     │         │  │  │
│  │  │  └─────────────┘     └─────────────┘       └─────────────────┘       │  │  │
│  │  │                                                                       │  │  │
│  │  │  Workers have access to:                                              │  │  │
│  │  │  • 655 MCP Tools                                                      │  │  │
│  │  │  • Knowledge Base (4-layer)                                           │  │  │
│  │  │  • Database (570 tables)                                              │  │  │
│  │  │  • External LLMs (Claude, GPT-4, Gemini, Grok)                        │  │  │
│  │  └─────────────────────────────────────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────────────────────────────┘  │
│                                      │                                           │
│                                      ▼                                           │
│  ┌───────────────────────────────────────────────────────────────────────────┐  │
│  │                         4. CRITIC LAYER                                    │  │
│  │  ┌─────────────────────────────────────────────────────────────────────┐  │  │
│  │  │  Quality Assurance & Validation                                      │  │  │
│  │  │                                                                       │  │  │
│  │  │  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐                 │  │  │
│  │  │  │ Broccoli     │ │ Coffee       │ │ Tea          │                 │  │  │
│  │  │  │ (KB Validator)│ │(Quality Check)│ │ (Analytics)  │                 │  │  │
│  │  │  └──────────────┘ └──────────────┘ └──────────────┘                 │  │  │
│  │  │                                                                       │  │  │
│  │  │  Critic Functions:                                                    │  │  │
│  │  │  • Reviews Worker outputs for quality                                 │  │  │
│  │  │  • Validates data integrity and completeness                          │  │  │
│  │  │  • Checks business rule compliance                                    │  │  │
│  │  │  • Can REQUEST RE-WORK from Workers                                   │  │  │
│  │  │  • Generates validation reports                                       │  │  │
│  │  │  • Final approval before delivery                                     │  │  │
│  │  └─────────────────────────────────────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────────────────────────────┘  │
│                                      │                                           │
│                                      ▼                                           │
│  ┌───────────────────────────────────────────────────────────────────────────┐  │
│  │                    5. DOWNSTREAM COMPONENTS                                │  │
│  │  ┌─────────────────────────────────────────────────────────────────────┐  │  │
│  │  │  Actions & Scheduled Tasks                                           │  │  │
│  │  │                                                                       │  │  │
│  │  │  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌────────────┐  │  │
│  │  │  │ Celery Tasks │ │ Cron Jobs    │ │ Webhooks     │ │ Events     │  │  │
│  │  │  │ (async)      │ │ (scheduled)  │ │ (outbound)   │ │ (pub/sub)  │  │  │
│  │  │  └──────────────┘ └──────────────┘ └──────────────┘ └────────────┘  │  │
│  │  └─────────────────────────────────────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
```

---

## The Four Pillars

### 1. Orchestrator (ADA)

**UI Location:** `/dashboard/agents/ada`

**File:** `solid-backend/agents/orchestrator.py`

The Orchestrator is the central nervous system of the agent architecture. ADA (Autonomous Data Agent) serves as the master orchestrator.

#### Responsibilities

| Function | Description |
|----------|-------------|
| **Request Reception** | Receives tasks from users, system events, and scheduled triggers |
| **Routing** | Determines which Planner should handle the task |
| **Approval Management** | Enforces approval gates based on cost/impact thresholds |
| **Progress Tracking** | Monitors execution across all agents |
| **Error Recovery** | Handles failures, retries, and escalations |
| **Multi-Agent Coordination** | Orchestrates collaboration between agents |

#### Orchestrator Types

```python
# Three orchestrators handle different scopes

AgentOrchestrator      # General agent lifecycle and execution
ChainOrchestrator      # Multi-step workflow chains with branching
KBOrchestrator         # Food agent coordination for KB onboarding
```

#### Configuration

```python
# Approval Gates (configurable per company)
{
    "customer_contact_requires_approval": True,
    "spend_threshold_usd": 100,
    "data_modification_requires_approval": True,
    "max_cost_per_action": 50.00,
    "max_refund_amount": 100.00
}
```

---

### 2. Planner Layer

**Status:** ✅ IMPLEMENTED (Dec 2025)

**Files:**
- `agents/planner/__init__.py` - Module exports
- `agents/planner/base_planner.py` - BasePlanner, domain planners, PlannerRouter

The Planner layer decomposes complex tasks into atomic subtasks and creates execution plans.

#### Planner Agent Design

```python
# agents/planner/base_planner.py

class BasePlanner:
    """
    Base class for all planning agents.
    Decomposes tasks and creates execution plans.
    """

    async def plan(
        self,
        task: str,
        context: Dict[str, Any],
        constraints: Optional[PlanConstraints] = None
    ) -> ExecutionPlan:
        """
        Decompose a task into an execution plan.

        Args:
            task: Natural language task description
            context: Current business context (company data, user, etc.)
            constraints: Time/cost/resource constraints

        Returns:
            ExecutionPlan with steps, dependencies, and assignments
        """
        pass


@dataclass
class ExecutionPlan:
    """Execution plan created by Planner"""
    plan_id: str
    task: str
    steps: List[PlanStep]
    dependencies: Dict[str, List[str]]  # step_id -> [dependency_ids]
    estimated_duration_seconds: int
    estimated_cost_usd: float
    required_workers: List[str]
    required_tools: List[str]
    priority: str  # critical, high, medium, low
    created_at: datetime


@dataclass
class PlanStep:
    """Single step in an execution plan"""
    step_id: str
    description: str
    worker_type: str  # Which agent handles this
    action: str       # What action to perform
    input_mapping: Dict[str, str]  # Map context to inputs
    output_key: str   # Where to store result
    can_parallel: bool  # Can run in parallel with others
    timeout_seconds: int
```

#### Domain-Specific Planners

| Planner | Domain | Handles |
|---------|--------|---------|
| **CRMPlanner** | Sales/Leads | Lead qualification, deal progression, contact management |
| **OpsPlanner** | Operations | Inventory, orders, fulfillment, scheduling |
| **KBPlanner** | Knowledge | KB population, document generation, learning |
| **GrowthPlanner** | Marketing | Campaigns, content, analytics, A/B tests |
| **FinancePlanner** | Finance | Billing, payments, reporting, compliance |

#### Example: CRM Task Planning

```python
# Input Task: "Qualify all new leads from today and schedule follow-ups"

# CRMPlanner output:
ExecutionPlan(
    plan_id="plan_abc123",
    task="Qualify all new leads from today and schedule follow-ups",
    steps=[
        PlanStep(
            step_id="step_1",
            description="Fetch today's new leads",
            worker_type="data_processor",
            action="fetch_leads",
            input_mapping={"date": "today", "status": "new"},
            output_key="leads_list",
            can_parallel=False,
            timeout_seconds=30
        ),
        PlanStep(
            step_id="step_2",
            description="Score each lead using AI",
            worker_type="lead_qualifier",  # Kale agent
            action="score_leads",
            input_mapping={"leads": "leads_list"},
            output_key="scored_leads",
            can_parallel=True,  # Can process leads in parallel
            timeout_seconds=120
        ),
        PlanStep(
            step_id="step_3",
            description="Create follow-up tasks for hot leads",
            worker_type="task_automator",  # Parsley agent
            action="create_followups",
            input_mapping={"leads": "scored_leads", "threshold": 70},
            output_key="followup_tasks",
            can_parallel=False,
            timeout_seconds=60
        ),
        PlanStep(
            step_id="step_4",
            description="Validate and report results",
            worker_type="critic",  # Broccoli agent
            action="validate_output",
            input_mapping={"tasks": "followup_tasks"},
            output_key="validation_result",
            can_parallel=False,
            timeout_seconds=30
        )
    ],
    dependencies={
        "step_2": ["step_1"],
        "step_3": ["step_2"],
        "step_4": ["step_3"]
    },
    estimated_duration_seconds=240,
    estimated_cost_usd=0.15,
    required_workers=["data_processor", "lead_qualifier", "task_automator", "critic"],
    required_tools=["crm.leads.list", "marcus__score_leads", "crm.tasks.create"],
    priority="medium"
)
```

---

### 3. Worker Layer (Digital Labor Workforce)

**UI Location:** `/dashboard/agents`

The Worker layer consists of specialized agents that execute atomic tasks.

#### Worker Categories

##### Core Agents (Customer-Facing)

| Agent | ID | Type | Primary Function |
|-------|-----|------|------------------|
| **Sage** | 1 | `chat` | Customer conversations, support |
| **Sarah** | 2 | `customer_service` | Sentiment tracking, escalations |
| **Sophia** | 3 | `strategy` | Business intelligence, daily digest |
| **Jake** | 4 | `inventory_manager` | Stock levels, reordering |
| **Marcus** | 5 | `marketing` | Lead scoring, growth intelligence |
| **Alex** | 6 | `finance` | Billing, payments, reporting |
| **Jordan** | 7 | `operations` | Orders, fulfillment, logistics |
| **Maya** | 8 | `brand` | Content, social media, voice |
| **Riley** | 9 | `graphic_designer` | Visual assets, templates |
| **Ace** | 10 | `developer` | Code, deployments, debugging |
| **Devon** | 11 | `devops` | Infrastructure, monitoring |
| **Annie** | 12 | `affiliate_manager` | Commissions, payouts |

##### Veggie Team (KB & Automation)

| Agent | Type | Phase | Function |
|-------|------|-------|----------|
| **Apple** | `industry_detector` | Appetizer | Detect company industry |
| **Kale** | `company_profiler` | Appetizer | Profile company size/needs |
| **Beet** | `analytics_reporter` | Appetizer | Initial analytics setup |
| **Meat** | `template_cloner` | Main Course | Clone industry KB templates |
| **Potato** | `customizer` | Main Course | Customize KB for company |
| **Broccoli** | `kb_validator` | Main Course | **CRITIC** - Validate KB quality |
| **Orange** | `enricher` | Main Course | Enrich KB with external data |
| **French Fries** | `data_mapper` | Sides | Map company data to KB |
| **Carrot** | `followup_automator` | Sides | Create automated follow-ups |
| **Radish** | `data_quality` | Sides | Check data quality |
| **Pepper** | `alert_generator` | Sides | Create proactive alerts |
| **Coffee** | `quality_checker` | Drinks | **CRITIC** - Quality checks ✅ |
| **Juice** | `health_monitor` | Drinks | System health checks ✅ |
| **Tea** | `analytics_validator` | Drinks | **CRITIC** - Validate analytics ✅ |
| **Bubble Tea** | `security_auditor` | Drinks | **CRITIC** - Security audit ✅ |
| **Cake** | `onboarding_guide` | Desserts | User onboarding flows ✅ |
| **Cupcake** | `feature_enabler` | Desserts | Enable features progressively ✅ |
| **Cookie** | `preference_learner` | Desserts | Learn user preferences ✅ |
| **Ice Cream** | `delight_generator` | Desserts | Create delightful experiences ✅ |
| **Dice** | `experimenter` | Toys | A/B experiments ✅ |
| **Target** | `goal_tracker` | Toys | Track business goals ✅ |
| **Game** | `gamification` | Toys | Engagement mechanics ✅ |
| **Easter Egg** | `surprise_generator` | Toys | Hidden features, rewards ✅ |

##### Superfood Agents (Advanced Automation)

| Agent | Type | Function |
|-------|------|----------|
| **Lead Qualifier** | `lead_qualifier` | AI lead scoring and qualification |
| **Task Automator** | `task_automator` | Automatic task creation |
| **Follow-up Automator** | `followup_automator` | Scheduled follow-up sequences |
| **Analytics Reporter** | `analytics_reporter` | Automated reports |
| **Data Quality** | `data_quality` | Data validation and cleanup |
| **Email Optimizer** | `email_optimizer` | Email timing and content |
| **Lead Nurturer** | `lead_nurturer` | Drip campaigns |
| **Pipeline Monitor** | `pipeline_monitor` | Deal health monitoring |
| **E-commerce Optimizer** | `ecommerce_optimizer` | Conversion optimization |
| **Sentiment Analyzer** | `sentiment_analyzer` | Customer sentiment tracking |
| **Churn Predictor** | `churn_predictor` | At-risk customer detection |
| **Upsell Finder** | `upsell_finder` | Cross-sell opportunities |

#### Worker Base Class

```python
# agents/food/base_food_agent.py

class BaseFoodAgent:
    """
    Base class for all worker agents.
    Provides access to MCP tools, KB, database, and LLMs.
    """

    def __init__(self, name: str, agent_type: str, db: Session = None):
        self.name = name
        self.agent_type = agent_type
        self.db = db
        self.company_id = None

    async def execute(
        self,
        phase: str,
        company_id: int,
        company_name: str,
        industry: str,
        user_count: int = 1,
        context: Optional[Dict[str, Any]] = None
    ) -> Dict[str, Any]:
        """Execute agent task for specific phase"""
        pass

    # Tool Access Methods
    async def _kb_search(self, company_id, query, kb_types, limit) -> List[Dict]
    async def _kb_create(self, company_id, title, content, category, ...) -> Dict
    async def _call_mcp_tool(self, tool_name, **kwargs) -> Any
    async def _llm_chat(self, prompt, model, task_type, context) -> str

    # Data Access Methods
    def _get_customers(self, company_id, limit, lifecycle_stage) -> List
    def _get_products(self, company_id, limit) -> List
    def _get_leads(self, company_id, limit) -> List
    def _get_deals(self, company_id, limit, status) -> List
    def _get_sales_metrics(self, company_id) -> Dict
```

---

### 4. Critic Layer

**Status:** ✅ FULLY IMPLEMENTED (Dec 2025)

**Critic Agents (DRINKS Phase):**
- `agents/food/coffee.py` - Quality Checker with re-work loop
- `agents/food/juice.py` - System Health Monitor
- `agents/food/tea.py` - Analytics Validator
- `agents/food/bubble_tea.py` - Security Auditor (multi-tenant isolation)

The Critic layer validates Worker outputs and can request re-work.

#### Critic Functions

| Function | Description |
|----------|-------------|
| **Quality Validation** | Check outputs meet quality standards |
| **Data Integrity** | Verify data completeness and accuracy |
| **Business Rules** | Ensure compliance with business logic |
| **Re-work Request** | Send work back to Workers with feedback |
| **Report Generation** | Create validation and quality reports |
| **Final Approval** | Approve outputs before delivery |

#### Critic Agent Design

```python
# agents/critic/base_critic.py

class BaseCritic:
    """
    Base class for critic agents.
    Reviews worker outputs and provides feedback.
    """

    async def review(
        self,
        worker_output: Dict[str, Any],
        quality_criteria: QualityCriteria,
        context: Dict[str, Any]
    ) -> ReviewResult:
        """
        Review worker output against quality criteria.

        Returns:
            ReviewResult with approval status and feedback
        """
        pass


@dataclass
class QualityCriteria:
    """Quality criteria for validation"""
    min_completeness_score: float = 0.8  # 0-1
    max_error_count: int = 0
    max_warning_count: int = 10
    required_fields: List[str] = field(default_factory=list)
    business_rules: List[BusinessRule] = field(default_factory=list)


@dataclass
class ReviewResult:
    """Result of critic review"""
    review_id: str
    approved: bool
    score: float  # 0-100
    issues: List[Issue]
    warnings: List[Warning]
    rework_required: bool
    rework_instructions: Optional[str]
    report_content: str
    reviewed_at: datetime


@dataclass
class Issue:
    """Critical issue requiring fix"""
    issue_id: str
    severity: str  # critical, high, medium
    description: str
    affected_items: List[str]
    suggested_fix: str
```

#### Re-work Loop

```
┌─────────────────────────────────────────────────────────────────┐
│                     CRITIC RE-WORK LOOP                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Worker Output ──► Critic Review ──► Approved? ──► Yes ──► Done │
│                          │                                       │
│                          ▼                                       │
│                         No                                       │
│                          │                                       │
│                          ▼                                       │
│              Generate Re-work Instructions                       │
│                          │                                       │
│                          ▼                                       │
│              Send Back to Worker with Feedback                   │
│                          │                                       │
│                          ▼                                       │
│              Worker Re-executes with Guidance                    │
│                          │                                       │
│                          ▼                                       │
│              (Loop back to Critic Review)                        │
│                                                                  │
│  Max Retries: 3 (then escalate to human)                        │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

#### Current Critic Agents (DRINKS Phase)

| Agent | File | Function | Status |
|-------|------|----------|--------|
| **Broccoli** | `agents/food/broccoli.py` | KB validation, data coverage | ✅ Implemented |
| **Coffee** | `agents/food/coffee.py` | Quality checks, re-work loop | ✅ Implemented |
| **Juice** | `agents/food/juice.py` | System health monitoring | ✅ Implemented |
| **Tea** | `agents/food/tea.py` | Analytics validation, completeness | ✅ Implemented |
| **Bubble Tea** | `agents/food/bubble_tea.py` | Security audit, tenant isolation | ✅ Implemented |

---

## Digital Labor Workforce

The Digital Labor Workforce is a subset of agents that **parse data → execute workflows → convert to downstream actions**.

Each agent in the workforce has its own **Agent Card** at `/dashboard/agents`.

### The Data → Workflow → Action Pipeline

```
┌─────────────────────────────────────────────────────────────────────────────┐
│              DIGITAL LABOR WORKFORCE - DATA TO ACTION PIPELINE              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  LAYER 1: DATA PARSING (Agent Cards: French Fries, Radish, Orange)          │
│  ═══════════════════════════════════════════════════════════════            │
│                                                                              │
│  Input Sources          Parser Agents           Output                       │
│  ┌──────────────┐      ┌──────────────┐       ┌──────────────┐              │
│  │ • CSV Upload │      │ French Fries │       │ Mapped       │              │
│  │ • JSON API   │─────►│ (data_mapper)│──────►│ Records      │              │
│  │ • Webhook    │      │              │       │              │              │
│  │ • Form Data  │      │ Radish       │       │ Clean        │              │
│  │ • Email Parse│─────►│ (data_quality)──────►│ Data         │              │
│  └──────────────┘      │              │       │              │              │
│                        │ Orange       │       │ AI-Enhanced  │              │
│                        │ (enricher)───│──────►│ Records      │              │
│                        └──────────────┘       └──────────────┘              │
│                                │                                             │
│                                ▼                                             │
│  LAYER 2: WORKFLOW EXECUTION (Agent Cards: ADA, ChainOrchestrator)          │
│  ═══════════════════════════════════════════════════════════════            │
│                                                                              │
│  Orchestrator           Chain Execution         Result                       │
│  ┌──────────────┐      ┌──────────────┐       ┌──────────────┐              │
│  │ ADA          │      │ Step 1       │       │              │              │
│  │ (routes to   │─────►│    ↓         │       │ Step         │              │
│  │  planner)    │      │ Step 2       │──────►│ Results      │              │
│  │              │      │    ↓         │       │              │              │
│  │ Chain/KB     │      │ Step 3       │       │ Decisions    │              │
│  │ Orchestrator │─────►│ (parallel)   │──────►│ Made         │              │
│  └──────────────┘      └──────────────┘       └──────────────┘              │
│                                │                                             │
│                                ▼                                             │
│  LAYER 3: ACTION CONVERSION (Downstream Components)                          │
│  ═══════════════════════════════════════════════════════════════            │
│                                                                              │
│  Decision               Action Type            Downstream File               │
│  ┌──────────────┐      ┌──────────────┐       ┌──────────────────────┐      │
│  │"Send email   │      │ Celery Task  │       │ tasks/email_tasks.py │      │
│  │ to lead"     │─────►│ (async)      │──────►│ → Sends email        │      │
│  │              │      └──────────────┘       └──────────────────────┘      │
│  │"Score leads  │      ┌──────────────┐       ┌──────────────────────┐      │
│  │ nightly"     │─────►│ Cron Job     │──────►│ jobs/daily_lead_     │      │
│  │              │      │ (scheduled)  │       │   scoring.py         │      │
│  │              │      └──────────────┘       └──────────────────────┘      │
│  │"Notify       │      ┌──────────────┐       ┌──────────────────────┐      │
│  │ Zapier"      │─────►│ Webhook      │──────►│ webhook_delivery_    │      │
│  │              │      │ (HTTP POST)  │       │   service.py         │      │
│  │              │      └──────────────┘       └──────────────────────┘      │
│  │"Alert team"  │      ┌──────────────┐       ┌──────────────────────┐      │
│  │              │─────►│ Event Bus    │──────►│ redis_event_bus.py   │      │
│  │              │      │ (pub/sub)    │       │ → Real-time notify   │      │
│  └──────────────┘      └──────────────┘       └──────────────────────┘      │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

### Workforce Agent → Agent Card Mapping

| Layer | Agent Name | Agent Card URL | Type | Function |
|-------|------------|----------------|------|----------|
| **DATA** | French Fries | `/dashboard/agents/french-fries` | `data_mapper` | Parse & map incoming data |
| **DATA** | Radish | `/dashboard/agents/radish` | `data_quality` | Validate & clean data |
| **DATA** | Orange | `/dashboard/agents/orange` | `enricher` | AI-enhance records |
| **WORKFLOW** | ADA | `/dashboard/agents/ada` | `orchestrator` | Route & coordinate |
| **WORKFLOW** | ChainOrch | `/dashboard/agents/chains` | `planner` | Execute multi-step flows |
| **WORKFLOW** | KBOrch | (internal) | `planner` | KB onboarding flows |
| **ACTION** | Parsley | `/dashboard/agents/parsley` | `task_automator` | Create downstream tasks |
| **ACTION** | Carrot | `/dashboard/agents/carrot` | `followup_automator` | Schedule follow-ups |
| **ACTION** | Beet | `/dashboard/agents/beet` | `analytics_reporter` | Generate reports |

### Downstream Components (Cron Jobs & Celery Tasks)

| Component | File | Trigger | Purpose |
|-----------|------|---------|---------|
| **Daily Lead Scoring** | `jobs/daily_lead_scoring.py` | Cron 2 AM | Score all leads with AI |
| **Subscription Billing** | `tasks/auto_billing_cron.py` | Cron 3 AM | Process subscriptions |
| **Backup Scheduler** | `jobs/backup_scheduler.py` | Cron 4 AM | Database backups |
| **Email Tasks** | `tasks/email_tasks.py` | Celery queue | Send transactional emails |
| **Notification Tasks** | `tasks/notification_tasks.py` | Celery queue | Push notifications |
| **KB Onboarding** | `tasks/kb_onboarding.py` | On signup | Populate KB for new company |
| **KB Learning** | `tasks/kb_learning.py` | Nightly | Continuous KB improvement |
| **Data Processing** | `tasks/data_processing.py` | On import | Process uploaded data |
| **Post-Import Agents** | `tasks/post_import_agents.py` | After import | Kale→Potato→Fries→Meat→Matching |
| **Report Generation** | `tasks/report_generation.py` | On demand | Generate reports |
| **Billing Tasks** | `tasks/billing_tasks.py` | Event-driven | Process billing events |
| **Auto Billing Cron** | `tasks/auto_billing_cron.py` | Scheduled | Automated billing |
| **Affiliate Tasks** | `tasks/affiliate_tasks.py` | Monthly | Commission calculations |

### Event Bus Integration

```python
# infra/redis_event_bus.py - Events that trigger downstream actions

EVENTS = {
    # Lead events → Marcus intelligence
    "lead.created": ["lead_qualifier", "kb_learner"],
    "lead.scored": ["notification", "crm_update"],

    # Deal events → Pipeline monitoring
    "deal.stage_changed": ["pipeline_monitor", "notification"],
    "deal.won": ["commission_calc", "celebration"],

    # Customer events → Sarah support
    "customer.sentiment_low": ["sarah_alert", "manager_notify"],
    "customer.feedback": ["kb_learner", "sentiment_analyzer"],

    # Inventory events → Jake management
    "inventory.low_stock": ["jake_reorder", "email_alert"],
    "inventory.received": ["notification", "stock_update"],

    # Agent events → ADA coordination
    "agent.action_completed": ["telemetry", "roi_tracker"],
    "agent.approval_needed": ["notification", "email"],
    "agent.error": ["devon_alert", "log_incident"],
}
```

---

## User Workflow Management (Per Agent)

Each agent has a configurable workflow that runs "behind the scenes." Users can tweak these via the **Agent Detail Page** at `/dashboard/agents/[id]`.

### What Users Can Configure

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                    AGENT SETTINGS TABS                                       │
│                    /dashboard/agents/[id]                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  [Overview] [Tools] [Activity] [Conversations] [Settings]                    │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ SETTINGS TAB - Fully Implemented ✅                                  │   │
│  │                                                                       │   │
│  │  1. AUTONOMY LEVEL (0-5 Slider)                                      │   │
│  │     └── 0 = Manual Only (requires approval for every action)         │   │
│  │     └── 1 = Minimal (only responds to direct queries)                │   │
│  │     └── 2 = Low (asks before taking actions)                         │   │
│  │     └── 3 = Moderate (acts on routine, asks on significant)          │   │
│  │     └── 4 = High (acts independently, reports afterward)             │   │
│  │     └── 5 = Full Autonomy (complete independence)                    │   │
│  │                                                                       │   │
│  │  2. MASTER PROMPT                                                    │   │
│  │     └── Core identity, personality, primary mission                  │   │
│  │                                                                       │   │
│  │  3. SYSTEM INSTRUCTIONS                                              │   │
│  │     └── Detailed workflows, step-by-step processes                   │   │
│  │     └── Decision-making frameworks                                   │   │
│  │                                                                       │   │
│  │  4. JOB NOTES & TRICKS                                               │   │
│  │     └── Business rules, escalation paths                             │   │
│  │     └── Edge cases, domain knowledge                                 │   │
│  │                                                                       │   │
│  │  5. LLM MODEL SELECTOR                                               │   │
│  │     └── Claude 4.5 Sonnet (Recommended)                              │   │
│  │     └── Claude Sonnet 4.6                                            │   │
│  │     └── GPT-4o, GPT-4o Mini                                          │   │
│  │     └── Grok 2, Grok 3                                               │   │
│  │                                                                       │   │
│  │  6. AI BEHAVIOR                                                      │   │
│  │     └── Temperature slider (0.0-2.0) - creativity level              │   │
│  │     └── Max tokens (100-16K) - response length                       │   │
│  │                                                                       │   │
│  │  7. CUSTOM INSTRUCTIONS                                              │   │
│  │     └── Additional rules prepended to system prompt                  │   │
│  │     └── "Always be concise" / "Prioritize satisfaction"              │   │
│  │                                                                       │   │
│  │  8. CONDITIONAL ROLES (If/Then Rules) ✅                             │   │
│  │     └── IF user_role is customer THEN be empathetic                  │   │
│  │     └── IF refund > $100 THEN request approval                       │   │
│  │     └── IF sentiment is negative THEN escalate to supervisor         │   │
│  │                                                                       │   │
│  │  9. TOYS SETTINGS (Engagement Features) ✅                           │   │
│  │     └── Gamification: Points per interaction, badge announcements    │   │
│  │     └── Goal Tracking: Set targets for conversations, satisfaction   │   │
│  │     └── A/B Testing: Create experiments with variant prompts         │   │
│  │                                                                       │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ TOOLS TAB - Tool Enable/Disable ✅                                   │   │
│  │                                                                       │   │
│  │  • Individual toggle for each MCP tool                               │   │
│  │  • Category-level toggles (CRM, Marketing, Platform)                 │   │
│  │  • Search bar to find specific tools                                 │   │
│  │  • "Enable All" / "Disable All" buttons                              │   │
│  │  • Stats: Total tools, enabled count, disabled count                 │   │
│  │  • Disabled tools won't be available during conversations            │   │
│  │                                                                       │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

### Per-Agent Configuration Matrix

| Setting | Location | What User Controls | Backend Field |
|---------|----------|-------------------|---------------|
| **Autonomy Level** | Settings Tab | Independence 0-5 slider | `agent.autonomy_level` |
| **Master Prompt** | Settings Tab | Core personality & mission | `agent.settings.master_prompt` |
| **System Instructions** | Settings Tab | Workflows & processes | `agent.settings.system_prompt` |
| **Job Notes** | Settings Tab | Business rules & edge cases | `agent.settings.job_notes` |
| **LLM Model** | Settings Tab | Claude, GPT-4, Grok selector | `agent.llm_model` |
| **Temperature** | Settings Tab | Creativity 0.0-2.0 slider | `agent.llm_config.temperature` |
| **Max Tokens** | Settings Tab | Response length 100-16K | `agent.llm_config.max_tokens` |
| **Custom Instructions** | Settings Tab | Extra rules | `agent.settings.custom_instructions` |
| **Conditional Rules** | Settings Tab | IF/THEN behavior rules | `agent.settings.conditional_rules` |
| **Tool Toggles** | Tools Tab | Enable/disable each tool | `agent.settings.disabled_tools` |
| **Gamification** | Settings Tab | Points, badges, announcements | `agent.settings.gamification` |
| **Goal Tracking** | Settings Tab | Targets & metrics | `agent.settings.goals` |
| **A/B Testing** | Settings Tab | Experiments, variants, splits | `agent.settings.ab_testing` |
| **Enable/Disable** | Card Toggle | On/Off | `agent.is_enabled` |

### Workflow Chains (Multi-Step)

Users can create and manage chains at `/dashboard/agents/chains`:

```
┌─────────────────────────────────────────────────────────────────────────────┐
│  CHAINS - Multi-Step Workflows                                               │
│  /dashboard/agents/chains                                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  Chain: "New Lead Qualification"                    Status: ● Active         │
│  ─────────────────────────────────────────────────────────────────────      │
│                                                                              │
│  TRIGGER: When lead.created event fires                                     │
│       │                                                                      │
│       ▼                                                                      │
│  ┌─────────────┐                                                            │
│  │ Step 1      │  Agent: Kale (Lead Qualifier)                              │
│  │ Score Lead  │  Action: marcus__score_leads                               │
│  │             │  Timeout: 30s                                              │
│  └──────┬──────┘                                                            │
│         │                                                                    │
│         ▼                                                                    │
│  ┌─────────────┐                                                            │
│  │ Step 2      │  Condition: IF score > 70                                  │
│  │ Check Score │  TRUE → Step 3 | FALSE → Step 4                            │
│  └──────┬──────┘                                                            │
│         │                                                                    │
│    ┌────┴────┐                                                              │
│    ▼         ▼                                                              │
│  ┌─────┐  ┌─────┐                                                           │
│  │ 3   │  │ 4   │  Hot Lead: Create task + notify                           │
│  │ Hot │  │ Cold│  Cold Lead: Add to nurture sequence                       │
│  └─────┘  └─────┘                                                           │
│                                                                              │
│  Stats: 234 runs | 96% success | Avg 45s                                    │
│                                                                              │
│  [Edit] [Pause] [Duplicate] [Delete]                                        │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

### Chain Building Options

| Step Type | What It Does | User Configures |
|-----------|--------------|-----------------|
| **Agent Step** | Run an agent action | Agent, action, timeout, retries |
| **Condition** | Branch based on result | IF condition, true/false paths |
| **Parallel** | Run agents simultaneously | Agents list, wait strategy |
| **Wait** | Pause execution | Duration or event to wait for |
| **Approval** | Request human approval | Approvers, message, timeout |
| **Loop** | Repeat steps | Condition, max iterations |

### Triggers

| Trigger | When It Fires | Example |
|---------|--------------|---------|
| **Event** | When system event occurs | `lead.created`, `deal.won` |
| **Schedule** | Cron-based timing | `0 2 * * *` (daily 2 AM) |
| **Manual** | User clicks "Run" | On-demand execution |

### Approval Gates (Per Company)

Users configure at `/dashboard/agents` → Approval Gates:

```
┌─────────────────────────────────────────────────────────────────────────────┐
│  APPROVAL GATES                                                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  [✓] Customer contact requires approval                                      │
│  [✓] Data modification requires approval                                     │
│                                                                              │
│  Spend threshold: $______100______ USD                                       │
│                                                                              │
│  When agents hit these limits, they request approval before acting.          │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

### Data Governance

Users configure at `/dashboard/agents/governance`:

| Control | What User Sets |
|---------|---------------|
| **Data Classification** | Mark fields as PII, Confidential, Internal |
| **Access Masking** | Which fields masked for external AI |
| **Cross-AI Firewall** | Block data flow between platforms |
| **Consent Tracking** | Customer consent for AI processing |

### Agent-Specific Features

| Agent | Special Settings | Location |
|-------|-----------------|----------|
| **Sarah** | Sentiment threshold, Response SLA, Auto-draft follow-ups | Settings Tab |
| **Marcus** | Lead scoring rules, Segment definitions | `/crm/marcus` |
| **Jake** | Reorder thresholds, Stock alerts | Settings Tab |
| **Devon** | Monitoring intervals, Alert thresholds | Settings Tab |

---

## Key Agent Pages

### Marcus Lead Manager

**URL:** `https://app.solidnumber.com/dashboard/crm/marcus`

```
┌─────────────────────────────────────────────────────────────────────────────┐
│  MARCUS - Growth Intelligence                                    [Settings] │
│  AI-Powered Lead Management & Sales Intelligence                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ HOT LEADS                                               [View All →] │   │
│  │                                                                       │   │
│  │ ┌────────────────────────────────────────────────────────────────┐  │   │
│  │ │ John Smith                           Score: 92 ████████████░   │  │   │
│  │ │ ABC Corp | Enterprise | $50,000                                 │  │   │
│  │ │ 🔥 High engagement | Opened 5 emails | Visited pricing page    │  │   │
│  │ │ [Email] [Call] [Schedule]                                       │  │   │
│  │ └────────────────────────────────────────────────────────────────┘  │   │
│  │                                                                       │   │
│  │ ┌────────────────────────────────────────────────────────────────┐  │   │
│  │ │ Sarah Johnson                        Score: 87 ███████████░░   │  │   │
│  │ │ XYZ Inc | Mid-Market | $25,000                                  │  │   │
│  │ │ ⚡ Quick response | Demo requested                              │  │   │
│  │ │ [Email] [Call] [Schedule]                                       │  │   │
│  │ └────────────────────────────────────────────────────────────────┘  │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ AI INSIGHTS                                                          │   │
│  │                                                                       │   │
│  │ 🎯 OPPORTUNITY: 3 leads showing buying signals this week            │   │
│  │ ⚠️ RISK: 2 deals stalled >14 days - recommend follow-up             │   │
│  │ 📈 TREND: Email open rates up 15% with new subject lines            │   │
│  │ 💡 ACTION: Schedule calls with high-intent leads before EOD         │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## Downstream Components

### Celery Tasks

**Directory:** `solid-backend/tasks/`

| Task File | Purpose | Trigger |
|-----------|---------|---------|
| `ai_dream_jobs.py` | AI background processing | Agent request |
| `data_processing.py` | Import/export processing | File upload |
| `email_tasks.py` | Email sending | Agent action |
| `notification_tasks.py` | Push notifications | Events |
| `billing_tasks.py` | Billing operations | Schedule/event |
| `kb_onboarding.py` | KB population | Company signup |
| `kb_learning.py` | KB continuous learning | Nightly |
| `affiliate_tasks.py` | Commission calculations | Monthly |
| `report_generation.py` | Report creation | Schedule/request |
| `self_optimizing_workflows.py` | Workflow optimization | Continuous |
| `predictive_scheduling.py` | Schedule optimization | Nightly |
| `auto_billing_cron.py` | Automated billing | Cron |

### Cron Jobs

**File:** `solid-backend/jobs/`

| Job | Schedule | Function |
|-----|----------|----------|
| `daily_lead_scoring.py` | Daily 2 AM | Score all leads |
| `subscription_billing.py` | Daily 3 AM | Process subscriptions |
| `backup_scheduler.py` | Daily 4 AM | Database backups |

### Event Bus

**File:** `solid-backend/infra/redis_event_bus.py`

```python
# Event types that trigger downstream actions
EVENTS = {
    "lead.created": ["lead_qualifier", "kb_learner"],
    "deal.stage_changed": ["pipeline_monitor", "notification"],
    "customer.sentiment_low": ["sarah_alert", "manager_notify"],
    "inventory.low_stock": ["jake_reorder", "email_alert"],
    "agent.action_completed": ["telemetry", "roi_tracker"],
    "agent.approval_needed": ["notification", "email"],
}
```

### Workflow Integration

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                    AGENT → ACTION FLOW                                       │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  Agent Decision                                                              │
│       │                                                                      │
│       ▼                                                                      │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ Action Type Router                                                   │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│       │                                                                      │
│       ├──► IMMEDIATE → Execute directly (DB write, API call)                │
│       │                                                                      │
│       ├──► ASYNC → Queue Celery task                                        │
│       │         └──► tasks/email_tasks.py                                   │
│       │         └──► tasks/notification_tasks.py                            │
│       │                                                                      │
│       ├──► SCHEDULED → Create cron job                                      │
│       │         └──► jobs/daily_lead_scoring.py                             │
│       │         └──► tasks/auto_billing_cron.py                           │
│       │                                                                      │
│       ├──► EVENT → Publish to Redis                                         │
│       │         └──► infra/redis_event_bus.py                               │
│       │                                                                      │
│       └──► WEBHOOK → HTTP POST to external                                  │
│                 └──► services/integrations/webhook_delivery_service.py      │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## Implementation Status

### System Overview

| Component | Status | Implementation | Agent Cards |
|-----------|--------|----------------|-------------|
| **Orchestrator** | ✅ LIVE | ADA + 3 orchestrator types | `/dashboard/agents/ada` |
| **Planner** | ✅ IMPLEMENTED | BasePlanner + 4 domain planners + PlannerRouter | `/dashboard/agents/chains` |
| **Workers** | ✅ LIVE | 72 agent modules (all 24 Food Agents complete) | `/dashboard/agents` |
| **Critic** | ✅ IMPLEMENTED | Coffee, Juice, Tea, BubbleTea (full DRINKS phase) | In agent cards |
| **Downstream** | ✅ LIVE | 12 Celery tasks, 3 cron jobs | Background |

### Food Fight Phase Status (Dec 2025)

| Phase | Agents | Status | Purpose |
|-------|--------|--------|---------|
| **APPETIZER** | Apple, Kale, Beet | ✅ Complete | Industry detection, company profiling |
| **MAIN COURSE** | Meat, Potato, Broccoli, Orange | ✅ Complete | KB cloning, customization, validation |
| **SIDES** | Fries, Carrot, Radish, Pepper | ✅ Complete | Data mapping, follow-ups, quality |
| **DRINKS** | Coffee, Juice, Tea, BubbleTea | ✅ Complete | Critics - quality, health, analytics, security |
| **DESSERTS** | Cake, Cupcake, Cookie, IceCream | ✅ Complete | Onboarding, features, preferences, delight |
| **TOYS** | Dice, Target, Game, EasterEgg | ✅ Complete | A/B testing, goals, gamification, surprises |

### Metrics (as of Dec 2025)

| Metric | Count |
|--------|-------|
| **Total Agent Modules** | 72 |
| **MCP Tools Available** | 229 |
| **Active Chains/Workflows** | 15+ templates |
| **Celery Task Types** | 12 |
| **Scheduled Jobs** | 3 |
| **LLM Providers** | 7 |

### Pattern Compliance

```
ORCHESTRATOR → PLANNER → WORKER → CRITIC
     ✅            ✅         ✅        ✅

ADA           Chain/KB     72 Agents   Broccoli/Devon
              Orchestrators             + QA checks
```

### Recent Implementations (Dec 2025)

#### Backend

| Feature | Implementation | Files |
|---------|---------------|-------|
| **Re-work Loop** | Coffee agent has full re-work capability | `agents/food/coffee.py` |
| **Planner Layer** | 4 domain planners + router | `agents/planner/base_planner.py` |
| **Security Auditor** | Multi-tenant isolation checks | `agents/food/bubble_tea.py` |
| **Gamification** | Points, badges, leaderboards | `agents/food/game.py` |
| **A/B Testing** | Experiment framework | `agents/food/dice.py` |
| **Unit Tests** | 41 tests for new agents + planner | `tests/unit/test_toys_desserts_drinks_agents.py` |

#### Frontend (Agent Settings UI)

| Feature | Implementation | Component |
|---------|---------------|-----------|
| **Autonomy Slider** | 6-level slider (0-5) with descriptions | `AutonomySettings` |
| **LLM Model Selector** | Dropdown with Claude, GPT-4, Grok models | `LLMSettings` |
| **Tool Enable/Disable** | Per-tool toggles, category toggles, search | `AgentToolsTab` |
| **Conditional Roles** | IF/THEN rule builder, add/remove rules | `ConditionalRoles` |
| **TOYS Settings** | Gamification, goal tracking, A/B testing | `ToysSettings` |

**File:** `solid-frontend/src/app/(main)/dashboard/agents/[id]/page.tsx`

### Enhancement Features (Dec 2025) ✅

All enhancement opportunities have been implemented:

| Feature | Status | Location |
|---------|--------|----------|
| **Plan Visualization** | ✅ LIVE | `/dashboard/agents/chains` → Live tab |
| **Critic Dashboard** | ✅ LIVE | `/dashboard/agents/critics` |
| **Worker Analytics** | ✅ LIVE | `/dashboard/agents/analytics` |

#### Plan Visualization (`/chains` → Live tab)
- Real-time step-by-step execution view
- Shows running/waiting/completed steps with animations
- Inline approval actions for waiting steps
- Color-coded status indicators

#### Critic Dashboard (`/critics`)
- Unified view of all 4 critic agents (Coffee, Juice, Tea, BubbleTea)
- Approval/rejection/rework stats per critic
- Review history with search and filters
- Rework queue with attempt tracking

#### Worker Analytics (`/analytics`)
- Cross-agent performance comparison table
- Sort by actions, success rate, speed, cost
- Domain breakdown view
- Top performers leaderboard
- Trend indicators (improving/needs attention)

---

## Next Sprint: Vibe Coding Integration

> **Vibe Coding runs ON the Agent Architecture**
>
> Every vibe request flows through: Orchestrator → Planner → Worker → Critic

### What is Vibe Coding?

Vibe Coding is a natural language interface for business owners to modify their system:
- "Add a deep cleaning service for $150"
- "Update the cancellation policy to 48 hours"
- "Create a landing page for summer sale"

**Rule #1: Vibe coding can NEVER delete data. Ever.**

### Agent Integration Map

| Vibe Function | Agent | Role |
|---------------|-------|------|
| **Safety Check** | BubbleTea | Block DELETE/DROP/TRUNCATE |
| **Routing** | ADA | Route to correct Planner |
| **Planning** | Domain Planners | Decompose into atomic tasks |
| **Validation** | Radish | Validate input data |
| **Execution** | Potato, Meat, Maya | Create/modify entities |
| **Quality Check** | Coffee | Review output quality |
| **Security Audit** | BubbleTea | Final security check |

### New Vibe Agents (To Build)

| Agent | Type | Function |
|-------|------|----------|
| **Vibe** | `vibe_executor` | Main vibe coding engine |
| **Undo** | `rollback_agent` | Execute rollback operations |
| **Preview** | `preview_generator` | Generate change previews |
| **Differ** | `diff_generator` | Create before/after diffs |

### Vibe Flow Through Agents

```
USER: "Add cleaning service for $150"
         │
         ▼
    BubbleTea ──► Safety check (ALLOWED: create action)
         │
         ▼
       ADA ──► Route to OpsPlanner
         │
         ▼
   OpsPlanner ──► Create ExecutionPlan
         │
         ▼
    Workers ──► Radish (validate) → Potato (create)
         │
         ▼
     Coffee ──► Quality review (APPROVED)
         │
         ▼
  VibeHistory ──► Log state_before/state_after
```

### Safety Enforcement (3 Layers)

```
Request → BubbleTea → Workers → Coffee → BubbleTea
              │                    │          │
              └────── NO DELETE ───┴──────────┘
```

### Files to Create

```
solid-backend/
├── services/vibe/
│   ├── vibe_engine.py          # Main engine
│   ├── vibe_safety.py          # Safety rules
│   ├── vibe_permissions.py     # Permission checking
│   └── vibe_history.py         # History & rollback
├── agents/planner/
│   └── vibe_planner.py         # Vibe-specific planning
└── agents/food/
    ├── vibe.py                 # Vibe executor agent
    ├── undo.py                 # Rollback agent
    ├── preview.py              # Preview generator
    └── differ.py               # Diff generator
```

**Full Documentation:** [22-Licensing/VIBE-CODING-ARCHITECTURE.md](../22-Licensing/VIBE-CODING-ARCHITECTURE.md)

---

## File Reference

### Core Agent Files

```
solid-backend/
├── agents/
│   ├── orchestrator.py              # Main orchestrator
│   ├── chains/
│   │   └── orchestrator.py          # Chain orchestrator
│   ├── kb_orchestrator.py           # KB food agent orchestrator
│   ├── registry.py                  # Agent definitions (100+ types)
│   ├── planner/                     # NEW: Planner layer
│   │   ├── __init__.py              # Module exports
│   │   └── base_planner.py          # BasePlanner, domain planners, PlannerRouter
│   ├── food/
│   │   ├── base_food_agent.py       # Worker base class
│   │   ├── apple.py                 # Industry detector
│   │   ├── kale.py                  # Company profiler
│   │   ├── broccoli.py              # KB validator (CRITIC)
│   │   ├── coffee.py                # Quality checker (CRITIC) - with re-work loop
│   │   ├── juice.py                 # Health monitor (CRITIC)
│   │   ├── tea.py                   # Analytics validator (CRITIC)
│   │   ├── bubble_tea.py            # Security auditor (CRITIC)
│   │   ├── cake.py                  # Onboarding guide
│   │   ├── cupcake.py               # Feature enabler
│   │   ├── cookie.py                # Preference learner
│   │   ├── ice_cream.py             # Delight generator
│   │   ├── dice.py                  # A/B experimenter
│   │   ├── target.py                # Goal tracker
│   │   ├── game.py                  # Gamification engine
│   │   ├── easter_egg.py            # Surprise generator
│   │   └── ... (24 agents total)
│   ├── vegetable_team.py            # KB learning agents
│   ├── memory/
│   │   ├── short_term.py            # Session memory
│   │   ├── medium_term.py           # Pattern memory
│   │   ├── long_term.py             # Persistent memory
│   │   └── cross_agent.py           # Inter-agent signals
│   └── llm/
│       ├── factory.py               # LLM provider factory
│       ├── anthropic_provider.py    # Claude
│       └── openai_provider.py       # GPT-4
├── tasks/
│   ├── ai_dream_jobs.py             # AI background jobs
│   ├── data_processing.py           # Import/export
│   ├── email_tasks.py               # Email sending
│   ├── kb_onboarding.py             # KB population
│   ├── post_import_agents.py        # Post-import: Kale, Potato, Fries, Meat, Matching
│   └── ... (13 task files)
├── jobs/
│   ├── daily_lead_scoring.py        # Lead scoring cron
│   ├── subscription_billing.py      # Billing cron
│   └── backup_scheduler.py          # Backup cron
└── workers/
    ├── kale_lead_qualifier.py       # Lead qualification
    ├── carrot_followup.py           # Follow-up automation
    ├── radish_data_quality.py       # Data quality
    └── ... (automation workers)
```

### Frontend Agent Files

```
solid-frontend/
└── src/
    └── app/(main)/dashboard/
        ├── agents/
        │   ├── page.tsx                    # Main agent list (card grid)
        │   ├── [id]/
        │   │   ├── page.tsx               # Agent detail + settings
        │   │   │   ├── AutonomySettings   # 0-5 slider component
        │   │   │   ├── LLMSettings        # Model selector + temp/tokens
        │   │   │   ├── MasterPrompt       # Prompt configuration
        │   │   │   ├── CustomInstructions # Additional rules
        │   │   │   ├── ConditionalRoles   # IF/THEN rule builder
        │   │   │   └── ToysSettings       # Gamification, goals, A/B
        │   │   ├── chat/page.tsx          # Agent chat interface
        │   │   └── _components/
        │   │       └── agent-tools-tab.tsx # Tool enable/disable UI
        │   └── (agent-pages)/
        │       ├── analytics/page.tsx     # Worker metrics comparison
        │       ├── approvals/page.tsx     # Approval queue
        │       ├── audit/page.tsx         # Audit trail
        │       ├── chains/page.tsx        # Workflow chains + Live tab
        │       ├── critics/page.tsx       # Critic dashboard
        │       └── governance/page.tsx    # Settings
        ├── crm/
        │   └── marcus/page.tsx            # Marcus lead manager
        └── assistant/
            └── ai-workflow/page.tsx       # Workflow visualization
```

---

## Related Documentation

| Document | Location | Description |
|----------|----------|-------------|
| AI Infrastructure | `03-AI-Systems/AI-INFRASTRUCTURE.md` | Budget, routing, analytics |
| Agent Controls | `03-AI-Systems/agent-controls.md` | Pause/unpause, approval gates |
| MCP Tools | `03-AI-Systems/mcp-chat-ai-to-ai.md` | Tool catalog and AI-to-AI |
| Food Agents Summary | `solid-backend/FOOD_AGENTS_SUMMARY.md` | 24 agent details |
| Chain Templates | `agents/chains/templates.py` | Pre-built workflow chains |
| Agent Unit Tests | `tests/unit/test_toys_desserts_drinks_agents.py` | 41 tests for new agents |

---

## Summary

### Solid# Implements the Full Orchestrator → Planner → Worker → Critic Pattern

```
┌────────────────────────────────────────────────────────────────────────────┐
│                         SOLID# AGENT ARCHITECTURE                           │
├────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐  │
│  │ ORCHESTRATOR: ADA          │ /dashboard/agents/ada                   │  │
│  │ Routes requests, manages approvals, coordinates multi-agent work     │  │
│  └──────────────────────────────────┬──────────────────────────────────┘  │
│                                     ▼                                      │
│  ┌─────────────────────────────────────────────────────────────────────┐  │
│  │ PLANNER: ChainOrchestrator  │ /dashboard/agents/chains               │  │
│  │ Decomposes tasks, creates execution plans, manages dependencies      │  │
│  └──────────────────────────────────┬──────────────────────────────────┘  │
│                                     ▼                                      │
│  ┌─────────────────────────────────────────────────────────────────────┐  │
│  │ WORKERS: 72 Agents          │ /dashboard/agents                      │  │
│  │ Marcus (growth), Sarah (CS), Jake (inventory), Devon (ops), etc.     │  │
│  │ + 24 Veggie Team automation agents                                   │  │
│  └──────────────────────────────────┬──────────────────────────────────┘  │
│                                     ▼                                      │
│  ┌─────────────────────────────────────────────────────────────────────┐  │
│  │ CRITIC: Broccoli, Devon     │ In agent cards                         │  │
│  │ Validates outputs, monitors quality, can request re-work             │  │
│  └──────────────────────────────────┬──────────────────────────────────┘  │
│                                     ▼                                      │
│  ┌─────────────────────────────────────────────────────────────────────┐  │
│  │ DOWNSTREAM: Celery + Cron   │ tasks/*.py, jobs/*.py                  │  │
│  │ Executes actions: emails, notifications, billing, reports            │  │
│  └─────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
└────────────────────────────────────────────────────────────────────────────┘
```

### Key URLs

| Page | URL | Purpose |
|------|-----|---------|
| All Agents | `https://app.solidnumber.com/dashboard/agents` | Agent card grid |
| ADA (Orchestrator) | `https://app.solidnumber.com/dashboard/agents/ada` | Orchestration hub |
| Marcus (Growth) | `https://app.solidnumber.com/dashboard/crm/marcus` | Lead management |
| Chains (Planner) | `https://app.solidnumber.com/dashboard/agents/chains` | Workflow builder |
| Approvals | `https://app.solidnumber.com/dashboard/agents/approvals` | Approval queue |

### Every Agent = One Card

Each of the 72 agent modules is manageable through its own **Agent Card** in the UI:
- Toggle on/off
- Adjust autonomy level (0-5)
- View metrics (actions, success rate, cost)
- Chat directly
- Configure settings

---

_Part of Owners Manual documentation suite_
_Maintained by: Platform Team_


--- FILE: 03-AI-Systems/AGENT-CONTROLS.md ---

---
topic: ai-systems
keywords: [AI, agents, MCP, SmartRouter, LLM, orchestration, knowledge-base]
code_paths:
  - agents/*.py
  - solid-backend/agents/registry.py
  - solid-backend/agents/orchestrator.py
  - solid-backend/agents/conversation.py
  - solid-backend/services/ai/agent_telemetry.py
  - mcp/*.py
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# Agent Controls System

_Last Updated: December 12, 2025_

---

## Overview

The Agent Controls System provides users with the ability to **pause individual agents** and configure **global approval gates** for AI actions. This gives businesses control over their AI workforce without losing context or breaking inter-agent communication.

### Key Principles

1. **Pause, Not Delete**: Paused agents continue receiving inter-agent messages to preserve context
2. **Global Gates**: Approval thresholds apply uniformly to all enabled agents
3. **Inter-Agent Communication Always Works**: Messages between agents are never blocked
4. **Simple UX**: ON/OFF toggles + 3 approval gates = easy to understand

---

## Architecture

```
┌─────────────────────────────────────────────────────────────────┐
│                    PER-AGENT TOGGLE                             │
│                (stored on Agent.is_enabled)                     │
├─────────────────────────────────────────────────────────────────┤
│  ON  → Works normally, respects global gates                    │
│  OFF → Paused, receives inter-agent messages, no actions        │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    GLOBAL APPROVAL GATES                        │
│              (stored in Company.agent_controls)                 │
├─────────────────────────────────────────────────────────────────┤
│  customer_contact_requires_approval: true/false                 │
│  spend_threshold_usd: number (e.g., 50)                         │
│  data_modification_requires_approval: true/false                │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    INTER-AGENT BUS                              │
│                    (ALWAYS ON)                                  │
├─────────────────────────────────────────────────────────────────┤
│  ada__send_agent_message → Always works                         │
│  ada__get_agent_inbox    → Always works                         │
│  AgentCommunication      → Always records                       │
│                                                                 │
│  Even PAUSED agents receive messages for context preservation   │
└─────────────────────────────────────────────────────────────────┘
```

---

## Database Schema

### Agent Model (existing field)

```python
# models/agent.py
is_enabled: Mapped[bool] = mapped_column(Boolean, default=True)
```

### Company Model (new field)

```python
# models/company.py
agent_controls: Mapped[Optional[Dict[str, Any]]] = mapped_column(
    JSONB,
    nullable=True,
    default=dict,
    comment="Agent control settings: {gates: {...}, notifications: {...}}"
)
```

### Default Structure

```python
DEFAULT_AGENT_CONTROLS = {
    "gates": {
        "customer_contact_requires_approval": True,
        "spend_threshold_usd": 50,
        "data_modification_requires_approval": False
    },
    "notifications": {
        "email_on_approval_needed": True,
        "email_on_action_completed": False,
        "daily_digest": True
    }
}
```

---

## Action Categories

| Category | Description | Examples |
|----------|-------------|----------|
| `CUSTOMER_CONTACT` | AI directly contacts customers | Email, SMS, phone calls |
| `SPEND_MONEY` | Financial transactions | Purchases, refunds, ad spend |
| `DATA_MODIFICATION` | Create/update records | CRM updates, inventory changes |
| `INTER_AGENT` | Agent-to-agent messages | **Never blocked** |

---

## Gate Checker Service

**File:** `/solid-backend/services/agent_gate_checker.py`

### Main Functions

```python
# Check if action is allowed
from services.agent_gate_checker import check_action_allowed, ActionCategory

result = check_action_allowed(
    db=db,
    agent_id=agent.id,
    company_id=company_id,
    action_category=ActionCategory.CUSTOMER_CONTACT,
    action_description="Send follow-up email to customer"
)

if result.blocked:
    # Agent is paused or not found
    return {"ok": False, "reason": result.reason}

if result.requires_approval:
    # Gate triggered - approval request created
    return {"ok": True, "status": "pending_approval", "approval_id": result.approval_id}

# Action is allowed - proceed
...
```

### Toggle Agent

```python
from services.agent_gate_checker import toggle_agent_enabled

success = toggle_agent_enabled(
    db=db,
    agent_id=agent_id,
    company_id=company_id,
    enabled=True  # or False to pause
)
```

### Update Controls

```python
from services.agent_gate_checker import update_company_agent_controls

success = update_company_agent_controls(
    db=db,
    company_id=company_id,
    new_controls={
        "gates": {
            "customer_contact_requires_approval": False,
            "spend_threshold_usd": 100
        }
    }
)
```

---

## API Endpoints

### Toggle Agent (Pause/Unpause)

```http
PATCH /api/v1/agents/{agent_id}/toggle
Content-Type: application/json

{
    "is_enabled": false
}
```

**Response:**
```json
{
    "agent_id": 5,
    "is_enabled": false,
    "status": "idle",
    "message": "Agent paused successfully"
}
```

### Get Controls

```http
GET /api/v1/agents/controls
```

**Response:**
```json
{
    "company_id": 1,
    "controls": {
        "gates": {
            "customer_contact_requires_approval": true,
            "spend_threshold_usd": 50,
            "data_modification_requires_approval": false
        },
        "notifications": {
            "email_on_approval_needed": true,
            "email_on_action_completed": false,
            "daily_digest": true
        }
    }
}
```

### Update Controls

```http
PUT /api/v1/agents/controls
Content-Type: application/json

{
    "gates": {
        "customer_contact_requires_approval": false,
        "spend_threshold_usd": 100
    },
    "notifications": {
        "daily_digest": false
    }
}
```

---

## Frontend UI

**File:** `/solid-frontend/src/app/(main)/dashboard/agents/page.tsx`

### Features

1. **Per-Agent Toggle Switch**: ON/OFF for each agent card
2. **Paused Indicator**: Yellow banner showing agent is paused but receiving context
3. **Approval Gates Button**: Opens modal for global settings
4. **Real-time Updates**: Optimistic UI updates with toast notifications

### UI Elements

```
┌─────────────────────────────────────────────────────────────────┐
│ AI Agents                                    [Approval Gates]   │
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ADA - VP of Operations                    [Active] [ON/OFF] │ │
│ │ Orchestrates all agents...                                  │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Jake - Inventory Manager                  [Paused] [ON/OFF] │ │
│ │ Monitors stock levels...                                    │ │
│ │ ⚠️ Paused - Still receiving context from other agents       │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```

---

## Use Cases

| Scenario | Action |
|----------|--------|
| Going on vacation | Pause customer-facing agents (Sarah, Sage) |
| Manual inventory count | Pause Jake (inventory manager) |
| Testing new marketing campaign | Enable customer contact approval gate |
| Fully trusting AI | Disable all approval gates |
| Business doesn't sell products | Keep Jake permanently paused |

---

## Critical: Inter-Agent Communication

**Inter-agent messages are NEVER blocked**, regardless of:
- Agent's `is_enabled` status
- Company's approval gates
- Any other setting

This ensures:
1. **Context Preservation**: Paused agents have full context when re-enabled
2. **No Chain Breakage**: Other agents can still reference paused agents
3. **Consistent State**: All agents share the same understanding of business state

---

## Implementation Notes

### When to Check Gates

Call `check_action_allowed()` before any agent action that:
- Contacts customers (email, SMS, call)
- Spends money (purchases, refunds, ad campaigns)
- Modifies business data (CRM, inventory)

### Approval Workflow

When a gate triggers:
1. `AgentApproval` record created with `status=PENDING`
2. User notified (if `email_on_approval_needed=True`)
3. User approves/rejects via `/api/v1/agents/approvals/{id}/approve`
4. If approved, original action executes

---

## File Reference

```
solid-backend/
├── models/
│   ├── company.py                  # agent_controls JSONB field
│   └── agent.py                    # is_enabled field
├── services/
│   └── agent_gate_checker.py       # Gate checking logic
├── controllers/
│   └── agents.py                   # API endpoints
└── alembic/versions/
    └── 20251212_add_agent_controls.py

solid-frontend/
└── src/app/(main)/dashboard/agents/
    └── page.tsx                    # UI with toggles and modal
```

---

## Migration

**File:** `20251212_add_agent_controls.py`

Adds `agent_controls` JSONB column to `companies` table with default values.

---

## End-to-End Integration

### Execution Flow

```
User/Agent triggers action
         │
         ▼
┌─────────────────────────────────────────────────────────────────┐
│ AIToolEngine.execute_tool()                                     │
│ (agents/tool_engine.py:424; gate check ~line 486 — was          │
│  ":287" prior to a refactor, verified 2026-08-29)                │
├─────────────────────────────────────────────────────────────────┤
│ 1. Lookup tool in MCP registry                                  │
│ 2. Get tool category from tool_categories.py                    │
│ 3. If requires_gate(tool_name):                                 │
│    └─> check_action_allowed(db, agent_id, company_id, ...)     │
│        ├─> BLOCKED → return {"status": "blocked"}              │
│        ├─> APPROVAL_REQUIRED → return {"status": "pending"}    │
│        └─> ALLOWED → continue                                  │
│ 4. Inject company_id, user_id, agent_id, conversation_id        │
│ 5. Execute tool_func(args)                                      │
│ 6. Log AgentAction (if agent_id present)                        │
│ 7. Return result                                                │
└─────────────────────────────────────────────────────────────────┘
```

---

## MCP Tool → Action Category Mapping

### CUSTOMER_CONTACT Tools

| Tool Name | Description |
|-----------|-------------|
| `email.send` / `send_email_to_contact` | Send email to customer |
| `email.reply` / `reply_to_email` | Reply to customer email |
| `marketing.campaigns.send` | Send marketing campaign |
| `drip.enroll` / `drip_enroll_contact` | Enroll in email drip |
| `surveys.send` | Send survey |
| `maya_generate_social_post` | Post to social media |
| `workflow.auto_nurture_cold_leads` | Auto-send to cold leads |
| `sms.send` | Send SMS |
| `voice.outbound_call` | Make outbound call |

### SPEND_MONEY Tools

| Tool Name | Description |
|-----------|-------------|
| `payments.charge` | Charge payment |
| `payments.refund` | Issue refund |
| `affiliate.process_payout` | Process affiliate payout |
| `ada.optimize_price` | Change product price |
| `marketing.ads.set_budget` | Set ad budget |

### DATA_MODIFICATION Tools

| Tool Name | Description |
|-----------|-------------|
| `crm.contacts.create` | Create CRM contact |
| `crm.contacts.update` | Update contact |
| `crm.deals.create` | Create deal |
| `crm.deals.close` | Close deal |
| `crm.tasks.create` | Create task |
| `inventory.adjust` | Adjust stock |
| `ada.inventory.create_transfer` | Create stock transfer |
| `promoter.create` | Create promoter |
| `landing.page.publish` | Publish landing page |

### INTER_AGENT Tools (Never Gated)

| Tool Name | Description |
|-----------|-------------|
| `ada.send_agent_message` | Send message to agent |
| `ada.get_agent_inbox` | Get agent inbox |
| `ada.get_full_context` | Get recovery context |

---

## Agent → MCP Tools Access

### ADA (Orchestrator) - Autonomy 5
- **Full access**: All analytics, CRM, marketing, drip, surveys
- **Key tools**: `ada__predict_stockout`, `ada__optimize_price`, `ada__send_agent_message`

### Sarah (Customer Service) - Autonomy 4
- **Customer ops**: Orders, refunds (max $100), customer lookup
- **CRM**: Contacts (read/update, NOT create), tasks
- **Key tools**: `solid__payments__refund`, `ada__send_agent_message`

### Jake (Inventory Manager) - Autonomy 4
- **Inventory**: Full access including transfers (max 100 units)
- **Stock**: Levels, adjustments, reservations
- **Key tools**: `ada__create_stock_transfer`, `ada__adjust_stock`

### Marcus (Marketing) - Autonomy 3
- **Lead intelligence**: Scoring, lookalikes, segmentation
- **Campaigns**: Create, send, schedule (max $500 spend)
- **Key tools**: `sales.score` (~~was `marcus__score_leads`~~ — that name only exists in Marcus's own system-prompt text in `agents/registry.py`; the actual registered MCP tool is `sales.score` → `sales__score` in `mcp/tools/sales_agent.py:560`, verified 2026-08-29), `marketing.campaigns.send`

### Annie (Affiliate Manager) - Autonomy 4
- **Promoters**: Full CRUD
- **Payouts**: Process (max $5000)
- **Key tools**: `affiliate_process_payout`, `promoter_create`

### Devon (DevOps) - Autonomy 5
- **Platform**: Health, metrics, CI/CD
- **Infra**: Service restarts (max 3 auto), security scans
- **Key tools**: `devops.restart_service`, `devops.check_vulnerabilities`

---

## KB Context Integration

KB templates load per-agent context via `ContextComposer`:

```python
# services/knowledge_base/composer.py
async def compose_for_agent(
    self,
    agent_name: str,      # "sarah", "marcus", etc.
    task_type: str,       # "send_email", "create_order", etc.
    ...
) -> Dict[str, Any]:
    # Layers: SESSION → USER → DEPARTMENT → ORGANIZATION → SYSTEM
    # All filtered by company_id
```

KB context is loaded BEFORE tool execution, giving agents:
- Company personality settings
- Industry-specific knowledge
- Business hours and contact info
- Custom instructions per company

---

## Customer Chat Actions (Special Case)

**File:** `/solid-backend/services/ai/chat_action_executor.py`

Customer-facing chat (Sage) has a separate execution path for actions triggered by customer messages:

| Aspect | Agent Tool Execution | Customer Chat Actions |
|--------|---------------------|----------------------|
| Trigger | Agent autonomous decision | Customer message |
| Path | `tool_engine.py` | `chat_action_executor.py` |
| Gate Checked | ✅ Yes | ❌ No |
| Why | Agents act on their own | Customer-initiated requests |

### Actions Created by Chat

When customers request things in chat, these are created immediately:

| Customer Says | Action Created | Gated? |
|---------------|---------------|--------|
| "Call me back" | Callback Task | No |
| "I need a quote" | Quote Task | No |
| "Schedule an appointment" | Appointment Task | No |
| "I want to speak to someone" | Escalation Task | No |

**Rationale**: These are customer-initiated requests, not autonomous AI decisions. Blocking them would degrade customer experience. The tasks are internal reminders for staff, not customer contact.

### If Sage is Paused

When Sage's `is_enabled = false`:
- Chat widget may still display (frontend decision)
- Responses still generated (customer experience)
- Chat actions still created (customer requests honored)

To fully disable customer chat, use company settings or remove the chat widget rather than pausing Sage.

---

## File Reference (Complete)

```
solid-backend/
├── agents/
│   ├── tool_engine.py           # Tool execution with gate checks
│   ├── tool_categories.py       # Tool → ActionCategory mapping
│   └── registry.py              # Agent → Tool access mapping
├── services/
│   ├── agent_gate_checker.py    # Gate checking logic
│   ├── ai/
│   │   └── chat_action_executor.py  # Customer chat actions (NOT gated)
│   └── knowledge_base/
│       └── composer.py          # KB context loading
├── models/
│   ├── company.py               # agent_controls JSONB
│   └── agent.py                 # is_enabled toggle
├── controllers/
│   └── agents.py                # API endpoints
├── mcp/
│   ├── registry.py              # MCP tool registry
│   └── tools/
│       ├── marketing_campaigns.py
│       ├── email_operations.py
│       ├── ops_payments.py
│       ├── ops_affiliates.py
│       └── ada_orchestrator.py
└── alembic/versions/
    └── 20251212_add_agent_controls.py

solid-frontend/
└── src/app/(main)/dashboard/agents/
    └── page.tsx                 # UI with toggles and gates modal
```

---

_Part of Owners Manual documentation suite_


--- FILE: 03-AI-Systems/AGENT-DISPLAY-NAMES.md ---

---
topic: ai-systems
keywords: [AI, agents, MCP, SmartRouter, LLM, orchestration, knowledge-base]
code_paths:
  - agents/*.py
  - solid-backend/agents/registry.py
  - solid-backend/agents/orchestrator.py
  - solid-backend/agents/conversation.py
  - solid-backend/services/ai/agent_telemetry.py
  - mcp/*.py
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

# Agent Display Names - Public vs Internal

> **Last Updated:** January 1, 2026
> **Status:** ✅ IMPLEMENTED
> **Priority:** HIGH (User Experience)

> ⚠️ **Re-verified 2026-08-29.** The core mechanism — `agent.settings["agent_display_name"]`
> read by `Agent.to_dict()` (`models/agent.py:275-286`, matches doc exactly) — is real and
> is the SAME field/mechanism used across the voice stack (`controllers/voice.py`,
> `controllers/shift4_nexus.py`, `services/contextual_personality.py`, etc.), confirming
> this doc's design is the one true implementation, not a separate/legacy one. Two
> claims below are corrected: (1) the food-agent → display-name mapping table has stale
> entries — "Bacon" and "Egg" do not exist in the current 23-agent roster
> (`agents/food/__init__.py`, `agents/kb_orchestrator.py:72-101`); (2) the "zero
> remaining `filter_by(name=)` calls" claim is overstated — see inline notes.
>
> **Also independently confirmed 2026-08-29** (this was the platform-rule cross-check
> for this doc): `agent_display_name` is set on the **outbound**/demo call paths
> (`controllers/voice.py:1130` `initiate_outbound_call`; `controllers/shift4_nexus.py`
> explicitly does NOT set it either, by design — see its comment at line ~4217) and is
> **never** set on the inbound path (`controllers/voice_engine_v2.py::v2_incoming`,
> the live inbound handler, has zero references to `agent_display_name`). This matches
> the platform rule verbatim: inbound calls always get Sarah's/the agent's full
> registry personality; only demo/outbound calls may override the display name.

---

## CRITICAL: agent_type Is the Stable Identifier

Clients can rename agents ("Sarah" → "Support Bot"). The display `name` is cosmetic.
**All system logic MUST use `agent_type`** (never changes).

```python
# WRONG — breaks if client renames the agent
agent = db.query(Agent).filter_by(name="Sarah").first()

# CORRECT — stable identifier, survives renames
agent = db.query(Agent).filter_by(agent_type="customer_service", company_id=company_id).first()
```

As of 2026-02-28, all workers, scripts, MCP tools, and services use `agent_type` for lookups. Zero remaining `filter_by(name=)` calls for agent identification.

> ⚠️ **Corrected 2026-08-29:** this is overstated for the codebase as it stands today.
> A guard test (`tests/test_voice_routing_integrity.py::
> test_voice_path_has_no_name_based_agent_lookups`) enforces the rule, but **only**
> against `controllers/voice.py` — it does not cover the whole codebase the doc's
> sentence implies. Real, current counterexamples that filter by the internal `name`
> column rather than `agent_type`: `scripts/setup_company3_voice.py:51`
> (`Agent.name == "Sarah"`), `workers/sage_chat_action_handler.py:85`
> (`Agent.name == self.agent_name`), and `services/ai_content_generator.py:162`
> (`Agent.name == agent_type` — filters the `name` column despite the confusing
> variable name). Whether these predate 2026-02-28 or were added after is not
> determinable from the code alone; either way "zero remaining" does not hold today.

---

## For Developers: How to Use Display Names

### Backend (Python)

The `Agent.to_dict()` method automatically includes `display_name`:

```python
# Agent model returns display_name from settings
agent = db.query(Agent).filter(Agent.id == agent_id).first()
data = agent.to_dict()

# data["name"] = "Coffee"  (internal name)
# data["display_name"] = "Quality Reviewer"  (user-facing name)
```

**Setting a display name:**
```python
# Via personality settings
from services.contextual_personality import set_agent_personality_settings

set_agent_personality_settings(
    db=db,
    agent_id=agent.id,
    company_id=company_id,
    agent_display_name="Quality Reviewer"
)

# Or directly in settings JSON
agent.settings["agent_display_name"] = "Quality Reviewer"
db.commit()
```

### Frontend (TypeScript)

The `Agent` interface includes `display_name`:

```typescript
import { Agent } from "@/lib/api/agents";

// Always use display_name for user-facing UI
<span>{agent.display_name}</span>  // Shows "Quality Reviewer"

// Use name only for internal/debug purposes
console.log(`Internal: ${agent.name}`);  // Shows "Coffee"
```

### The Golden Rule

```
Frontend displays: agent.display_name
Logs/debugging:    agent.name (internal)
```

---

## The Problem

Our internal AI agent system uses food-themed names (Coffee, Juice, Tea, Meat, Potato, etc.). While fun for developers, these names confuse users.

**Current UI shows:**
```
Critic: Coffee
Worker: Meat
Worker: Potato
Worker: Carrot
```

**Users think:** "Why is Coffee reviewing my data? What does Meat do?"

---

## The Solution: Display Name Mapping

### Critic Agents (Quality Reviewers)

| Internal Name | Public Display Name | Description |
|---------------|---------------------|-------------|
| **Coffee** | Quality Reviewer | Reviews KB entries for accuracy and completeness |
| **Juice** | Template Validator | Validates templates and formatting standards |
| **Tea** | Consistency Checker | Ensures cross-document consistency |
| **BubbleTea** | Security Auditor | Validates multi-tenant isolation and security |

### Worker Agents (Task Executors)

> ⚠️ **Corrected 2026-08-29** (verified `agents/food/__init__.py` and
> `agents/kb_orchestrator.py:20-101`): **"Egg" and "Bacon" do not exist** in the
> current roster — there is no `bacon.py` or `egg.py` (only `easter_egg.py`, a
> *Toys*-phase agent unrelated to appointments). The real current 23-agent roster is
> Apple, Kale, Beet, Meat, Potato, Broccoli, Orange, French Fries, Carrot, Radish,
> Pepper, Coffee, Juice, Tea, Bubble Tea, Cake, Cupcake, Cookie, Ice Cream, Dice,
> Target, Game, Easter Egg — grouped by onboarding phase (MAIN_COURSE: Meat, Potato,
> Broccoli, Orange · SIDES: French Fries, Carrot, Radish, Pepper · DRINKS: Coffee,
> Juice, Tea, Bubble Tea · TOYS: Dice, Target, Game, Easter Egg), not by a
> Worker/Critic split as the two tables below imply. The DRINKS group does match this
> doc's separate "Critic Agents" table below. Apple, Kale, Beet, Cake, Cupcake, Cookie,
> Ice Cream, Dice, Target, and Game have no display-name mapping documented anywhere
> in this file — that gap is unverified/unaddressed, not confirmed accurate.

| Internal Name | Public Display Name | Description |
|---------------|---------------------|-------------|
| **Meat** | Data Processor | Handles data import and customer records |
| **Potato** | Entity Creator | Creates services, products, forms |
| **Carrot** | Workflow Builder | Creates workflows and automations |
| **Fries** | Content Mapper | Maps and organizes content |
| **Radish** | Data Validator | Validates data quality |
| **Pepper** | Alert Generator | Creates notifications and alerts |
| **Orange** | Content Enricher | Enriches KB entries with context |
| **Broccoli** | KB Writer | Creates knowledge base entries |
| ~~**Egg**~~ | ~~Action Executor~~ | **Does not exist in the roster — see note above** |
| ~~**Bacon**~~ | ~~Appointment Manager~~ | **Does not exist in the roster — see note above** |

### Planner Agents

| Internal Name | Public Display Name | Description |
|---------------|---------------------|-------------|
| **OpsPlanner** | Operations Planner | Plans operational tasks |
| **KBPlanner** | Knowledge Planner | Plans KB updates |
| **CRMPlanner** | Customer Planner | Plans CRM operations |
| **GrowthPlanner** | Growth Planner | Plans marketing tasks |

### Core Business Agents

| Internal Name | agent_type | Public Display Name | Description |
|---------------|-----------|---------------------|-------------|
| **ADA** | `orchestrator` | AI Coordinator | Main orchestrator (ID 12) |
| **Sarah** | `customer_service` | Customer Service | Chat, voice, support, brand voice (ID 1) |
| **Marcus** | `marketing` | Growth Intelligence | Email, ads, landing pages (ID 4) |
| **Maya** | `brand` | Brand Director | Social, brand voice, visual identity (ID 7) |
| **Ace** | `developer` | Developer | Blogs, code, website content (ID 9) |
| **Devon** | `devops` | Operations Monitor | System health, monitoring (ID 11) |
| **Victor** | `validator` | QA Validator | Page validation, deploy gates (ID 15) |
| **Operator** | `operator` | Platform Operator | SuperAdmin-only management (ID 16) |
| **Gwen** | `google_workspace` | Workspace Manager | Gmail, Calendar, Drive, Docs (ID 17) |

> **Note:** "Sage" was an old marketing name that doesn't exist in the registry.
> Customer-facing chat is handled by **Sarah** (customer_service, ID 1).

> ⚠️ **Checked 2026-08-29** (`agents/registry.py`): every `agent_type` key and name
> above matches the registry, with one wording difference — the registry's `"name"`
> for the `operator` entry is **"Operator Console"**, not "Operator". The numeric
> `(ID n)` values in this table are per-row `Agent.id` values from the database, not
> constants in `agents/registry.py` (which is keyed by `agent_type` string, not a
> fixed int) — they could not be confirmed or refuted from source alone within this
> pass's scope (no DB query performed); treat them as illustrative, not verified.
> "Sage" is confirmed correct as noted: it exists only as an orphaned lowercase key in
> `services/ai/smart_router.py`'s `AGENT_TASK_MAP`, never as a registry agent name.

---

## Implementation Details (✅ COMPLETED)

### 1. Database: Uses Existing Settings JSON

No schema changes needed - display names are stored in the existing `Agent.settings` JSON field:

```python
agent.settings = {
    "agent_display_name": "Quality Reviewer",
    # ... other settings
}
```

### 2. Backend: Agent.to_dict() Returns display_name

**File:** `models/agent.py`

```python
def to_dict(self):
    settings = self.settings or {}
    display_name = settings.get("agent_display_name") or self.name

    return {
        "id": self.id,
        "name": self.name,  # Internal name (Coffee)
        "display_name": display_name,  # User-facing (Quality Reviewer)
        # ...
    }
```

### 3. Frontend: Uses display_name

**File:** `src/lib/api/agents.ts`

```typescript
export interface Agent {
  id: number;
  name: string;
  display_name: string;  // User-friendly name
  // ...
}
```

### 4. Updated UI Components

| Component | Location | Status |
|-----------|----------|--------|
| Critic cards | `/dashboard/agents/(agent-pages)/critics` | ✅ Updated |
| Worker list | `/dashboard/agents/(agent-pages)/critics` | ✅ Updated |
| Review history table | Critics page | ✅ Updated |
| Rework queue | Critics page | ✅ Updated |

---

## Design Guidelines

### DO:
- Use action-oriented names (Reviewer, Validator, Processor)
- Show what the agent DOES, not what it's CALLED
- Keep names professional and clear
- Use consistent terminology

### DON'T:
- Show internal food names to users
- Use cute/quirky names in production
- Expose `code_name` in UI
- Mix internal and display names

---

## User-Facing Copy Examples

**Task History:**
```
✓ Quality Reviewer approved your KB entry (Score: 95)
✓ Data Validator checked your import (88 records valid)
⟳ Template Validator requested changes to your email
```

**Status Messages:**
```
"Your data is being processed by our Data Processor..."
"Quality Reviewer is checking your content..."
"Security Auditor verified your configuration."
```

**Error Messages:**
```
"Quality Reviewer found issues with your content. See details below."
NOT: "Coffee found issues..."
```

---

## Migration Plan

### Phase 1: Database (1 day)
- [ ] Add display_name columns
- [ ] Populate display names for all agents
- [ ] Add API endpoint to get agent display info

### Phase 2: Backend (1 day)
- [ ] Update agent responses to include display_name
- [ ] Update task/history responses to include display_name
- [ ] Keep code_name for internal routing

### Phase 3: Frontend (2-3 days)
- [ ] Update AI Console critic cards
- [ ] Update worker list displays
- [ ] Update task history component
- [ ] Update rework queue
- [ ] Update AI chat displays
- [ ] Update any status messages

### Phase 4: QA
- [ ] Verify no food names visible to users
- [ ] Check all agent references use display_name
- [ ] Test with real users for clarity

---

## Why We Keep Internal Names

The food naming convention stays for:
1. **Developer experience** - Fun, memorable for debugging
2. **Code references** - `agents/food/coffee.py` is clear
3. **Logs** - Internal logs can show code_name
4. **Documentation** - Internal docs use food names

**Rule:** Internal = Food Names, External = Professional Names

---

## Files to Update

### Backend
- `models/agent.py` - Add display_name field
- `api/routers/agents.py` - Include display_name in responses
- `services/agent_registry.py` - Map code_name to display_name

### Frontend
- `src/app/(main)/dashboard/ai-console/page.tsx`
- `src/components/agents/CriticCard.tsx`
- `src/components/agents/WorkerList.tsx`
- `src/components/tasks/TaskHistory.tsx`
- Any component showing agent names

---

*Part of Owners Manual - AI Systems Documentation*


--- FILE: 03-AI-Systems/AGENT-EXPANSION-ARCHITECTURE.md ---

---
topic: agent-expansion
keywords: [agents, scaling, boss-agents, task-agents, two-tier, expansion, 100-agents]
last_verified: 2026-03-02
status: current
priority: high
owner: platform-team
---

# Agent Expansion Architecture

> **How to scale from 15 agents to 100+ per company without 100 new controllers.**

_Created: March 2, 2026_

---

**⚠️ PARTIAL — unverified as of 2026-08-29.** This document reads as an architecture
proposal. Checked against `solid-backend/` on 2026-08-29: the `task_agent_definitions`
table, `services/task_agent_service.py`, and every `/api/v1/agents/tasks/*` endpoint
described below **do not exist anywhere in the codebase** (`grep -rl task_agent_definitions`
and `find -iname task_agent_service.py` both return nothing; no route matches
`agents/tasks` in `controllers/agents.py`). The Two-Tier Agent Model, database schema,
generic task endpoint, tier gating table, and migration phases are **unimplemented
proposals, not shipped behavior** — treat everything below "The Solution" as a design
doc, not a system description. The Boss Agent roster is spot-checked separately below
(one name was wrong and has been corrected). `last_verified` left unchanged because the
document's central subject could not be confirmed against code.

---

## The Problem

Today every company gets 15 customer-facing agents (Sarah, Jake, ADA, etc.) — ~~this "15" figure is stale~~: the platform's derived count as of 2026-08-29 is **32 AI agents** (33 registry entries, ADA counted twice for free/paid) in `agents/registry.py`. See `Owners-Manual/PLATFORM-METRICS.md` for the current canonical count rather than a hand-typed number here. Each core agent has:
- A dedicated controller (`controllers/agents.py`, `api/routers/cto_agent.py`)
- Dedicated UI pages (`/dashboard/agents/[agent_type]`)
- Dragon Command Studio integration
- Field manuals, system prompts, MCP tool assignments
- Full agent_profiles entry

If a team wants 100 agents, we **cannot** build 85 more controllers, 85 more pages, and 85 more field manuals. That doesn't scale.

---

## The Solution: Two-Tier Agent Model

### Tier 1: Boss Agents (Core — Full MVC)

The 15 customer-facing agents are **Boss Agents**. They own a domain, have full infrastructure, and can delegate work to helpers.

| # | Boss Agent | Domain |
|---|-----------|--------|
| 1 | Sarah | Customer Service |
| 2 | Jake | Inventory & Supply Chain |
| 3 | Morgan | Strategy & Analytics |
| 4 | Marcus | Marketing & Growth |
| 5 | Alex | Finance & Accounting |
| 6 | Jordan | Operations & Fulfillment |
| 7 | Maya | Brand & Content |
| 8 | Riley | Design & Visual Assets |
| 9 | Ace | Development & Engineering |
| 10 | Annie | Affiliates & Partnerships |
| 11 | Devon | DevOps & Infrastructure |
| 12 | ADA | Orchestration (Dragon) |
| 13 | Atlas (~~was listed as "Nora" — no such agent exists in `agents/registry.py`; the `cto` agent_type's actual name is Atlas, line ~2975, verified 2026-08-29~~) | CTO / Technical Sales |
| 14 | Emma | Sales Follow-up |
| 15 | Gwen | Google Workspace |

**Boss agents have:**
- Dedicated controllers & routes
- Dedicated UI pages in Dragon + Agents
- Full field manuals & system prompts
- MCP tool assignments
- Agent resumes in Owners Manual
- Direct customer interaction capability

### Tier 2: Task Agents (Helpers — Lightweight)

Task Agents are lightweight workers that **report to a Boss Agent**. They:
- Share the Boss's controller infrastructure (no new routes needed)
- Execute through a **generic task execution endpoint**
- Inherit context from their Boss's domain
- Can be created, renamed, and deleted by company owners
- Are managed through the AI HR portal (see: AI-HUMAN-RESOURCES.md)

**Task agents have:**
- An `agent_type` (like everything else)
- A `parent_agent_type` (links to their Boss)
- A role description and system prompt
- Access to a subset of their Boss's MCP tools
- NO dedicated controller, NO dedicated UI page

---

## How It Works

```
┌──────────────────────────────────────────────────────────┐
│                    BOSS AGENT (Sarah)                     │
│   agent_type: customer_service                           │
│   Has: Controller, UI page, Field Manual, Dragon slot    │
│                                                          │
│   ┌─────────────┐ ┌──────────────┐ ┌─────────────────┐  │
│   │ Ticket Triage│ │ Refund Bot   │ │ VIP Escalator   │  │
│   │ (Task Agent) │ │ (Task Agent) │ │ (Task Agent)    │  │
│   │ parent:      │ │ parent:      │ │ parent:         │  │
│   │ customer_svc │ │ customer_svc │ │ customer_svc    │  │
│   └─────────────┘ └──────────────┘ └─────────────────┘  │
└──────────────────────────────────────────────────────────┘
```

### Delegation Flow

1. ADA assigns a mission to **Sarah** (Boss)
2. Sarah evaluates the task complexity
3. If simple: Sarah handles it directly
4. If specialized: Sarah delegates to a **Task Agent** (e.g., "Refund Bot")
5. Task Agent executes using Sarah's MCP tools (scoped subset)
6. Task Agent reports result back to Sarah
7. Sarah reports to ADA

### Generic Task Agent Endpoint

Instead of dedicated controllers, Task Agents use ONE generic endpoint:

```
POST /api/v1/agents/tasks/execute
{
  "task_agent_type": "ticket_triage",
  "parent_agent_type": "customer_service",
  "company_id": <from JWT>,
  "action": "classify_ticket",
  "payload": { ... }
}
```

This single endpoint handles ALL task agents. The parent_agent_type determines:
- Which MCP tools are available
- Which field manuals to reference
- Which guardrails apply
- Cost attribution (charged to the Boss's budget)

---

## Database Schema

### New: `task_agent_definitions` Table

```sql
CREATE TABLE task_agent_definitions (
    id SERIAL PRIMARY KEY,
    company_id INTEGER NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
    agent_type VARCHAR(100) NOT NULL,          -- unique per company
    parent_agent_type VARCHAR(50) NOT NULL,     -- FK to boss agent's agent_type
    name VARCHAR(100) NOT NULL,                 -- e.g., "Ticket Triage"
    role VARCHAR(255),                          -- short description
    system_prompt TEXT,                         -- task-specific instructions
    allowed_tools JSONB DEFAULT '[]',           -- subset of parent's MCP tools
    autonomy_level INTEGER DEFAULT 2,           -- typically lower than boss
    is_enabled BOOLEAN DEFAULT true,
    created_by INTEGER REFERENCES users(id),    -- who created this task agent
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(company_id, agent_type)
);

CREATE INDEX idx_task_agents_company ON task_agent_definitions(company_id);
CREATE INDEX idx_task_agents_parent ON task_agent_definitions(parent_agent_type);
```

### Key Design Decisions

| Decision | Rationale |
|----------|-----------|
| **Separate table** (not in `agents`) | Task agents are lightweight; mixing them with Boss agents complicates queries |
| **No PostgreSQL ENUM** for task agent_type | Companies create custom types — can't add enum values per company |
| **VARCHAR agent_type** | Flexible, company-defined, validated at application layer |
| **parent_agent_type** not parent_id | Boss agents identified by type (stable), not by per-company DB id |
| **allowed_tools as JSONB** | Subset of parent's MCP tools, easily customizable |
| **company_id scoped** | Multi-tenant: each company defines their own task agents |

---

## Tier Gating

Task Agent limits by subscription tier:

| Tier | Boss Agents | Task Agents Per Boss | Total Possible |
|------|-------------|---------------------|----------------|
| Starter | 5 | 0 | 5 |
| Builder | 10 | 3 | 40 |
| Professional | 15 | 5 | 90 |
| Enterprise | 15 | 10 | 165 |

**Enterprise** customers can have up to 165 agents total (15 bosses × 10 helpers + 15 bosses).

---

## What Does NOT Change

| Component | Status |
|-----------|--------|
| `agents` table | Unchanged — still holds Boss agents per company |
| `agent_profiles` table | Unchanged — still platform-level definitions for Boss agents |
| `agent_type` ENUM | Unchanged — only Boss agent types are in the enum |
| Dragon Command Studio | Unchanged — shows Boss agents only (task agents appear as sub-items) |
| MCP tool registry | Unchanged — tools assigned to Boss agents, task agents inherit subsets |
| Provisioning | Unchanged — still creates 15 Boss agents per company |
| `resolve_agent_by_db_id()` | Unchanged — resolves Boss agents only |

---

## What IS New

| Component | Description |
|-----------|-------------|
| `task_agent_definitions` table | Per-company task agent definitions |
| `POST /api/v1/agents/tasks/execute` | Generic task execution endpoint |
| `GET /api/v1/agents/tasks` | List task agents for a company |
| `POST /api/v1/agents/tasks` | Create a task agent |
| `PUT /api/v1/agents/tasks/{id}` | Update a task agent |
| `DELETE /api/v1/agents/tasks/{id}` | Delete a task agent |
| AI HR Portal (frontend) | UI for managing task agents, associations, org chart |
| `services/task_agent_service.py` | Task agent execution, delegation, tool scoping |

---

## Naming Convention

Task agents follow a structured naming pattern:

```
{boss_domain}_{function}
```

Examples:
- `customer_service_ticket_triage`
- `customer_service_refund_processor`
- `marketing_email_ab_tester`
- `inventory_restock_alerter`
- `finance_invoice_chaser`

The prefix matches the parent Boss agent's domain. This makes it immediately clear who the task agent reports to.

---

## Example: Sarah's Team (Customer Service)

```
Sarah (Boss — customer_service)
├── Ticket Triage      — Classifies incoming tickets by priority
├── Refund Processor   — Handles refund requests under $50 automatically
├── Sentiment Monitor  — Watches for negative customer sentiment
├── VIP Escalator      — Routes high-value customer issues to humans
└── FAQ Bot            — Answers common questions from KB
```

Each of these:
- Uses Sarah's MCP tools (`crm.tickets.*`, `crm.contacts.*`, `kb.search`)
- Runs under Sarah's CognitiveLimiter budget
- Reports results back to Sarah
- Appears as a sub-item in Dragon when Sarah is selected

---

## Migration Path

### Phase 1: Foundation (Sprint)
1. Create `task_agent_definitions` table + migration
2. Build `TaskAgentService` (CRUD + execution)
3. Build generic `/agents/tasks/*` endpoints
4. Add tier gating for task agent limits

### Phase 2: AI HR Portal (Sprint)
5. Build AI HR frontend (see: AI-HUMAN-RESOURCES.md)
6. Task agent creation wizard
7. Parent assignment + tool scoping UI
8. Dragon integration (show task agents under Boss)

### Phase 3: Intelligence (Future)
9. ADA auto-suggests task agents based on workload patterns
10. Task agents learn from Boss agent's field manuals
11. Cross-boss task agent sharing (e.g., "Invoice Chaser" works for both Finance and Operations)

---

## Related Documentation

| Document | Description |
|----------|-------------|
| [AI-HUMAN-RESOURCES.md](./AI-HUMAN-RESOURCES.md) | AI HR Portal — manage agents, org chart, associations |
| [AGENT-REGISTRY-MAP.md](./AGENT-REGISTRY-MAP.md) | Single source of truth for Boss agent identities |
| [AGENT-LIFECYCLE.md](./AGENT-LIFECYCLE.md) | 9-stage lifecycle (applies to Boss agents) |
| [47-Field-Manual/](../47-Field-Manual/) | MCP tool infrastructure (inherited by task agents) |

---

_Part of Owners Manual documentation suite_


--- FILE: 03-AI-Systems/AGENT-PROFILE-SERVICE.md ---

---
topic: agent-profile-service
keywords: [agent-profiles, identity, capabilities, channels, service, API, source-of-truth]
code_paths:
  - solid-backend/models/agent_profile.py
  - solid-backend/services/agent_profile_service.py
  - solid-backend/controllers/agent_profiles.py
  - solid-backend/controllers/agents.py
  - solid-backend/migrations/versions/agent_profiles_20260301.py
  - solid-backend/migrations/versions/agent_profiles_capabilities_20260302.py
last_verified: 2026-08-29
status: current
priority: critical
owner: platform-team
---

# Agent Profile Service — Centralized Identity Hub

> **Single source of truth for "who is this agent."**
>
> The `agent_profiles` table replaces scattered registry definitions and hardcoded
> capability lists. Every consumer of agent identity reads through this service.

---

## Architecture: Two-Layer Agent Model

```
┌─────────────────────────────────────────────────────────────────────┐
│  PLATFORM LAYER                                                     │
│  Table: agent_profiles            Scope: One row per agent_type    │
│  ~~26 total rows (14 core + 9 veggie + 3 internal)~~ — STALE, corrected 2026-08-29. │
│  The seed migration (agent_profiles_20260301.py) seeds dynamically from            │
│  `AGENT_TYPE_TO_ID` in agents/registry.py, which has grown to 34 keys as of         │
│  2026-08-29 (agents/registry.py:5506-5541) — well past the 26 this doc assumed.     │
│  Canonical count: 32 AI agents / 33 registry entries — see Owners-Manual/           │
│  PLATFORM-METRICS.md. Row count in the LIVE `agent_profiles` table depends on       │
│  whether `sync_from_registry()` has been run since the registry grew — not          │
│  independently confirmed against the running database by this verification pass.   │
│                                                                     │
│  Contains: name, bio, title, system_prompt, capabilities JSON,     │
│            channel flags, colors, category, autonomy_level          │
│                                                                     │
│  Service: AgentProfileService                                      │
│  API: /api/v1/agent-profiles                                       │
└─────────────────────────────┬───────────────────────────────────────┘
                              │ provisioning reads from here
                              v
┌─────────────────────────────────────────────────────────────────────┐
│  PER-COMPANY LAYER                                                  │
│  Table: agents                    Scope: One row per agent per co  │
│  ~14 rows per company (customer-facing agents)                     │
│                                                                     │
│  Contains: display_name, is_enabled, settings JSON,                │
│            llm_config, voice_config, autonomy_level override       │
│                                                                     │
│  API: /api/v1/agents                                               │
└─────────────────────────────┬───────────────────────────────────────┘
                              │ channel tables FK to agents.id
                              v
┌─────────────────────────────────────────────────────────────────────┐
│  CHANNEL LAYER                                                      │
│  Tables: company_email_addresses, company_phone_numbers,           │
│          chat_widgets                                              │
│                                                                     │
│  Each row links to an agent via assigned_agent_id / agent_id       │
│  API: GET /api/v1/agents/{id}/channels → unified summary          │
└─────────────────────────────────────────────────────────────────────┘
```

**Key principle:** Platform identity lives in `agent_profiles`. Per-company overrides live in `agents`. Channel assignments live in their own tables. The channels endpoint joins all three for a complete picture.

---

## Database Schema: `agent_profiles`

| Column | Type | Purpose |
|--------|------|---------|
| `id` | Integer PK | Auto-increment row ID |
| `agent_type` | String(50), unique | Canonical identifier: `customer_service`, `marketing`, etc. |
| `agent_id` | Integer, unique | Numeric ID: 1 (Sarah), 4 (Marcus), etc. |
| `name` | String(100) | Platform name (immutable across companies) |
| `display_name` | String(100) | Optional platform display override |
| `title` | String(200) | Role title: "Voice Intelligence Engine" |
| `avatar_url` | String(500) | Agent icon URL |
| `bio` | Text | Longer description |
| `purpose` | Text | Mission statement |
| `default_personality` | String(50) | Default personality preset: "professional" |
| `sales_approach` | String(20) | Default sales style: "mild" |
| `intensity` | String(20) | Default intensity: "lite" |
| `voice_style` | String(50) | TTS voice mapping |
| `autonomy_level` | Integer | Default 1-5 autonomy |
| `system_prompt` | Text | Base system prompt from registry |
| `capabilities` | JSONB | **Structured capabilities** (see below) |
| `color` | String(60) | Tailwind text color class |
| `bg_color` | String(100) | Tailwind background class |
| `category` | String(30) | "core", "veggie", "internal" |
| `is_customer_facing` | Boolean | Used by tenant provisioning filter |
| `version` | Integer | Bumped on every update |
| `created_at` / `updated_at` | DateTime | Timestamps |

### Capabilities JSON Schema

```json
{
  "channels": {
    "email": true,
    "phone": true,
    "sms": true,
    "chat": true,
    "voice": true
  },
  "email_purpose": "support",
  "actions": [
    "resolve_tickets",
    "process_refunds",
    "handle_calls"
  ],
  "max_autonomy": 4
}
```

**`channels`** — Which communication channels this agent can operate on. Used by the setup wizard to populate agent selection dropdowns instead of hardcoded lists.

**`email_purpose`** — Suggested email category when assigning this agent to an email address (support, sales, marketing, transactional).

**`actions`** — High-level actions this agent can perform. For documentation and UI display.

**`max_autonomy`** — Maximum recommended autonomy level for this agent type.

### Channel Capabilities by Agent

| Agent | ID | Email | Phone | SMS | Chat | Voice | Email Purpose |
|-------|---:|:-----:|:-----:|:---:|:----:|:-----:|--------------|
| Sarah (customer_service) | 1 | Y | Y | Y | Y | Y | support |
| Jake (inventory_manager) | 2 | Y | - | - | Y | - | transactional |
| Morgan (strategy) | 3 | Y | - | - | Y | - | support |
| Marcus (marketing) | 4 | Y | Y | Y | Y | Y | marketing |
| Alex (finance) | 5 | Y | - | - | Y | - | transactional |
| Jordan (operations) | 6 | - | - | - | Y | - | - |
| Maya (brand) | 7 | - | - | - | Y | - | - |
| Riley (graphic_designer) | 8 | - | - | - | Y | - | - |
| Ace (developer) | 9 | - | - | - | Y | - | - |
| Annie (affiliate_manager) | 10 | Y | - | - | Y | - | marketing |
| Devon (devops) | 11 | - | - | - | Y | - | - |
| ADA (orchestrator) | 12 | - | - | - | Y | - | - |
| ~~Nora CTO~~ **Atlas** (cto) | 13 | - | - | - | Y | - | - | <!-- corrected 2026-08-29: agents/registry.py:5518 names agent_id 13 "Atlas (CTO Agent)", not Nora -->
| Emma (sales_followup) | 14 | Y | Y | Y | Y | Y | sales |
| Gwen (google_workspace) | 17 | Y | - | - | Y | - | transactional |
| Veggie workers (18-26) | 18-26 | - | - | - | - | - | - |
| Validator/Operator (15-16) | 15-16 | - | - | - | - | - | - |

**Table incomplete as of 2026-08-29** — `agents/registry.py:5533-5541` (`AGENT_TYPE_TO_ID`) now has 8 more entries this table never lists: `sales` (27, Jackson), `project_manager` (28, Lucie), `compliance` (29, Daphne), `medical_scribe` (30, Dexter), `orchestrator_free` (31, ADA Free), `pediatric_care_coordinator` (32), `clinical_summarizer` (33), and `shift4_annual_fee` (34, Sarah/Shift4 voice bot). Their channel-capability flags were not re-derived in this pass — verify against each entry's `capabilities` JSON in `agent_profiles` before relying on this table for those agents.

---

## Service Layer: `AgentProfileService`

**File:** `services/agent_profile_service.py`

| Method | Purpose |
|--------|---------|
| `get_profile(agent_type)` | Get profile by type string |
| `get_profile_by_id(agent_id)` | Get profile by numeric ID |
| `get_all_profiles(category=None)` | List all, optionally filtered by category |
| `get_customer_facing_profiles()` | For tenant provisioning (`is_customer_facing=True`) |
| `get_capable_agents(channel)` | Query by channel capability flag |
| `get_system_prompt(agent_type)` | Hot path for conversation pipeline; falls back to registry |
| `get_agent_definition(agent_type)` | Registry-compatible dict for orchestrator/server |
| `get_profiles_for_frontend()` | Slim format for frontend registry replacement |
| `get_public_identity(agent_type, company_id, base_url)` | **Public business card** — merges platform profile + per-company instance + channels. Never exposes system_prompt. |
| `get_public_directory(company_id, base_url)` | **Public agent directory** — all enabled + customer-facing agents for a company with URLs |
| `update_profile(agent_type, updates)` | Update fields; bumps version; superadmin only |
| `sync_from_registry()` | Re-seed missing profiles from AGENT_REGISTRY |

### Channel Capability Query

```python
svc = AgentProfileService(db)
email_agents = svc.get_capable_agents("email")
# → [Sarah, Jake, Morgan, Marcus, Alex, Annie, Emma, Gwen]

phone_agents = svc.get_capable_agents("phone")
# → [Sarah, Marcus, Emma]
```

**SQL executed:**
```sql
SELECT * FROM agent_profiles
WHERE capabilities->'channels'->>'email' = 'true'
ORDER BY agent_id
```

---

## REST API

### Agent Profiles API (`/api/v1/agent-profiles`)

| Endpoint | Method | Auth | Description |
|----------|--------|------|-------------|
| `/api/v1/agent-profiles` | GET | user | List all profiles |
| `/api/v1/agent-profiles?format=slim` | GET | user | Lightweight shape for frontend |
| `/api/v1/agent-profiles?category=core` | GET | user | Filter by category |
| `/api/v1/agent-profiles?channel=email` | GET | user | **New:** Only agents with that channel enabled |
| `/api/v1/agent-profiles/{agent_type}` | GET | user | Full profile for one agent |
| `/api/v1/agent-profiles/{agent_type}/prompt` | GET | user | Assembled system prompt |
| `/api/v1/agent-profiles/{agent_type}` | PUT | superadmin | Update profile fields |
| `/api/v1/agent-profiles/sync` | POST | superadmin | Re-seed from registry |

**Valid `channel` values:** `email`, `phone`, `sms`, `chat`, `voice`

### Agent Channels API (`/api/v1/agents/{id}/channels`)

| Endpoint | Method | Auth | Description |
|----------|--------|------|-------------|
| `/api/v1/agents/{agent_id}/channels` | GET | user | All channels assigned to this agent for the user's company |

**Response:**
```json
{
  "agent_id": 1,
  "company_id": 42,
  "email": [
    {"id": 10, "address": "sarah@acmeplumbing.com", "display_name": "Acme Support", "purpose": "support"}
  ],
  "phone": [
    {"id": 5, "number": "+18015551234", "friendly_name": "Main Line", "sms_enabled": true, "voice_enabled": true}
  ],
  "chat": [
    {"id": 3, "chat_id": "abc123xyz", "name": "Homepage Chat", "personality": "professional"}
  ],
  "summary": {
    "email_count": 1,
    "phone_count": 1,
    "chat_count": 1,
    "has_sms": true,
    "has_voice": true
  }
}
```

This endpoint queries three tables filtered by `company_id` + `agent_id`:
- `company_email_addresses.assigned_agent_id`
- `company_phone_numbers.agent_id`
- `chat_widgets.agent_id`

---

## Setup Wizard Integration

The setup wizard uses agent profiles to populate agent selection dropdowns:

### Email Agent Selection

**Endpoint:** `GET /api/v1/setup/email/available-agents`

Previously used a hardcoded list `[1, 2, 3, 4]`. Now queries:
```python
svc = AgentProfileService(db)
profiles = svc.get_capable_agents("email")
```

Returns agents with `capabilities.channels.email = true`, plus `capabilities.email_purpose` for each.

### Phone Agent Selection

**Endpoint:** `GET /api/v1/setup/phone/agents`

Previously used a hardcoded type list `["customer_service", "sales_followup", "marketing"]`. Now queries:
```python
profiles = svc.get_capable_agents("phone")
```

Falls back to registry if `agent_profiles` table is empty (pre-migration safety net).

### Adding New Capable Agents

To make a new agent appear in email/phone/chat dropdowns:

1. Update the agent's capabilities in `agent_profiles`:
```sql
UPDATE agent_profiles
SET capabilities = jsonb_set(capabilities, '{channels,email}', 'true')
WHERE agent_type = 'new_agent_type';
```

2. No code changes needed — the wizard reads from the table dynamically.

---

## Frontend Integration

### Agent Profile Page — Profile Tab

The agent detail page (`/dashboard/agents/[id]`) Profile tab now shows three data sources in parallel:

1. **Platform Identity** (from `GET /api/v1/agent-profiles/{agent_type}`)
   - Title, bio, purpose, default personality
   - Channel capability flags (email/phone/sms/chat/voice badges)

2. **Assigned Channels** (from `GET /api/v1/agents/{id}/channels`)
   - Email addresses assigned to this agent
   - Phone numbers with SMS/voice flags
   - Chat widgets with personality overrides

3. **Resume & Performance** (from `GET /api/v1/agents/{id}/resume`)
   - MCP tools by namespace
   - Reflection scores and history

All three fetched via `Promise.allSettled` for resilience — if one fails, others still render.

### Frontend API Client

**File:** `solid-frontend/src/lib/api/agents.ts`

```typescript
import { getAgentChannels, AgentChannelsResponse } from "@/lib/api/agents";

const channels = await getAgentChannels(agentId);
// channels.email, channels.phone, channels.chat, channels.summary
```

**File:** `solid-frontend/src/lib/api/agent-profiles.ts`

```typescript
import { getAgentProfile, AgentProfileFull } from "@/lib/api/agent-profiles";

const profile = await getAgentProfile("customer_service");
// profile.capabilities.channels, profile.title, profile.bio
```

---

## Migrations

| Migration | Revision ID | Purpose |
|-----------|-------------|---------|
| `agent_profiles_20260301.py` | `agent_profiles_20260301` | Create table + seed 26 agents from AGENT_REGISTRY |
| `agent_profiles_capabilities_20260302.py` | `agent_profiles_capabilities_20260302` | Populate capabilities JSON with channel flags per agent |

### Migration Chain

```
approval_reflect_20260228
  └─> agent_profiles_20260301 (create table + seed)
        └─> agent_profiles_capabilities_20260302 (populate capabilities)
```

---

## Consumers

| Consumer | File | What it reads |
|----------|------|---------------|
| Conversation pipeline | `agents/conversation.py` | `get_system_prompt()` |
| Orchestrator | `agents/orchestrator.py` | `get_agent_definition()` |
| AI Bridge | `services/ai/bridge.py` | `get_system_prompt()` |
| Server health | `agents/server.py` | `get_all_profiles()` |
| Tenant provisioning | `services/tenant_provisioning.py` | `get_customer_facing_profiles()` |
| Setup wizard (email) | `controllers/setup_wizard.py` | `get_capable_agents("email")` |
| Setup wizard (phone) | `controllers/setup_wizard.py` | `get_capable_agents("phone")` |
| **Public agent identity** | `controllers/agent_public.py` | `get_public_identity()` + `get_public_directory()` |
| Frontend registry | `agent-profiles.ts` | `GET /agent-profiles?format=slim` |
| Agent detail page | `agent-resume-tab.tsx` | `GET /agent-profiles/{type}` + `GET /agents/{id}/channels` |

---

## Relationship to AGENT_REGISTRY

`AGENT_REGISTRY` in `agents/registry.py` is the **legacy** source of truth. The `agent_profiles` table is the **new** source of truth.

**Fallback behavior:** If a profile is missing from the table, `AgentProfileService` falls back to `AGENT_REGISTRY`. This safety net ensures the system works even before the migration runs.

**Sync tool:** `POST /api/v1/agent-profiles/sync` (superadmin) creates missing profiles from the registry. Does NOT overwrite existing edits.

**Goal:** Eventually `AGENT_REGISTRY` becomes a seed source only, with all runtime reads going through `agent_profiles`. The registry stays in code for version control and as the initial seed.

---

## Related Documentation

| Document | Location |
|----------|----------|
| Agent Digital Identity (public addressing) | `03-AI-Systems/AGENT-DIGITAL-IDENTITY.md` |
| Agent Lifecycle (9 stages) | `03-AI-Systems/AGENT-LIFECYCLE.md` |
| Serialization & Identity (IDs vs names) | `03-AI-Systems/SERIALIZATION-AND-IDENTITY.md` |
| Agent Registry Map (all 32 AI agents) | `03-AI-Systems/AGENT-REGISTRY-MAP.md` |
| Setup Wizard Step Flow | `19-Onboarding/81-Setup-Wizard/V1-Current/02-STEP-FLOW.md` |
| CLI Agent Management | `47-Field-Manual/11-AGENT-MANAGEMENT.md` |

---

_Part of Owners Manual -- 03-AI-Systems_


--- FILE: 03-AI-Systems/KB-STATUS.md ---

---
topic: ai-systems
keywords: [AI, agents, MCP, SmartRouter, LLM, orchestration, knowledge-base]
code_paths:
  - agents/*.py
  - solid-backend/services/ai/kb_layer_analytics.py
  - agents/knowledge_graph/*.py
  - solid-backend/agents/kb_orchestrator.py
  - mcp/*.py
last_verified: 2026-08-29
status: current
priority: high
owner: platform-team
---

> **Verified 2026-08-29 against solid-backend:**
> - ~~"608 total MCP tools"~~ — stale. The canonical, derived MCP tool count is now 655 (`Owners-Manual/PLATFORM-METRICS.md`, generated by `scripts/platform_metrics.py`). Never hand-type this number again.
> - ~~"45 industry templates"~~ — stale. `scripts/templates/industries/` now has **58** industry template files (matches the canonical count in `Owners-Manual/PLATFORM-METRICS.md`).
> - ~~`models/knowledge_base.py` | Database models~~ — **wrong file**. `MasterKnowledgeBase`, `CompanyKnowledgeBase`, `KnowledgeBaseQA`, and `UnifiedAIContext` are defined in `solid-backend/models/unified_kb.py`, verified 2026-08-29. `models/knowledge_base.py` exists but defines a *different*, older model set (`KnowledgeBaseCategory`, `KnowledgeBaseArticle`, `ArticleTag`, `ArticleTagAssociation`, `ArticleAttachment`, `ArticleSearchIndex`) — not the 5 models this doc describes.
> - ~~`services/unified_kb_service.py` (1,950 lines)~~ — the file has grown to **2,833 lines** (verified via `wc -l`, 2026-08-29). Still the correct file/service.
> - `controllers/unified_kb_controller.py` — **confirmed 47 `@router` endpoints**, matching the "47 REST endpoints" claim exactly.
> - `mcp/tools/kb_*.py` — 11 files found (not literally "18 tools" as files), containing ~49 `def`/`async def` functions total. Could not confirm the exact "18 tools" figure maps to a specific registered-tool count — **left unverified**, treat with caution.
> - "1,071 KB entries in production" — a live-database row count; **not verifiable by static code review**, left unverified.

# Knowledge Base System - Current Status
**Last Updated:** 2025-11-24
**Status:** ✅ **PRODUCTION READY**

> **Note:** This is a quick status reference. For detailed architecture, schemas, and cross-references, see `KB_SYSTEM_INDEX.md` (the master index).

---

## Quick Status

| Component | Status | Notes |
|-----------|--------|-------|
| **Database Models** | ✅ COMPLETE | 5 models, all migrations run |
| **MCP Tools** | ✅ COMPLETE | 18 tools, 608 total MCP tools live |
| **Service Layer** | ✅ COMPLETE | UnifiedKnowledgeBaseService (1,950 lines) |
| **API Endpoints** | ✅ COMPLETE | 47 REST endpoints working |
| **Industry Templates** | ✅ COMPLETE | 45 templates, 211 business types |
| **KB Entries** | ✅ COMPLETE | 1,071 entries in production |
| **Coverage** | ✅ 100% | All business types covered |

---

## What's Working

### 1. Database (100% Complete)
- `MasterKnowledgeBase` - Platform-level KB
- `CompanyKnowledgeBase` - Company-specific KB
- `KnowledgeBaseQA` - Q&A entries
- `UnifiedAIContext` - AI context management
- Uses `ARRAY(Float)` for embeddings (works everywhere)

### 2. MCP Tools (100% Complete)
- 18 KB-specific tools
- 608 total MCP tools in production
- Search, create, update, delete, analytics

### 3. Service Layer (100% Complete)
- `services/unified_kb_service.py` (1,950 lines)
- Semantic search with embeddings
- Template cloning
- Multi-tenant isolation
- Automatic fallback (Company → Master → Platform)

### 4. API Endpoints (100% Complete)
- 47 REST endpoints
- Admin and user-facing APIs
- Full CRUD operations
- Analytics and search

### 5. Industry Templates (100% Complete)
- 45 industry templates
- 211 business types mapped
- All industries covered
- Auto-cloning on company creation

### 6. Production Data (100% Complete)
- 1,071 KB entries live
- Multi-tenant isolation working
- Real business data being used

---

## Architecture

### 3-Layer System
```
Layer 0: Platform KB   → "What is Solid#" (system prompts)
Layer 1: Master KB     → "What does Solid# do" (capabilities)
Layer 2: Company KB    → Company-specific data, policies, procedures
Layer 3: Customer KB   → Customer-specific interactions (optional)
```

### KB Types
- `platform` - Platform documentation
- `company` - Company-specific
- `master` - Master templates
- `{industry}` - Industry templates (mortgage_broker, plumber, etc.)

---

## What's NOT Complete

### Optional Future Enhancements
1. **Rep/Employee Layer** - Per-user KB isolation (not needed for MVP)
2. **Customer Layer** - Per-customer KB (not needed for MVP)
3. **Webhook Integration** - Auto-update KB from CRM events (post-MVP)
4. **Advanced Analytics** - Usage tracking, search analytics (post-MVP)

---

## Key Files

| File | Purpose |
|------|---------|
| ~~`models/knowledge_base.py`~~ → `models/unified_kb.py` | Database models (`MasterKnowledgeBase`, `CompanyKnowledgeBase`, `KnowledgeBaseQA`, `UnifiedAIContext`) — corrected 2026-08-29 |
| `services/unified_kb_service.py` | Core service (1,950 lines) |
| `controllers/unified_kb_controller.py` | REST API |
| `mcp/tools/kb_*.py` | MCP tools (18 tools) |
| `templates/*.py` | Industry templates (45 files) |

---

## Documentation Files

**This file replaces all 19 KB documentation files.**

All other KB_*.md files are legacy documentation from development and can be archived.

---

## Testing

✅ All tests passing:
- Unit tests for service layer
- Integration tests for MCP tools
- API endpoint tests
- Live production verification

---

## For Developers

**To use KB in your code:**
```python
from services.unified_kb_service import UnifiedKnowledgeBaseService

kb = UnifiedKnowledgeBaseService()
results = await kb.search_kb(
    company_id=1,
    query="What are our business hours?",
    kb_types=["company"],
    limit=5
)
```

**To use KB via MCP:**
```bash
curl "http://localhost:8090/api/v1/mcp/kb-context?company_id=1&kb_types=company"
```

**To use KB via REST API:**
```bash
curl "http://localhost:8090/api/v1/kb/search?company_id=1&q=hours"
```

---

**Status:** ✅ Production Ready
**Next Steps:** None - System is complete and operational


--- FILE: 19-Onboarding/00-BILLING-CRITICAL-INDEX.md ---

---
topic: onboarding
keywords: [onboarding]
code_paths:
  - solid-backend/controllers/platform_commerce_webhooks.py
  - solid-platform-commerce/scripts/monitor_session_isolation.py
last_verified: 2026-08-29
status: archived
priority: high
owner: platform-team
---

# 🚨 CRITICAL: Billing Documentation Index

> **RETIRED PROCESSOR:** The former "Solid Payments" / "Solid Pay" processor is retired — do not build against it; no single processor is core (see the Billing feedback in `CLAUDE.md`). Platform billing (Solid# → Company) runs on Stripe via Platform Commerce (swappable by design — see `solid-platform-commerce/ARCHITECTURE.md`). Tenant payments: every company connects its **own** processor through the adapter registry (`services/payments/registry.py`). Retired-processor material below is historical.

This index formerly pointed to a set of processor integration/security/auto-billing documents that have been removed as part of the retired processor decommission. Platform billing now runs on **Stripe via Platform Commerce** — see `solid-platform-commerce/ARCHITECTURE.md` (swappable by design). Tenant payments run through each merchant's **own** processor via the adapter registry (`services/payments/registry.py`). No processor integration remains to be maintained; this document is retained only as a historical placeholder.


--- END: 51 docs included ---
