The file D:\ClaudeTools\MSP-MODE-SPEC.md has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
  1371→8. **Maximum information density** - brief but complete
  1372→
  1373→User just works, Claude captures everything in structured, queryable format.
  1374→
  1375→### Normal Mode Behaviors (DEFINED)
  1376→
  1377→**Core Principle:** Track valuable work that doesn't belong to a specific client or dev project. General research, internal tasks, exploration, learning.
  1378→
  1379→#### Purpose
  1380→
  1381→Normal Mode is for:
  1382→- **Research and exploration** - "How does JWT authentication work?"
  1383→- **General questions** - "What's the best way to handle SQL migrations?"
  1384→- **Internal infrastructure** (non-client) - Working on Jupiter/Saturn without client context
  1385→- **Learning/experimentation** - Testing new tools, trying approaches
  1386→- **Documentation** - Writing guides, updating READMEs
  1387→- **Non-categorized work** - Anything that doesn't fit MSP or Dev
  1388→
  1389→**Not for:**
  1390→- Client work → Use MSP Mode
  1391→- Specific development projects → Use Dev Mode
  1392→
  1393→#### When `/normal` is Called
  1394→
  1395→1. **Mode Switch:**
  1396→   - If coming from MSP/Dev mode: preserve all knowledge/context from previous mode
  1397→   - Set session context to "general" (no client_id, no project_id)
  1398→   - Display: "Normal Mode | General work session"
  1399→
  1400→2. **Knowledge Retention:**
  1401→   - **Keep:** All learned information, credentials accessed, context from previous modes
  1402→   - **Clear:** Client/project assignment only
  1403→   - **Rationale:** You might research something in Normal mode, then apply it in MSP mode
  1404→
  1405→3. **Session Creation:**
  1406→   - Create session with:
  1407→     - client_id = NULL
  1408→     - project_id = NULL (or link to "Internal" or "Research" pseudo-project)
  1409→     - session_title = "General work session: [auto-generated from topic]"
  1410→     - is_billable = false (by default, since not client work)
  1411→
  1412→#### During Normal Mode Session
  1413→
  1414→**Tracking (lighter than MSP):**
  1415→- Still create work_items, but less granular
  1416→- Track major actions: "Researched FastAPI authentication patterns"
  1417→- Track useful findings: "Found pyjwt library, better than python-jose"
  1418→- Track decisions: "Decided to use Alembic for migrations"
  1419→
  1420→**What gets stored:**
  1421→- Work items with category (usually 'documentation', 'research', or 'development')
  1422→- Key commands run (if applicable)
  1423→- Files modified (if applicable)
  1424→- Tags: technology, topics
  1425→- Brief summary of what was learned/accomplished
  1426→
  1427→**What doesn't get stored:**
  1428→- Less emphasis on billability tracking
  1429→- No client/project relationships
  1430→- Less detailed command/file tracking (unless requested)
  1431→
  1432→#### Information Density in Normal Mode
  1433→
  1434→**Focus on:** Capturing useful knowledge, decisions, findings
  1435→
  1436→**Example Normal Mode work_item:**
  1437→```
  1438→Title: Researched PostgreSQL connection pooling for FastAPI
  1439→Category: research
  1440→Description: Compared SQLAlchemy pooling vs asyncpg.
  1441→Finding: SQLAlchemy pool_size=20, max_overflow=10 optimal for our load.
  1442→Decision: Use SQLAlchemy with pool_pre_ping=True for connection health checks.
  1443→Tags: postgresql, sqlalchemy, fastapi, connection-pooling
  1444→Billable: false
  1445→```
  1446→
  1447→**Not:** "I started by searching for PostgreSQL connection pooling documentation..."
  1448→
  1449→#### Session End (Normal Mode)
  1450→
  1451→**Auto-save:**
  1452→- session.client_id = NULL
  1453→- session.is_billable = false
  1454→- session.summary = brief summary of research/work done
  1455→
  1456→**Generated summary example:**
  1457→```
  1458→Session: General Research
  1459→Duration: 45 minutes
  1460→Category: Research
  1461→
  1462→Topics Explored:
  1463→- FastAPI database connection pooling
  1464→- JWT vs session authentication
  1465→- Alembic migration strategies
  1466→
  1467→Key Findings:
  1468→- SQLAlchemy pooling recommended for our use case
  1469→- JWT refresh tokens better than long-lived access tokens
  1470→- Alembic supports auto-generate from models
  1471→
  1472→Tags: fastapi, postgresql, jwt, alembic
  1473→Billable: No
  1474→```
  1475→
  1476→#### Value of Normal Mode Sessions
  1477→
  1478→**Why track this?**
  1479→1. **Knowledge base** - "What did I learn about X last month?"
  1480→2. **Decision trail** - "Why did we choose technology Y?"
  1481→3. **Reference** - "Where did I see that solution before?"
  1482→4. **Context recovery** - Future Claude instances can search: "Show me research on JWT authentication"
  1483→
  1484→**Queryable:**
  1485→- "What have I researched about Docker networking?"
  1486→- "When did I decide to use FastAPI over Flask?"
  1487→- "Show all sessions tagged 'postgresql'"
  1488→
  1489→#### Mode Comparison
  1490→
  1491→| Aspect | MSP Mode | Dev Mode | Normal Mode |
  1492→|--------|----------|----------|-------------|
  1493→| **Purpose** | Client work | Specific projects | General work/research |
  1494→| **Client/Project** | Required | Optional | None (NULL) |
  1495→| **Billable** | Default: yes | Default: no | Default: no |
  1496→| **Detail Level** | High (every command) | Medium | Light (key actions) |
  1497→| **Focus** | Client value delivery | Code/features | Knowledge/learning |
  1498→| **Session Title** | "[Client] - [Issue]" | "[Project] - [Feature]" | "Research: [Topic]" |
  1499→
  1500→#### Switching Between Modes
  1501→
  1502→**MSP → Normal:**
  1503→- User: "Let me research how to fix this SSL issue"
  1504→- `/normal` → Research mode, but can reference client context if needed
  1505→- Knowledge retained: knows which client, what SSL issue
  1506→- Categorization: research session, not billable client work
  1507→
  1508→**Normal → MSP:**
  1509→- User: "Okay, back to Dataforth"
  1510→- `/msp` → Resumes (or starts new) Dataforth session
  1511→- Knowledge retained: knows solution from research
  1512→- Categorization: client work, billable
  1513→
  1514→**Dev → Normal → MSP:**
  1515→- Modes are fluid, knowledge carries through
  1516→- Only categorization changes
  1517→- Session assignments change (project vs client vs general)
  1518→
  1519→---
  1520→
  1521→### Development Mode Behaviors (To Define)
  1522→1. What should Development Mode track?
  1523→2. How does it differ from MSP and Normal modes?
  1524→3. Integration with git repos?
  1525→
  1526→### Implementation Order
  1527→1. Database schema design
  1528→2. API development and deployment
  1529→3. MCP server or API client for Claude Code
  1530→4. MSP Mode slash command

### Normal Mode Behaviors (DEFINED)

**Core Principle:** Track valuable work that doesn't belong to a specific client or dev project. General research, internal tasks, exploration, learning.

#### Purpose

Normal Mode is for:
- **Research and exploration** - "How does JWT authentication work?"
- **General questions** - "What's the best way to handle SQL migrations?"
- **Internal infrastructure** (non-client) - Working on Jupiter/Saturn without client context
- **Learning/experimentation** - Testing new tools, trying approaches
- **Documentation** - Writing guides, updating READMEs
- **Non-categorized work** - Anything that doesn't fit MSP or Dev

**Not for:**
- Client work → Use MSP Mode
- Specific development projects → Use Dev Mode

#### When `/normal` is Called

1. **Mode Switch:**
   - If coming from MSP/Dev mode: preserve all knowledge/context from previous mode
   - Set session context to "general" (no client_id, no project_id)
   - Display: "Normal Mode | General work session"

2. **Knowledge Retention:**
   - **Keep:** All learned information, credentials accessed, context from previous modes
   - **Clear:** Client/project assignment only
   - **Rationale:** You might research something in Normal mode, then apply it in MSP mode

3. **Session Creation:**
   - Create session with:
     - client_id = NULL
     - project_id = NULL (or link to "Internal" or "Research" pseudo-project)
     - session_title = "General work session: [auto-generated from topic]"
     - is_billable = false (by default, since not client work)

#### During Normal Mode Session

**Tracking (lighter than MSP):**
- Still create work_items, but less granular
- Track major actions: "Researched FastAPI authentication patterns"
- Track useful findings: "Found pyjwt library, better than python-jose"
- Track decisions: "Decided to use Alembic for migrations"

**What gets stored:**
- Work items with category (usually 'documentation', 'research', or 'development')
- Key commands run (if applicable)
- Files modified (if applicable)
- Tags: technology, topics
- Brief summary of what was learned/accomplished

**What doesn't get stored:**
- Less emphasis on billability tracking
- No client/project relationships
- Less detailed command/file tracking (unless requested)

#### Information Density in Normal Mode

**Focus on:** Capturing useful knowledge, decisions, findings

**Example Normal Mode work_item:**
```
Title: Researched PostgreSQL connection pooling for FastAPI
Category: research
Description: Compared SQLAlchemy pooling vs asyncpg.
Finding: SQLAlchemy pool_size=20, max_overflow=10 optimal for our load.
Decision: Use SQLAlchemy with pool_pre_ping=True for connection health checks.
Tags: postgresql, sqlalchemy, fastapi, connection-pooling
Billable: false
```

**Not:** "I started by searching for PostgreSQL connection pooling documentation..."

#### Session End (Normal Mode)

**Auto-save:**
- session.client_id = NULL
- session.is_billable = false
- session.summary = brief summary of research/work done

**Generated summary example:**
```
Session: General Research
Duration: 45 minutes
Category: Research

Topics Explored:
- FastAPI database connection pooling
- JWT vs session authentication
- Alembic migration strategies

Key Findings:
- SQLAlchemy pooling recommended for our use case
- JWT refresh tokens better than long-lived access tokens
- Alembic supports auto-generate from models

Tags: fastapi, postgresql, jwt, alembic
Billable: No
```

#### Value of Normal Mode Sessions

**Why track this?**
1. **Knowledge base** - "What did I learn about X last month?"
2. **Decision trail** - "Why did we choose technology Y?"
3. **Reference** - "Where did I see that solution before?"
4. **Context recovery** - Future Claude instances can search: "Show me research on JWT authentication"

**Queryable:**
- "What have I researched about Docker networking?"
- "When did I decide to use FastAPI over Flask?"
- "Show all sessions tagged 'postgresql'"

#### Mode Comparison

| Aspect | MSP Mode | Dev Mode | Normal Mode |
|--------|----------|----------|-------------|
| **Purpose** | Client work | Specific projects | General work/research |
| **Client/Project** | Required | Optional | None (NULL) |
| **Billable** | Default: yes | Default: no | Default: no |
| **Detail Level** | High (every command) | Medium | Light (key actions) |
| **Focus** | Client value delivery | Code/features | Knowledge/learning |
| **Session Title** | "[Client] - [Issue]" | "[Project] - [Feature]" | "Research: [Topic]" |

#### Switching Between Modes

**MSP → Normal:**
- User: "Let me research how to fix this SSL issue"
- `/normal` → Research mode, but can reference client context if needed
- Knowledge retained: knows which client, what SSL issue
- Categorization: research session, not billable client work

**Normal → MSP:**
- User: "Okay, back to Dataforth"
- `/msp` → Resumes (or starts new) Dataforth session
- Knowledge retained: knows solution from research
- Categorization: client work, billable

**Dev → Normal → MSP:**
- Modes are fluid, knowledge carries through
- Only categorization changes
- Session assignments change (project vs client vs general)

---

### Development Mode Behaviors (To Define)
1. What should Development Mode track?
2. How does it differ from MSP and Normal modes?
3. Integration with git repos?

### Implementation Order

# MSP Mode Specification

**Date Started:** 2026-01-15
**Status:** Planning / Design Phase

---

## Overview

Creating a custom "MSP Mode" for Claude Code that tracks client work, maintains context across sessions and machines, and provides structured access to historical MSP data.

## Objectives

1. **Track MSP client work** - Sessions, work items, time, credentials
2. **Multi-machine access** - Same context available on all machines
3. **Long-term context** - Search historical work across clients/projects
4. **Scalable & robust** - Designed to evolve over time

---

## Architecture Decisions

### Storage: SQL Database (MariaDB)

**Decision:** Use SQL database instead of local files + Git sync

**Rationale:**
- Claude Code requires internet anyway (offline not a real advantage)
- Structured queries needed ("show all work for Client X in January")
- Relational data (clients → projects → sessions → credentials → billing)
- Fast indexing and search even with years of data
- No merge conflicts (single source of truth)
- Time tracking and billing calculations
- Report generation capabilities

**Infrastructure:**
- Existing MariaDB on Jupiter (172.16.3.20)
- New database: `msp_tracking`

### Access Method: REST API with JWT Authentication

**Decision:** FastAPI REST API on Jupiter with JWT tokens

**Rationale - Security:**
- Token-based auth (revocable, rotatable)
- Scoped permissions (API can't access other databases)
- Audit logging (track all queries by user/token/timestamp)
- Rate limiting possible
- HTTPS encryption in transit
- Token revocation without DB password changes
- IP restrictions and 2FA possible later

**Rationale - Scalability:**
- Industry standard approach
- Can add team members later
- Other tools can integrate (scripts, mobile, GuruRMM)
- Stateless authentication (no session storage)
- Multiple clients supported

**Rationale - Robustness:**
- Comprehensive error handling
- Input validation before DB access
- Structured logging
- Health checks and monitoring
- Version controlled schema migrations

### Technology Stack

**API Framework: FastAPI (Python)**
- Async performance for concurrent requests
- Auto-generated OpenAPI/Swagger documentation
- Type safety with Pydantic models (runtime validation)
- SQLAlchemy ORM for complex queries
- Built-in background tasks
- Industry-standard testing with pytest
- Alembic for database migrations
- Mature dependency injection

**Authentication: JWT Tokens**
- Stateless (no DB lookup to validate)
- Claims-based (permissions, scopes, expiration)
- Refresh token pattern for long-term access
- Multiple clients/machines supported
- Short-lived tokens minimize compromise risk
- Industry standard

**Configuration Storage: Gitea (Private Repo)**
- Multi-machine sync
- Version controlled
- Single source of truth
- Token rotation = one commit, all machines sync
- Encrypted token values (git-crypt or encrypted JSON)
- Backup via Gitea

**Deployment: Docker Container**
- Easy deployment and updates
- Resource limits
- Systemd service for auto-restart
- Portable (can migrate to dedicated host later)

---

## Infrastructure Design

### Jupiter Server (172.16.3.20)

**Docker Container: msp-api**
- FastAPI application (Python 3.11+)
- SQLAlchemy + Alembic (ORM and migrations)
- JWT auth library (python-jose)
- Pydantic validation
- Gunicorn/Uvicorn ASGI server
- Health checks endpoint
- Prometheus metrics (optional)
- Mounted logs: /var/log/msp-api/

**MariaDB Database: msp_tracking**
- Connection pooling (SQLAlchemy)
- Automated backups (critical MSP data)
- Schema versioned with Alembic

**Nginx Reverse Proxy**
- HTTPS with Let's Encrypt
- Rate limiting
- Access logs
- Proxies to: msp-api.azcomputerguru.com

### Gitea Private Repository

**Repo: azcomputerguru/claude-settings (or new msp-config repo)**

Structure:
```
msp-api-config.json
├── api_url (https://msp-api.azcomputerguru.com)
├── api_token (encrypted JWT or refresh token)
└── database_schema_version (for migration tracking)
```

### Local Machine (D:\ClaudeTools)

**Directory Structure:**
```
D:\ClaudeTools\
├── .claude/
│   ├── commands/
│   │   ├── msp.md (MSP Mode slash command)
│   │   ├── dev.md (Development Mode - TBD)
│   │   └── normal.md (Normal Mode - TBD)
│   └── msp-api-config.json (synced from Gitea)
├── MSP-MODE-SPEC.md (this file)
└── .git/ (synced to Gitea)
```

---

## API Design Principles

### Versioning
- Start with `/api/v1/` from day one
- Allows breaking changes in future versions

### Security
- All endpoints require JWT authentication
- Input validation with Pydantic models
- Never expose database errors to client
- Rate limiting to prevent abuse
- Comprehensive audit logging

### Endpoints (Draft - To Be Detailed)
```
POST   /api/v1/sessions          (start new MSP session)
GET    /api/v1/sessions          (query sessions - filters: client, date range, etc.)
POST   /api/v1/work-items        (log work performed)
GET    /api/v1/clients           (list clients)
POST   /api/v1/clients           (create client record)
GET    /api/v1/clients/{id}/credentials
POST   /api/v1/auth/token        (get JWT token)
POST   /api/v1/auth/refresh      (refresh expired token)
GET    /api/v1/health            (health check)
GET    /api/v1/metrics           (Prometheus metrics - optional)
```

### Error Handling
- Structured JSON error responses
- HTTP status codes (400, 401, 403, 404, 429, 500)
- Never leak sensitive information in errors
- Log all errors with context

### Logging
- JSON structured logs (easy parsing)
- Log levels: DEBUG, INFO, WARNING, ERROR, CRITICAL
- Include: timestamp, user/token ID, endpoint, duration, status
- Separate audit log for sensitive operations (credential access, deletions)

---

## JWT Token Structure

### Access Token (Short-lived: 1 hour)
```json
{
  "sub": "mike@azcomputerguru.com",
  "scopes": ["msp:read", "msp:write", "msp:admin"],
  "machine": "windows-workstation",
  "exp": 1234567890,
  "iat": 1234567890,
  "jti": "unique-token-id"
}
```

### Refresh Token (Long-lived: 30 days)
- Stored securely in Gitea config
- Used to obtain new access tokens
- Can be revoked server-side

### Scopes (Permissions)
- `msp:read` - Read sessions, clients, work items
- `msp:write` - Create/update sessions, work items
- `msp:admin` - Manage clients, credentials, delete operations

---

## Database Schema (Draft - To Be Detailed)

### Tables (High-Level)
```
clients
- id, name, network_cidr, primary_contact, notes, created_at, updated_at

projects
- id, client_id, name, description, status, created_at, updated_at

sessions
- id, project_id, start_time, end_time, billable_hours, notes, created_at

work_items
- id, session_id, description, category, timestamp, billable, created_at

credentials
- id, client_id, service, username, password_encrypted, notes, created_at, updated_at

tags (for categorization)
- id, name, type (client_tag, project_tag, work_tag)

session_tags (many-to-many)
- session_id, tag_id
```

### Schema Versioning
- Alembic migrations in version control
- Schema version tracked in config
- Automated migration on API startup (optional)

---

## Modes Overview (D:\ClaudeTools Context)

### 1. MSP Mode
- **Purpose:** Track client work, maintain context across sessions
- **Activation:** `/msp` slash command
- **Behaviors:** (To Be Detailed)
  - Prompt for client/project at start
  - Auto-log work items as we work
  - Track time spent
  - Save credentials securely
  - Generate session summary at end

### 2. Development Mode
- **Purpose:** (To Be Detailed)
- **Activation:** `/dev` slash command
- **Behaviors:** (To Be Detailed)

### 3. Normal Mode
- **Purpose:** Return to standard Claude behavior
- **Activation:** `/normal` slash command
- **Behaviors:** (To Be Detailed)
  - Clear active mode context
  - Standard conversational Claude

---

## Database Schema Design

**Status:** ✅ Analyzed via 5 parallel agents on 2026-01-15

Based on comprehensive analysis of:
- 37 session logs (Dec 2025 - Jan 2026)
- shared-data/credentials.md
- All project directories and documentation
- Infrastructure and client network patterns

### Schema Summary

**Total Tables:** 22 core tables + 5 junction tables = **27 tables**

**Categories:**
1. Core MSP Tracking (5 tables)
2. Client & Infrastructure (7 tables)
3. Credentials & Security (4 tables)
4. Work Details (6 tables)
5. Tagging & Categorization (3 tables)
6. System & Audit (2 tables)

---

### 1. Core MSP Tracking Tables (5 tables)

#### `clients`
Master table for all client organizations.

```sql
CREATE TABLE clients (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name VARCHAR(255) NOT NULL UNIQUE,
    type VARCHAR(50) NOT NULL CHECK(type IN ('msp_client', 'internal', 'project')),
    network_subnet VARCHAR(100), -- e.g., "192.168.0.0/24"
    domain_name VARCHAR(255), -- AD domain or primary domain
    m365_tenant_id UUID, -- Microsoft 365 tenant ID
    primary_contact VARCHAR(255),
    notes TEXT,
    is_active BOOLEAN DEFAULT true,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_clients_type (type),
    INDEX idx_clients_name (name)
);
```

**Examples:** Dataforth, Grabb & Durando, Valley Wide Plastering, AZ Computer Guru (internal)

---

#### `projects`
Individual projects/engagements for clients.

```sql
CREATE TABLE projects (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
    name VARCHAR(255) NOT NULL,
    slug VARCHAR(255) UNIQUE, -- directory name: "dataforth-dos"
    category VARCHAR(50) CHECK(category IN (
        'client_project', 'internal_product', 'infrastructure',
        'website', 'development_tool', 'documentation'
    )),
    status VARCHAR(50) DEFAULT 'working' CHECK(status IN (
        'complete', 'working', 'blocked', 'pending', 'critical', 'deferred'
    )),
    priority VARCHAR(20) CHECK(priority IN ('critical', 'high', 'medium', 'low')),
    description TEXT,
    started_date DATE,
    target_completion_date DATE,
    completed_date DATE,
    estimated_hours DECIMAL(10,2),
    actual_hours DECIMAL(10,2),
    gitea_repo_url VARCHAR(500),
    notes TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_projects_client (client_id),
    INDEX idx_projects_status (status),
    INDEX idx_projects_slug (slug)
);
```

**Examples:** dataforth-dos, gururmm, grabb-website-move

---

#### `sessions`
Work sessions with time tracking.

```sql
CREATE TABLE sessions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    client_id UUID REFERENCES clients(id) ON DELETE SET NULL,
    project_id UUID REFERENCES projects(id) ON DELETE SET NULL,
    session_date DATE NOT NULL,
    start_time TIMESTAMP,
    end_time TIMESTAMP,
    duration_minutes INTEGER, -- auto-calculated or manual
    status VARCHAR(50) DEFAULT 'completed' CHECK(status IN (
        'completed', 'in_progress', 'blocked', 'pending'
    )),
    session_title VARCHAR(500) NOT NULL,
    summary TEXT, -- markdown summary
    is_billable BOOLEAN DEFAULT false,
    billable_hours DECIMAL(10,2),
    technician VARCHAR(255), -- "Mike Swanson", etc.
    session_log_file VARCHAR(500), -- path to .md file
    notes TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_sessions_client (client_id),
    INDEX idx_sessions_project (project_id),
    INDEX idx_sessions_date (session_date),
    INDEX idx_sessions_billable (is_billable)
);
```

---

#### `work_items`
Individual tasks/actions within sessions (granular tracking).

```sql
CREATE TABLE work_items (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
    category VARCHAR(50) NOT NULL CHECK(category IN (
        'infrastructure', 'troubleshooting', 'configuration',
        'development', 'maintenance', 'security', 'documentation'
    )),
    title VARCHAR(500) NOT NULL,
    description TEXT NOT NULL,
    status VARCHAR(50) DEFAULT 'completed' CHECK(status IN (
        'completed', 'in_progress', 'blocked', 'pending', 'deferred'
    )),
    priority VARCHAR(20) CHECK(priority IN ('critical', 'high', 'medium', 'low')),
    is_billable BOOLEAN DEFAULT false,
    estimated_minutes INTEGER,
    actual_minutes INTEGER,
    affected_systems TEXT, -- JSON array: ["jupiter", "172.16.3.20"]
    technologies_used TEXT, -- JSON array: ["docker", "mariadb"]
    item_order INTEGER, -- sequence within session
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    completed_at TIMESTAMP,

    INDEX idx_work_items_session (session_id),
    INDEX idx_work_items_category (category),
    INDEX idx_work_items_status (status)
);
```

**Categories distribution (from analysis):**
- Infrastructure: 30%
- Troubleshooting: 25%
- Configuration: 15%
- Development: 15%
- Maintenance: 10%
- Security: 5%

---

#### `pending_tasks`
Open items across all clients/projects.

```sql
CREATE TABLE pending_tasks (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    client_id UUID REFERENCES clients(id) ON DELETE CASCADE,
    project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
    work_item_id UUID REFERENCES work_items(id) ON DELETE SET NULL,
    title VARCHAR(500) NOT NULL,
    description TEXT,
    priority VARCHAR(20) CHECK(priority IN ('critical', 'high', 'medium', 'low')),
    blocked_by TEXT, -- what's blocking this
    assigned_to VARCHAR(255),
    due_date DATE,
    status VARCHAR(50) DEFAULT 'pending' CHECK(status IN (
        'pending', 'in_progress', 'blocked', 'completed', 'cancelled'
    )),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    completed_at TIMESTAMP,

    INDEX idx_pending_tasks_client (client_id),
    INDEX idx_pending_tasks_status (status),
    INDEX idx_pending_tasks_priority (priority)
);
```

---

### 2. Client & Infrastructure Tables (7 tables)

#### `sites`
Physical/logical locations for clients.

```sql
CREATE TABLE sites (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
    name VARCHAR(255) NOT NULL, -- "Main Office", "SLC - Salt Lake City"
    network_subnet VARCHAR(100), -- "172.16.9.0/24"
    vpn_required BOOLEAN DEFAULT false,
    vpn_subnet VARCHAR(100), -- "192.168.1.0/24"
    gateway_ip VARCHAR(45), -- IPv4/IPv6
    dns_servers TEXT, -- JSON array
    notes TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_sites_client (client_id)
);
```

---

#### `infrastructure`
Servers, network devices, NAS, workstations.

```sql
CREATE TABLE infrastructure (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    client_id UUID REFERENCES clients(id) ON DELETE CASCADE,
    site_id UUID REFERENCES sites(id) ON DELETE SET NULL,
    asset_type VARCHAR(50) NOT NULL CHECK(asset_type IN (
        'physical_server', 'virtual_machine', 'container',
        'network_device', 'nas_storage', 'workstation',
        'firewall', 'domain_controller'
    )),
    hostname VARCHAR(255) NOT NULL,
    ip_address VARCHAR(45),
    mac_address VARCHAR(17),
    os VARCHAR(255), -- "Ubuntu 22.04", "Windows Server 2022", "Unraid"
    role_description TEXT, -- "Primary DC, NPS/RADIUS server"
    parent_host_id UUID REFERENCES infrastructure(id) ON DELETE SET NULL, -- for VMs/containers
    status VARCHAR(50) DEFAULT 'active' CHECK(status IN (
        'active', 'migration_source', 'migration_destination', 'decommissioned'
    )),
    notes TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_infrastructure_client (client_id),
    INDEX idx_infrastructure_type (asset_type),
    INDEX idx_infrastructure_hostname (hostname),
    INDEX idx_infrastructure_parent (parent_host_id)
);
```

**Examples:** Jupiter, AD2 (Dataforth), VWP-DC1, D2TESTNAS

---

#### `services`
Applications/services running on infrastructure.

```sql
CREATE TABLE services (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    infrastructure_id UUID REFERENCES infrastructure(id) ON DELETE CASCADE,
    service_name VARCHAR(255) NOT NULL, -- "Gitea", "PostgreSQL", "Apache"
    service_type VARCHAR(100), -- "git_hosting", "database", "web_server"
    external_url VARCHAR(500), -- "https://git.azcomputerguru.com"
    internal_url VARCHAR(500), -- "http://172.16.3.20:3000"
    port INTEGER,
    protocol VARCHAR(50), -- "https", "ssh", "smb"
    status VARCHAR(50) DEFAULT 'running' CHECK(status IN (
        'running', 'stopped', 'error', 'maintenance'
    )),
    version VARCHAR(100),
    notes TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_services_infrastructure (infrastructure_id),
    INDEX idx_services_name (service_name),
    INDEX idx_services_type (service_type)
);
```

---

#### `service_relationships`
Dependencies and relationships between services.

```sql
CREATE TABLE service_relationships (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    from_service_id UUID NOT NULL REFERENCES services(id) ON DELETE CASCADE,
    to_service_id UUID NOT NULL REFERENCES services(id) ON DELETE CASCADE,
    relationship_type VARCHAR(50) NOT NULL CHECK(relationship_type IN (
        'hosted_on', 'proxied_by', 'authenticates_via',
        'backend_for', 'depends_on', 'replicates_to'
    )),
    notes TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    UNIQUE(from_service_id, to_service_id, relationship_type),
    INDEX idx_service_rel_from (from_service_id),
    INDEX idx_service_rel_to (to_service_id)
);
```

**Examples:**
- Gitea (proxied_by) NPM
- GuruRMM API (hosted_on) Jupiter container

---

#### `networks`
Network segments, VLANs, VPN networks.

```sql
CREATE TABLE networks (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    client_id UUID REFERENCES clients(id) ON DELETE CASCADE,
    site_id UUID REFERENCES sites(id) ON DELETE CASCADE,
    network_name VARCHAR(255) NOT NULL,
    network_type VARCHAR(50) CHECK(network_type IN (
        'lan', 'vpn', 'vlan', 'isolated', 'dmz'
    )),
    cidr VARCHAR(100) NOT NULL, -- "192.168.0.0/24"
    gateway_ip VARCHAR(45),
    vlan_id INTEGER,
    notes TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_networks_client (client_id),
    INDEX idx_networks_site (site_id)
);
```

---

#### `firewall_rules`
Network security rules (for documentation/audit trail).

```sql
CREATE TABLE firewall_rules (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    infrastructure_id UUID REFERENCES infrastructure(id) ON DELETE CASCADE,
    rule_name VARCHAR(255),
    source_cidr VARCHAR(100),
    destination_cidr VARCHAR(100),
    port INTEGER,
    protocol VARCHAR(20), -- "tcp", "udp", "icmp"
    action VARCHAR(20) CHECK(action IN ('allow', 'deny', 'drop')),
    rule_order INTEGER,
    notes TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    created_by VARCHAR(255),

    INDEX idx_firewall_infra (infrastructure_id)
);
```

---

#### `m365_tenants`
Microsoft 365 tenant tracking.

```sql
CREATE TABLE m365_tenants (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    client_id UUID REFERENCES clients(id) ON DELETE CASCADE,
    tenant_id UUID NOT NULL UNIQUE, -- Microsoft tenant ID
    tenant_name VARCHAR(255), -- "dataforth.com"
    default_domain VARCHAR(255), -- "dataforthcorp.onmicrosoft.com"
    admin_email VARCHAR(255),
    cipp_name VARCHAR(255), -- name in CIPP portal
    notes TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_m365_client (client_id),
    INDEX idx_m365_tenant_id (tenant_id)
);
```

---

### 3. Credentials & Security Tables (4 tables)

#### `credentials`
Encrypted credential storage (values encrypted at rest).

```sql
CREATE TABLE credentials (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    client_id UUID REFERENCES clients(id) ON DELETE CASCADE,
    service_id UUID REFERENCES services(id) ON DELETE CASCADE,
    infrastructure_id UUID REFERENCES infrastructure(id) ON DELETE CASCADE,
    credential_type VARCHAR(50) NOT NULL CHECK(credential_type IN (
        'password', 'api_key', 'oauth', 'ssh_key',
        'shared_secret', 'jwt', 'connection_string', 'certificate'
    )),
    service_name VARCHAR(255) NOT NULL, -- "Gitea Admin", "AD2 sysadmin"
    username VARCHAR(255),
    password_encrypted BYTEA, -- AES-256-GCM encrypted
    api_key_encrypted BYTEA,
    client_id_oauth VARCHAR(255), -- for OAuth
    client_secret_encrypted BYTEA,
    tenant_id_oauth VARCHAR(255),
    public_key TEXT, -- for SSH
    token_encrypted BYTEA,
    connection_string_encrypted BYTEA,
    integration_code VARCHAR(255), -- for services like Autotask

    -- Metadata
    external_url VARCHAR(500),
    internal_url VARCHAR(500),
    custom_port INTEGER,
    role_description VARCHAR(500),
    requires_vpn BOOLEAN DEFAULT false,
    requires_2fa BOOLEAN DEFAULT false,
    ssh_key_auth_enabled BOOLEAN DEFAULT false,
    access_level VARCHAR(100),

    -- Lifecycle
    expires_at TIMESTAMP,
    last_rotated_at TIMESTAMP,
    is_active BOOLEAN DEFAULT true,

    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_credentials_client (client_id),
    INDEX idx_credentials_service (service_id),
    INDEX idx_credentials_type (credential_type),
    INDEX idx_credentials_active (is_active)
);
```

**Security:**
- All sensitive fields encrypted with AES-256-GCM
- Encryption key stored separately (environment variable or vault)
- Master password unlock mechanism

---

#### `credential_audit_log`
Audit trail for credential access.

```sql
CREATE TABLE credential_audit_log (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    credential_id UUID NOT NULL REFERENCES credentials(id) ON DELETE CASCADE,
    action VARCHAR(50) NOT NULL CHECK(action IN (
        'view', 'create', 'update', 'delete', 'rotate', 'decrypt'
    )),
    user_id VARCHAR(255) NOT NULL, -- JWT sub claim
    ip_address VARCHAR(45),
    user_agent TEXT,
    details TEXT, -- JSON: what changed, why
    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_cred_audit_credential (credential_id),
    INDEX idx_cred_audit_user (user_id),
    INDEX idx_cred_audit_timestamp (timestamp)
);
```

---

#### `security_incidents`
Track security events and remediation.

```sql
CREATE TABLE security_incidents (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    client_id UUID REFERENCES clients(id) ON DELETE CASCADE,
    service_id UUID REFERENCES services(id) ON DELETE SET NULL,
    infrastructure_id UUID REFERENCES infrastructure(id) ON DELETE SET NULL,
    incident_type VARCHAR(100) CHECK(incident_type IN (
        'bec', 'backdoor', 'malware', 'unauthorized_access',
        'data_breach', 'phishing', 'ransomware', 'brute_force'
    )),
    incident_date TIMESTAMP NOT NULL,
    severity VARCHAR(50) CHECK(severity IN ('critical', 'high', 'medium', 'low')),
    description TEXT NOT NULL,
    findings TEXT, -- investigation results
    remediation_steps TEXT,
    status VARCHAR(50) DEFAULT 'investigating' CHECK(status IN (
        'investigating', 'contained', 'resolved', 'monitoring'
    )),
    resolved_at TIMESTAMP,
    notes TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_incidents_client (client_id),
    INDEX idx_incidents_type (incident_type),
    INDEX idx_incidents_status (status)
);
```

**Examples:** BG Builders OAuth backdoor, CW Concrete BEC

---

#### `credential_permissions`
Access control for credentials (future team expansion).

```sql
CREATE TABLE credential_permissions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    credential_id UUID NOT NULL REFERENCES credentials(id) ON DELETE CASCADE,
    user_id VARCHAR(255) NOT NULL, -- or role_id
    permission_level VARCHAR(50) CHECK(permission_level IN ('read', 'write', 'admin')),
    granted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    granted_by VARCHAR(255),

    UNIQUE(credential_id, user_id),
    INDEX idx_cred_perm_credential (credential_id),
    INDEX idx_cred_perm_user (user_id)
);
```

---

### 4. Work Details Tables (6 tables)

#### `file_changes`
Track files created/modified/deleted during sessions.

```sql
CREATE TABLE file_changes (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    work_item_id UUID NOT NULL REFERENCES work_items(id) ON DELETE CASCADE,
    session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
    file_path VARCHAR(1000) NOT NULL,
    change_type VARCHAR(50) CHECK(change_type IN (
        'created', 'modified', 'deleted', 'renamed', 'backed_up'
    )),
    backup_path VARCHAR(1000),
    size_bytes BIGINT,
    description TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_file_changes_work_item (work_item_id),
    INDEX idx_file_changes_session (session_id)
);
```

---

#### `commands_run`
Shell/PowerShell/SQL commands executed.

```sql
CREATE TABLE commands_run (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    work_item_id UUID NOT NULL REFERENCES work_items(id) ON DELETE CASCADE,
    session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
    command_text TEXT NOT NULL,
    host VARCHAR(255), -- where executed: "jupiter", "172.16.3.20"
    shell_type VARCHAR(50), -- "bash", "powershell", "sql", "docker"
    success BOOLEAN,
    output_summary TEXT, -- first/last lines or error
    execution_order INTEGER, -- sequence within work item
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_commands_work_item (work_item_id),
    INDEX idx_commands_session (session_id),
    INDEX idx_commands_host (host)
);
```

---

#### `infrastructure_changes`
Audit trail for infrastructure modifications.

```sql
CREATE TABLE infrastructure_changes (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    work_item_id UUID NOT NULL REFERENCES work_items(id) ON DELETE CASCADE,
    session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
    infrastructure_id UUID REFERENCES infrastructure(id) ON DELETE SET NULL,
    change_type VARCHAR(50) CHECK(change_type IN (
        'dns', 'firewall', 'routing', 'ssl', 'container',
        'service_config', 'hardware', 'network', 'storage'
    )),
    target_system VARCHAR(255) NOT NULL,
    before_state TEXT,
    after_state TEXT,
    is_permanent BOOLEAN DEFAULT true,
    rollback_procedure TEXT,
    verification_performed BOOLEAN DEFAULT false,
    verification_notes TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_infra_changes_work_item (work_item_id),
    INDEX idx_infra_changes_session (session_id),
    INDEX idx_infra_changes_infrastructure (infrastructure_id)
);
```

---

#### `problem_solutions`
Issue tracking with root cause and resolution.

```sql
CREATE TABLE problem_solutions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    work_item_id UUID NOT NULL REFERENCES work_items(id) ON DELETE CASCADE,
    session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
    problem_description TEXT NOT NULL,
    symptom TEXT, -- what user saw
    error_message TEXT, -- exact error code/message
    investigation_steps TEXT, -- JSON array of diagnostic commands
    root_cause TEXT,
    solution_applied TEXT NOT NULL,
    verification_method TEXT,
    rollback_plan TEXT,
    recurrence_count INTEGER DEFAULT 1, -- if same problem reoccurs
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_problems_work_item (work_item_id),
    INDEX idx_problems_session (session_id)
);
```

---

#### `deployments`
Track software/config deployments.

```sql
CREATE TABLE deployments (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    work_item_id UUID NOT NULL REFERENCES work_items(id) ON DELETE CASCADE,
    session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
    infrastructure_id UUID REFERENCES infrastructure(id) ON DELETE SET NULL,
    service_id UUID REFERENCES services(id) ON DELETE SET NULL,
    deployment_type VARCHAR(50) CHECK(deployment_type IN (
        'code', 'config', 'database', 'container', 'service_restart'
    )),
    version VARCHAR(100),
    description TEXT,
    deployed_from VARCHAR(500), -- source path or repo
    deployed_to VARCHAR(500), -- destination
    rollback_available BOOLEAN DEFAULT false,
    rollback_procedure TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_deployments_work_item (work_item_id),
    INDEX idx_deployments_infrastructure (infrastructure_id),
    INDEX idx_deployments_service (service_id)
);
```

---

#### `database_changes`
Track database schema/data modifications.

```sql
CREATE TABLE database_changes (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    work_item_id UUID NOT NULL REFERENCES work_items(id) ON DELETE CASCADE,
    session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
    database_name VARCHAR(255) NOT NULL,
    infrastructure_id UUID REFERENCES infrastructure(id) ON DELETE SET NULL,
    change_type VARCHAR(50) CHECK(change_type IN (
        'schema', 'data', 'index', 'optimization', 'cleanup', 'migration'
    )),
    sql_executed TEXT,
    rows_affected BIGINT,
    size_freed_bytes BIGINT, -- for cleanup operations
    backup_taken BOOLEAN DEFAULT false,
    backup_location VARCHAR(500),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_db_changes_work_item (work_item_id),
    INDEX idx_db_changes_database (database_name)
);
```

---

### 5. Tagging & Categorization Tables (3 tables)

#### `tags`
Flexible tagging system for work items.

```sql
CREATE TABLE tags (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name VARCHAR(100) UNIQUE NOT NULL,
    category VARCHAR(50) CHECK(category IN (
        'technology', 'client', 'infrastructure',
        'problem_type', 'action', 'service'
    )),
    description TEXT,
    usage_count INTEGER DEFAULT 0, -- auto-increment on use
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_tags_category (category),
    INDEX idx_tags_name (name)
);
```

**Pre-populated tags:** 157+ tags identified from analysis
- 58 technology tags (docker, postgresql, apache, etc.)
- 24 infrastructure tags (jupiter, saturn, pfsense, etc.)
- 20+ client tags
- 30 problem type tags (connection-timeout, ssl-error, etc.)
- 25 action tags (migration, upgrade, cleanup, etc.)

---

#### `work_item_tags` (Junction Table)
Many-to-many relationship: work items ↔ tags.

```sql
CREATE TABLE work_item_tags (
    work_item_id UUID NOT NULL REFERENCES work_items(id) ON DELETE CASCADE,
    tag_id UUID NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
    PRIMARY KEY (work_item_id, tag_id),

    INDEX idx_wit_work_item (work_item_id),
    INDEX idx_wit_tag (tag_id)
);
```

---

#### `session_tags` (Junction Table)
Many-to-many relationship: sessions ↔ tags.

```sql
CREATE TABLE session_tags (
    session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
    tag_id UUID NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
    PRIMARY KEY (session_id, tag_id),

    INDEX idx_st_session (session_id),
    INDEX idx_st_tag (tag_id)
);
```

---

### 6. System & Audit Tables (2 tables)

#### `api_audit_log`
Track all API requests for security and debugging.

```sql
CREATE TABLE api_audit_log (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id VARCHAR(255) NOT NULL, -- JWT sub claim
    endpoint VARCHAR(500) NOT NULL, -- "/api/v1/sessions"
    http_method VARCHAR(10), -- GET, POST, PUT, DELETE
    ip_address VARCHAR(45),
    user_agent TEXT,
    request_body TEXT, -- sanitized (no credentials)
    response_status INTEGER, -- 200, 401, 500
    response_time_ms INTEGER,
    error_message TEXT,
    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_api_audit_user (user_id),
    INDEX idx_api_audit_endpoint (endpoint),
    INDEX idx_api_audit_timestamp (timestamp),
    INDEX idx_api_audit_status (response_status)
);
```

---

#### `schema_migrations`
Track database schema versions (Alembic migrations).

```sql
CREATE TABLE schema_migrations (
    version_id VARCHAR(100) PRIMARY KEY,
    description TEXT,
    applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    applied_by VARCHAR(255),
    migration_sql TEXT
);
```

---

### Junction Tables Summary

1. **work_item_tags** - Work items ↔ Tags
2. **session_tags** - Sessions ↔ Tags
3. **project_relationships** (optional) - Projects ↔ Projects (related/dependent)
4. **project_session_logs** (optional) - Projects ↔ Sessions (many-to-many if sessions span multiple projects)

---

### Schema Statistics

**Total Tables:** 27
- Core MSP: 5 tables
- Client & Infrastructure: 7 tables
- Credentials & Security: 4 tables
- Work Details: 6 tables
- Tagging: 3 tables (+ 2 junction)
- System: 2 tables

**Estimated Row Counts (1 year of MSP work):**
- sessions: ~500-1000 (2-3 per day)
- work_items: ~5,000-10,000 (5-10 per session)
- file_changes: ~10,000
- commands_run: ~20,000
- tags: ~200
- clients: ~50
- projects: ~100
- credentials: ~500
- api_audit_log: ~100,000+

**Storage Estimate:** ~1-2 GB per year (compressed)

---

### Design Principles Applied

1. **Normalized Structure** - Minimizes data duplication
2. **Flexible Tagging** - Supports evolving categorization
3. **Audit Trail** - Comprehensive logging for security and troubleshooting
4. **Scalability** - Designed for multi-user MSP team growth
5. **Security First** - Encrypted credentials, access control, audit logging
6. **Temporal Tracking** - created_at, updated_at, completed_at timestamps
7. **Soft Deletes** - is_active flags allow recovery
8. **Relationships** - Foreign keys enforce referential integrity
9. **Indexes** - Strategic indexes for common query patterns
10. **JSON Flexibility** - JSON fields for arrays/flexible data (affected_systems, technologies_used)

---

## Next Steps for Database Implementation

1. ✅ Schema designed (27 tables, relationships defined)
2. ⏳ Create Alembic migration files
3. ⏳ Set up encryption key management
4. ⏳ Seed initial data (tags, MSP infrastructure)
5. ⏳ Create database on Jupiter MariaDB
6. ⏳ Build FastAPI models (SQLAlchemy + Pydantic)
7. ⏳ Implement API endpoints
8. ⏳ Create authentication flow
9. ⏳ Build MSP Mode slash command integration

---

## Open Questions

### MSP Mode Behaviors (DEFINED)

**Core Principle:** Automatically categorize client interactions and store useful data in brief but information-dense format.

#### When `/msp` is Called (Session Start)

1. **Client/Project Detection:**
   - Auto-detect from context if possible (mentions of client names, domains, IPs)
   - If ambiguous, present quick-select list of recent clients
   - Prompt: "Working on: [Client] - [Project]? (or select different)"

2. **Session Initialization:**
   - Start timer automatically
   - Create session record with:
     - session_date (today)
     - start_time (now)
     - client_id, project_id (detected or selected)
     - status = 'in_progress'

3. **Context Display:**
   - Show brief summary: "MSP Mode: [Client] - [Project] | Started: [time]"
   - Load relevant context: recent sessions, open tasks, credentials for this client

#### During Session (Automatic Tracking)

**Auto-Categorization - Work Items:**
As work progresses, Claude automatically creates work_items with:

- **Category detection:**
  - Keywords trigger categories:
    - "ssh", "docker restart" → infrastructure
    - "error", "not working", "broken" → troubleshooting
    - "configure", "setup", "change settings" → configuration
    - "build", "code", "implement" → development
    - "cleanup", "optimize", "backup" → maintenance
    - "malware", "breach", "unauthorized" → security

- **Technology tagging:**
  - Auto-detect from commands/context: docker, apache, mariadb, m365, etc.
  - Add to work_item.technologies_used array

- **Affected systems:**
  - Extract IPs, hostnames from commands
  - Add to work_item.affected_systems array

**Information-Dense Data Capture:**

1. **Commands Run:**
   - Auto-log every bash/powershell/SQL command executed
   - Store: command_text, host, shell_type, success, output_summary (first/last 5 lines)
   - Link to current work_item

2. **File Changes:**
   - Track when files are read/edited/written
   - Store: file_path, change_type, backup_path (if created), size_bytes
   - Brief description (auto-generated: "Modified Apache config for SSL")

3. **Problems & Solutions:**
   - When user describes an error, auto-create problem_solution record:
     - symptom: "Users can't access website"
     - error_message: "ERR_CONNECTION_TIMED_OUT"
     - investigation_steps: [array of diagnostic commands]
     - root_cause: "Firewall blocking port 443"
     - solution_applied: "Added iptables ACCEPT rule for 443"
     - verification_method: "curl test successful"

4. **Credentials Accessed:**
   - When retrieving credentials, log to credential_audit_log:
     - action: 'decrypt' or 'view'
     - credential_id
     - user_id (from JWT)
     - timestamp
   - Don't log the actual credential value (security)

5. **Infrastructure Changes:**
   - Detect infrastructure modifications:
     - DNS changes → change_type: 'dns'
     - Firewall rules → change_type: 'firewall'
     - Service configs → change_type: 'service_config'
   - Store before_state, after_state, rollback_procedure

**Concise Summaries:**
- Auto-generate brief descriptions:
  - Work item title: "Fixed Apache SSL certificate expiration on jupiter"
  - Problem description: "Website down: cert expired, renewed via certbot, verified"
  - Not verbose: avoid "I then proceeded to...", just facts

#### Billability Detection

**Auto-flag billable work:**
- Client work (non-internal) → is_billable = true by default
- Internal infrastructure → is_billable = false
- User can override with quick command: "/billable false"

**Time allocation:**
- Track time per work_item (start when created, end when completed)
- Aggregate to session total

#### Session End Behavior

**When `/msp end` or `/normal` is called:**

1. **Auto-save to database:**
   - End timer (session.end_time = now)
   - Calculate session.duration_minutes
   - Set session.status = 'completed'

2. **Generate dense summary:**
   ```
   Session: [Client] - [Project]
   Duration: [duration]
   Category: [primary category based on work_items]

   Work Completed:
   - [Concise bullet: category, title, affected systems]
   - [Another item]

   Problems Solved: [count]
   - [Error] → [Solution]

   Infrastructure Changes: [count]
   - [System]: [change type] - [brief description]

   Commands Run: [count] | Files Modified: [count]
   Technologies: [tag list]

   Billable: [yes/no] | Hours: [calculated]
   ```

3. **Prompt for review:**
   - "Save session? (y/n)"
   - "Billable hours: [auto-calculated] - adjust? (or press Enter)"
   - "Add notes? (or press Enter to skip)"

4. **Store to database:**
   - POST to API: /api/v1/sessions (complete session object)
   - Include all related: work_items, commands_run, file_changes, etc.
   - API returns session_id

5. **Generate session log file (optional):**
   - Create markdown file in session-logs/
   - Format similar to current session logs but auto-generated
   - Include all dense information captured

#### Information Density Examples

**Dense (Good):**
```
Problem: Apache crash on jupiter
Error: segfault in mod_php
Cause: PHP 8.1 incompatibility
Fix: Downgraded to PHP 7.4, restarted apache
Verify: Website loads, no errors in logs
Files: /etc/apache2/mods-enabled/php*.conf
Commands: 3 (apt, systemctl, curl)
```

**Verbose (Avoid):**
```
I first investigated the Apache crash by checking the error logs.
Then I noticed that there was a segmentation fault in the mod_php module.
After some research, I determined this was due to a PHP version incompatibility.
I proceeded to downgrade PHP from version 8.1 to version 7.4.
Once that was complete, I restarted the Apache service.
Finally, I verified the fix by loading the website and checking the logs.
```

**Dense storage = More information, fewer words.**

#### Credential Handling

**Storage:**
- New credentials discovered → prompt: "Store credential for [service]? (y/n)"
- If yes → encrypt and store in credentials table
- Link to client_id, service_id, infrastructure_id

**Retrieval:**
- When needed: "Retrieved password for AD2\\sysadmin"
- Log access to credential_audit_log
- Display credential in response (since user authorized it)

**Audit:**
- Every credential access logged with:
  - Who (JWT user_id)
  - When (timestamp)
  - What (credential_id, service_name)
  - Why (optional context from work_item)

#### Auto-Tagging

**As work progresses, auto-apply tags:**
- Mention "docker" → tag: docker
- Working on "jupiter" → tag: jupiter
- Client "Dataforth" → tag: dataforth
- Error "connection-timeout" → tag: connection-timeout
- Action "migration" → tag: migration

**Tag categories:**
- technology (docker, apache, mariadb)
- infrastructure (jupiter, pfsense)
- client (dataforth)
- problem_type (ssl-error, connection-timeout)
- action (migration, upgrade, cleanup)

Tags stored in work_item_tags and session_tags junction tables.

#### Context Awareness

**MSP Mode remembers:**
- Previous sessions for this client (last 5)
- Open pending_tasks for this client
- Recent credentials accessed for this client
- Infrastructure topology for this client

**Auto-suggest:**
- "Last time we worked on [client], we left off at [pending_task]"
- "Credentials for [service] are available (last used [date])"
- "Previous similar issue: [problem from history] - same solution?"

---

### Summary: MSP Mode = Smart Auto-Tracking

1. **Auto-categorize** work as it happens (infrastructure, troubleshooting, etc.)
2. **Auto-extract** structured data (commands, files, systems, technologies)
3. **Auto-tag** based on content
4. **Auto-detect** billability
5. **Auto-generate** dense summaries (facts, not narrative)
6. **Auto-link** related data (sessions, problems, credentials)
7. **Minimal user input** required - Claude does the categorization
8. **Maximum information density** - brief but complete

User just works, Claude captures everything in structured, queryable format.

### Development Mode Behaviors (To Define)
1. What should Development Mode track?
2. How does it differ from normal mode?
3. Integration with git repos?

### Implementation Order
1. Database schema design
2. API development and deployment
3. MCP server or API client for Claude Code
4. MSP Mode slash command
5. Development Mode
6. Normal Mode

---

## Security Considerations

### Credential Storage
- **Never store plaintext passwords**
- Use Fernet encryption or AES-256-GCM
- Encryption key stored separately from database
- Key rotation strategy needed

### API Security
- HTTPS only (no HTTP)
- Rate limiting (prevent brute force)
- IP whitelisting (optional - VPN only)
- Token expiration and refresh
- Revocation list for compromised tokens
- Audit logging for credential access

### Multi-Machine Sync
- Encrypted tokens in Gitea config
- git-crypt or encrypted JSON values
- Never commit plaintext tokens to repo

---

## Next Steps (Planning Phase)

1. ✅ Architecture decisions (SQL, FastAPI, JWT)
2. ⏳ Define MSP Mode behaviors in detail
3. ⏳ Design database schema
4. ⏳ Define API endpoints specification
5. ⏳ Create authentication flow diagram
6. ⏳ Design slash command interactions

---

## Notes

- This spec will evolve as we discuss details
- Focus on scalability and robustness
- Design for future team members and integrations
- All decisions documented with rationale

---

## Change Log

**2026-01-15:**
- Initial spec created
- Architecture decisions: SQL, FastAPI, JWT, Gitea config
- Technology stack defined
- High-level infrastructure design
- Open questions identified
- **Database schema designed:** 27 tables via parallel agent analysis
  - 5 parallel agents analyzed: sessions, credentials, projects, work categorization, infrastructure
  - Comprehensive schema with 22 core tables + 5 junction tables
  - Analyzed 37 session logs, credentials file, all projects, infrastructure docs
  - Estimated storage: 1-2 GB/year
  - Pre-identified 157+ tags for categorization

+**Core Principle:** Track valuable work that doesn't belong to a specific client or dev project. General research, internal tasks, exploration, learning.

+- **Research and exploration** - "How does JWT authentication work?"

+- **General questions** - "What's the best way to handle SQL migrations?"

+- **Internal infrastructure** (non-client) - Working on Jupiter/Saturn without client context

+- **Learning/experimentation** - Testing new tools, trying approaches

+- **Documentation** - Writing guides, updating READMEs

+- **Non-categorized work** - Anything that doesn't fit MSP or Dev

+- Specific development projects → Use Dev Mode

+   - If coming from MSP/Dev mode: preserve all knowledge/context from previous mode

+   - Set session context to "general" (no client_id, no project_id)

+   - Display: "Normal Mode | General work session"

+   - **Keep:** All learned information, credentials accessed, context from previous modes

+   - **Clear:** Client/project assignment only

+   - **Rationale:** You might research something in Normal mode, then apply it in MSP mode

+     - project_id = NULL (or link to "Internal" or "Research" pseudo-project)

+     - session_title = "General work session: [auto-generated from topic]"

+     - is_billable = false (by default, since not client work)

+- Still create work_items, but less granular

+- Track major actions: "Researched FastAPI authentication patterns"

+- Track useful findings: "Found pyjwt library, better than python-jose"

+- Track decisions: "Decided to use Alembic for migrations"

+- Work items with category (usually 'documentation', 'research', or 'development')

+- Brief summary of what was learned/accomplished

+- Less emphasis on billability tracking

+- Less detailed command/file tracking (unless requested)

+#### Information Density in Normal Mode

+**Focus on:** Capturing useful knowledge, decisions, findings

+Title: Researched PostgreSQL connection pooling for FastAPI

+Description: Compared SQLAlchemy pooling vs asyncpg.

+Finding: SQLAlchemy pool_size=20, max_overflow=10 optimal for our load.

+Decision: Use SQLAlchemy with pool_pre_ping=True for connection health checks.

+Tags: postgresql, sqlalchemy, fastapi, connection-pooling

+**Not:** "I started by searching for PostgreSQL connection pooling documentation..."

+- session.summary = brief summary of research/work done

+- SQLAlchemy pooling recommended for our use case

+- JWT refresh tokens better than long-lived access tokens

+- Alembic supports auto-generate from models

+Tags: fastapi, postgresql, jwt, alembic

+1. **Knowledge base** - "What did I learn about X last month?"

+2. **Decision trail** - "Why did we choose technology Y?"

+3. **Reference** - "Where did I see that solution before?"

+4. **Context recovery** - Future Claude instances can search: "Show me research on JWT authentication"

+- "What have I researched about Docker networking?"

+- "When did I decide to use FastAPI over Flask?"

+- "Show all sessions tagged 'postgresql'"

+| Aspect | MSP Mode | Dev Mode | Normal Mode |

+| **Purpose** | Client work | Specific projects | General work/research |

+| **Client/Project** | Required | Optional | None (NULL) |

+| **Billable** | Default: yes | Default: no | Default: no |

+| **Detail Level** | High (every command) | Medium | Light (key actions) |

+| **Focus** | Client value delivery | Code/features | Knowledge/learning |

+| **Session Title** | "[Client] - [Issue]" | "[Project] - [Feature]" | "Research: [Topic]" |

+- User: "Let me research how to fix this SSL issue"

+- `/normal` → Research mode, but can reference client context if needed

+- Knowledge retained: knows which client, what SSL issue

+- Categorization: research session, not billable client work

+- `/msp` → Resumes (or starts new) Dataforth session

+- Knowledge retained: knows solution from research

+- Categorization: client work, billable

+- Modes are fluid, knowledge carries through

+- Session assignments change (project vs client vs general)

-2. How does it differ from normal mode?

+2. How does it differ from MSP and Normal modes?


Good, I've updated the spec to clarify Normal Mode. Now the three modes are clear:

1. **MSP Mode** - Client-focused work, high detail tracking, billable
2. **Dev Mode** - Project-focused development (TBD)
3. **Normal Mode** - General work/research, light tracking, knowledge capture

The key insight is that knowledge flows between modes - only the categorization/assignment changes. This makes sense because you might research something in Normal mode, then apply it in MSP mode for a client.

Let me update the change log to reflect this.


Edit

**2026-01-15:**
- Initial spec created
- Architecture decisions: SQL, FastAPI, JWT, Gitea config
- Technology stack defined
- High-level infrastructure design
- Open questions identified
- **Database schema designed:** 27 tables via parallel agent analysis
  - 5 parallel agents analyzed: sessions, credentials, projects, work categorization, infrastructure
  - Comprehensive schema with 22 core tables + 5 junction tables
  - Analyzed 37 session logs, credentials file, all projects, infrastructure docs
  - Estimated storage: 1-2 GB/year
  - Pre-identified 157+ tags for categorization

**2026-01-15:**
- Initial spec created
- Architecture decisions: SQL, FastAPI, JWT, Gitea config
- Technology stack defined
- High-level infrastructure design
- Open questions identified
- **Database schema designed:** 27 tables via parallel agent analysis
  - 5 parallel agents analyzed: sessions, credentials, projects, work categorization, infrastructure
  - Comprehensive schema with 22 core tables + 5 junction tables
  - Analyzed 37 session logs, credentials file, all projects, infrastructure docs
  - Estimated storage: 1-2 GB/year
  - Pre-identified 157+ tags for categorization
- **MSP Mode behaviors defined:**
  - Auto-categorization of client work
  - Information-dense storage format
  - Auto-tracking: commands, files, problems, credentials, infrastructure changes
  - Smart billability detection
  - Context awareness and auto-suggestion
- **Normal Mode behaviors defined:**
  - For general work/research not assigned to client or dev project
  - Knowledge retention across mode switches
  - Lighter tracking than MSP mode
  - Captures decisions, findings, learnings
  - Queryable knowledge base