# Diagrams & Access Control

## AOLL — Always-On Lead Library
### Flow Diagrams, User Roles & Authorization

| Field | Value |
|-------|-------|
| **Document Version** | 1.0 |
| **Status** | Draft |
| **Last Updated** | July 28, 2026 |
| **Companion Documents** | PRD-AOLL.md, ARCHITECTURE-AOLL.md, TECHNICAL_SPECIFICATION-AOLL.md |

---

## Table of Contents

1. [Data Ingestion Flow](#1-data-ingestion-flow)
2. [Advanced Search Flow](#2-advanced-search-flow)
3. [Intent Module Flow](#3-intent-module-flow)
4. [User Authentication Flow](#4-user-authentication-flow)
5. [User Roles & Types](#5-user-roles--types)
6. [Authorization Model](#6-authorization-model)
7. [Feature Access Matrix by Role](#7-feature-access-matrix-by-role)
8. [Plan Tier vs Role (Entitlements)](#8-plan-tier-vs-role-entitlements)
9. [API Access Control](#9-api-access-control)

---

## 1. Data Ingestion Flow

How company, contact, brand, and agency data enters AOLL from the **web scraper**, **CSV/Excel upload**, and optional **vendor API** — all through one unified pipeline.

### 1.1 High-Level Ingestion Architecture

```mermaid
flowchart TB
    subgraph sources["Data Sources"]
        S1["Web Scraper scheduled"]
        S2["Admin CSV Upload"]
        S3["Admin Excel Upload"]
        S4["Vendor API optional"]
    end

    subgraph landing["Raw and Staging"]
        STG["Staging Table or S3 Raw Zone"]
        SCR["scraper_runs log"]
        IMP["import_jobs log"]
    end

    subgraph pipeline["Processing Pipeline"]
        PARSE["Parse and Validate"]
        NORM["Normalize Fields"]
        ER["Entity Resolution"]
        ENR["Enrichment"]
        LOAD["Load to PostgreSQL"]
        IDX["Sync OpenSearch Index"]
    end

    subgraph output["Available in Product"]
        SEARCH["Advanced Search"]
        PROFILE["Company Profile"]
        FEED["Home Feed and Intent"]
    end

    S1 --> STG
    S1 --> SCR
    S2 --> STG
    S3 --> STG
    S2 --> IMP
    S3 --> IMP
    S4 --> STG

    STG --> PARSE --> NORM --> ER --> ENR --> LOAD --> IDX
    IDX --> SEARCH
    LOAD --> PROFILE
    LOAD --> FEED
```

### 1.2 Web Scraper Path (Existing)

```mermaid
sequenceDiagram
    participant Cron as Scheduler
    participant Scraper as Web Scraper
    participant STG as Staging DB
    participant Worker as Pipeline Worker
    participant ER as Entity Resolver
    participant PG as PostgreSQL
    participant OS as OpenSearch

    Cron->>Scraper: Trigger daily run
    Scraper->>Scraper: Crawl public sources
    Scraper->>STG: Dump raw records
    Scraper->>STG: Log scraper_run_id

    Worker->>STG: Pick up new run
    loop Each record
        Worker->>ER: Resolve domain and name
        ER-->>Worker: entity_id or new
        Worker->>PG: Upsert company or contact
    end
    Worker->>OS: Batch index sync
    Worker->>STG: Mark run completed
```

### 1.3 CSV / Excel Upload Path (Admin)

```mermaid
sequenceDiagram
    participant Admin as Admin User
    participant UI as Admin Upload UI
    participant API as AOLL API
    participant S3 as Object Storage
    participant Worker as Import Worker
    participant ER as Entity Resolver
    participant PG as PostgreSQL
    participant OS as OpenSearch

    Admin->>UI: Select file and entity type
    UI->>API: POST admin imports
    API->>API: Check Admin role
    API->>S3: Store original file
    API->>PG: Create import_job pending
    API-->>UI: import_job_id

    Worker->>S3: Read file
    Worker->>Worker: Parse CSV or Excel
    Worker->>Worker: Validate rows

    loop Each valid row
        Worker->>ER: Match or create entity
        Worker->>PG: Upsert with data_source tag
    end

    Worker->>S3: Write errors.csv if needed
    Worker->>PG: Update job status and counts
    Worker->>OS: Index sync
    Worker-->>Admin: In-app notification complete
```

### 1.4 Entity Resolution During Ingest

```mermaid
flowchart TD
    Row["Incoming Record"]
    Norm["Normalize domain and name"]
    T1{"Exact domain match?"}
    T2{"Fuzzy name match?"}
    Merge["Update existing entity_id"]
    Create["Create new entity_id"]
    Tag["Set data_source and source_ref"]
    Done["Record in PostgreSQL"]

    Row --> Norm --> T1
    T1 -->|Yes| Merge
    T1 -->|No| T2
    T2 -->|Yes| Merge
    T2 -->|No| Create
    Merge --> Tag --> Done
    Create --> Tag --> Done
```

### 1.5 Data Source Attribution

Every record stores where it came from:

| Field | Example Values |
|-------|----------------|
| `data_source` | `scraper`, `csv_upload`, `excel_upload`, `vendor` |
| `source_ref` | `scraper_run_id` or `import_job_id` |
| `source_file` | `brands_q3_2026.xlsx` (uploads only) |

---

## 2. Advanced Search Flow

How a user searches companies, brands, agencies, contacts, and scoops with filters — including auth, plan limits, and OpenSearch.

### 2.1 Search Request Flow

```mermaid
flowchart TB
    User["Sales User"]
    UI["Advanced Search UI"]
    Auth["Session Auth Check"]
    Role["Role Check"]
    Plan["Plan Entitlement Check"]
    Usage["Usage Meter"]
    SearchSvc["Search Service"]
    OS["OpenSearch"]
    PG["PostgreSQL hydrate"]
    Response["Results JSON"]

    User --> UI
    UI --> Auth
    Auth -->|Not logged in| Login["Redirect to Login"]
    Auth -->|Logged in| Role
    Role -->|Viewer blocked from export only| Plan
    Plan -->|Feature not on plan| Upgrade["402 Upgrade Prompt"]
    Plan -->|Allowed| Usage
    Usage -->|Limit exceeded| Upgrade
    Usage -->|OK increment count| SearchSvc
    SearchSvc --> OS
    OS --> SearchSvc
    SearchSvc --> PG
    PG --> Response
    Response --> UI
```

### 2.2 Advanced Search UI Structure

```mermaid
flowchart LR
    subgraph tabs["Entity Tabs"]
        T1["Companies"]
        T2["Brands"]
        T3["Agencies"]
    end

    subgraph filters["Filters Panel"]
        F1["Industry"]
        F2["Employee Count"]
        F3["Revenue"]
        F4["Media Spend"]
        F5["Location"]
        F6["Technology"]
        F7["Contact Name Email"]
    end

    subgraph results["Result Sub-Tabs"]
        R1["Contacts"]
        R2["Companies"]
        R3["Scoops"]
    end

    subgraph actions["User Actions"]
        A1["Select Rows"]
        A2["Export CSV"]
        A3["Save and Alert"]
    end

    tabs --> filters --> results --> actions
```

### 2.3 Search Sequence (Detailed)

```mermaid
sequenceDiagram
    participant U as User
    participant UI as Search Page
    participant API as API v1
    participant Auth as Auth Middleware
    participant Ent as Entitlement Service
    participant SS as Search Service
    participant OS as OpenSearch

    U->>UI: Apply filters and search
    UI->>API: GET search companies
    API->>Auth: Validate session
    Auth-->>API: user_id workspace_id role

    API->>Ent: check search quota and plan
    alt Starter limit reached
        Ent-->>API: 402 Payment Required
        API-->>UI: Show upgrade modal
    else Allowed
        Ent->>Ent: Increment usage_events
        API->>SS: Build OpenSearch DSL
        SS->>OS: Execute query
        OS-->>SS: Hits and facet counts
        SS-->>API: Normalized results
        API-->>UI: JSON with pagination
        UI-->>U: Render results table
    end
```

### 2.4 Filter to Index Mapping

```mermaid
flowchart LR
    UI["UI Filter"]
    API["API Query Params"]
    DSL["OpenSearch DSL"]
    Index["companies index"]

    UI --> API
    API --> DSL
    DSL --> Index

    F1["industry"] --> T1["term industry"]
    F2["employee_min max"] --> T2["range employee_count"]
    F3["media_spend_tier"] --> T3["term media_spend_tier"]
    F4["technology"] --> T4["terms technologies"]
    F5["keyword q"] --> T5["multi_match name domain"]
```

### 2.5 Plan Gating on Search Features

| Feature | Starter | Professional | Intelligence | Enterprise |
|---------|---------|--------------|--------------|------------|
| Search companies | Limited | Full | Full | Full |
| Search brands and agencies | No | Yes | Yes | Yes |
| Media spend filter | No | Yes | Yes | Yes |
| Contact email visible | Masked | Full | Full | Full |
| Export results | Limited | Yes | Yes | Yes |
| Save and Alert | No | Yes | Yes | Yes |

---

## 3. Intent Module Flow

How intent signals are sourced, scored, assigned to users via topics, and displayed in the Intent module and Home feed.

### 3.1 Intent Data Pipeline

```mermaid
flowchart TB
    subgraph signals["Signal Sources"]
        PROXY["Proxy Composite Scorer"]
        SCOOPS["Scoops and Events"]
        HIRE["Hiring Signals"]
        ADS["Ad Spend Changes"]
        BOMB["Bombora optional"]
    end

    subgraph topics["Topic Library"]
        LIB["500 plus Intent Topics"]
        USER["User Topics max 6"]
    end

    subgraph storage["Storage"]
        IS["intent_signals table"]
        PG["companies table"]
    end

    subgraph ui["Intent Module UI"]
        VIEW["View Signals tab"]
        MINE["My Topics tab"]
        LIBUI["Topic Library"]
    end

    PROXY --> IS
    SCOOPS --> PROXY
    HIRE --> PROXY
    ADS --> PROXY
    BOMB --> IS

    LIB --> LIBUI
    USER --> MINE
    IS --> VIEW
    PG --> VIEW
    LIBUI -->|Assign topic| USER
```

### 3.2 Proxy Intent Scoring (v1)

When Bombora license is not available, intent is **modeled** from activity signals:

```mermaid
flowchart LR
    S1["Recent Scoops 25pct"]
    S2["Hiring Activity 20pct"]
    S3["Funding Recency 20pct"]
    S4["Tech Stack Change 15pct"]
    S5["Ad Spend Increase 20pct"]
    SUM["Weighted Sum"]
    NORM["Normalize 0 to 100"]
    STORE["intent_signals row"]

    S1 --> SUM
    S2 --> SUM
    S3 --> SUM
    S4 --> SUM
    S5 --> SUM
    SUM --> NORM --> STORE
```

UI label: **Activity-based intent score** (not claimed as Bombora-grade content intent).

### 3.3 Intent Module User Flow

```mermaid
sequenceDiagram
    participant U as User
    participant IM as Intent Module
    participant API as API v1
    participant PG as PostgreSQL
    participant Ent as Entitlement

    U->>IM: Open Intent page
    IM->>API: GET intent signals
    API->>Ent: Requires Professional plus plan
    Ent-->>API: Allowed
    API->>PG: Query signals with filters
    PG-->>API: Signal rows with scores
    API-->>IM: Table data
    IM-->>U: View Signals table

    U->>IM: Switch to My Topics
    IM->>API: GET intent topics mine
    API-->>IM: Up to 6 assigned topics

    U->>IM: Browse All Topics
    IM->>API: GET intent topics library
    U->>IM: Assign 2 topics
    IM->>API: POST intent topics assign
    API->>PG: Insert user_topics
    API-->>IM: Updated count X of 6
```

### 3.4 Intent Signals Table Columns

```mermaid
flowchart LR
    subgraph columns["View Signals Table"]
        C1["Last Signal Date"]
        C2["Country"]
        C3["Company clickable"]
        C4["Topic"]
        C5["Industry"]
        C6["Signal Score 0-100"]
        C7["Audience Strength bar"]
    end

    subgraph filters["Filters"]
        F1["Date Range"]
        F2["Intent Topic"]
        F3["Company"]
        F4["Location"]
        F5["Media Spend"]
        F6["Technology"]
    end

    filters --> columns
```

### 3.5 Intent to Home Feed Connection

```mermaid
flowchart TB
    Prefs["User Feed Preferences"]
    Topics["User Topics up to 6"]
    IS["Intent Signals"]
    Scoops["Scoops"]
    Rank["Feed Ranking Engine"]
    Home["Home Feed Cards"]

    Prefs --> Rank
    Topics --> IS
    IS --> Rank
    Scoops --> Rank
    Rank --> Home
```

---

## 4. User Authentication Flow

AOLL supports **email + password** and **Google sign-in** only.

```mermaid
flowchart TB
    subgraph public["Public Pages"]
        Login["Login Page"]
        Signup["Sign Up Page"]
        Reset["Forgot Password"]
    end

    subgraph auth["Authentication Methods"]
        Email["Email and Password"]
        Google["Google OAuth"]
    end

    subgraph session["Session Created"]
        SESS["Redis Session"]
        WS["Workspace Linked"]
    end

    subgraph gate["Access Gate"]
        Dash["Dashboard"]
    end

    Login --> Email
    Login --> Google
    Signup --> Email
    Signup --> Google
    Email --> SESS
    Google --> SESS
    SESS --> WS --> Dash
    Reset --> Email
```

```mermaid
sequenceDiagram
    participant U as User
    participant App as AOLL
    participant Google as Google OAuth
    participant DB as aoll_users
    participant Redis as Session Store

    alt Email login
        U->>App: POST email and password
        App->>DB: Verify credentials
        DB-->>App: User record
        App->>Redis: Create session
        App-->>U: Redirect dashboard
    else Google login
        U->>App: Click Continue with Google
        App->>Google: OAuth redirect
        Google-->>App: Authorization code
        App->>DB: Find or create user by google_id
        App->>Redis: Create session
        App-->>U: Redirect dashboard
    end
```

---

## 5. User Roles & Types

AOLL uses **two layers** of access control:

1. **Role (RBAC)** — what actions a user can perform in the workspace
2. **Plan tier (Entitlements)** — what features the workspace has paid for

Both must pass for access to be granted.

### 5.1 Role Hierarchy

```mermaid
flowchart TB
    WS["Workspace"]

    WS --> Owner["Account Owner"]
    WS --> Admin["Admin"]
    WS --> Manager["Manager"]
    WS --> Member["Member"]
    WS --> Viewer["Viewer"]

    Owner --- P1["Billing users all access"]
    Admin --- P2["Billing users data upload"]
    Manager --- P3["CRM workflows no billing"]
    Member --- P4["Standard sales user"]
    Viewer --- P5["Read only no export"]
```

### 5.2 Role Definitions

| Role | Code | Description | Typical User |
|------|------|-------------|--------------|
| **Account Owner** | `owner` | Created the workspace; full control; cannot be removed | Signup user |
| **Admin** | `admin` | Full workspace management: billing, users, connectors, data upload | RevOps lead, IT admin |
| **Manager** | `manager` | All product features per plan; can manage team saved searches; no billing or user admin | Sales manager |
| **Member** | `member` | Standard sales user: search, export, alerts, workflows per plan | SDR, AE, media seller |
| **Viewer** | `viewer` | Read-only: search and view profiles; no export, no contact reveal, no CRM | Executive, intern |

**Note:** Jira AA-43 lists Admin / Non-Admin with optional Viewer and Manager. Implementation maps:
- **Non-Admin** default → `member`
- **Admin access toggle ON** → `admin`
- **Role select** → `manager` or `viewer`

### 5.3 User Status

| Status | Can Log In | Description |
|--------|------------|-------------|
| `active` | Yes | Normal access |
| `inactive` | No | Deactivated by admin |
| `pending` | No | Invited but not yet accepted |
| `locked` | No | Payment failed or policy lock |

### 5.4 Workspace vs User

```mermaid
flowchart LR
    WS["Workspace"]
    PLAN["Plan Tier Starter to Enterprise"]
    USERS["Users with Roles"]
    DATA["Shared Data and Connectors"]

    WS --> PLAN
    WS --> USERS
    WS --> DATA
```

- One **workspace** per account (v1)
- All users in a workspace share the **same plan tier**
- Usage limits (searches, exports) are **per workspace** unless noted otherwise
- CRM connectors are **workspace-level** (one HubSpot connection per workspace)

---

## 6. Authorization Model

### 6.1 Two-Layer Access Check

```mermaid
flowchart TD
    Request["API or Page Request"]
    AuthN["1. Authenticated?"]
    AuthZRole["2. Role allowed?"]
    AuthZPlan["3. Plan tier allowed?"]
    AuthZUsage["4. Usage limit OK?"]
    Allow["Allow"]
    Deny401["401 Unauthorized"]
    Deny403["403 Forbidden"]
    Deny402["402 Upgrade Required"]

    Request --> AuthN
    AuthN -->|No| Deny401
    AuthN -->|Yes| AuthZRole
    AuthZRole -->|No| Deny403
    AuthZRole -->|Yes| AuthZPlan
    AuthZPlan -->|No| Deny402
    AuthZPlan -->|Yes| AuthZUsage
    AuthZUsage -->|No| Deny402
    AuthZUsage -->|Yes| Allow
```

**Fail closed:** If any check fails, access is denied. No silent downgrade to free features on error.

### 6.2 Admin-Only Actions (from Design AA-27)

| Action | Admin Only |
|--------|------------|
| Change billing / plan | Yes |
| Add or remove users | Yes |
| Create new intent topic (workspace config) | Yes |
| CSV / Excel data upload | Yes |
| Trigger manual scraper run | Yes |
| Configure CRM connectors | Yes (Admin or Manager) |
| View import job history | Yes |

### 6.3 Authentication Methods vs Roles

| Method | Who Can Use | Notes |
|--------|-------------|-------|
| Email + password | All roles | Work email required on signup |
| Google OAuth | All roles | Auto-provision on first login |
| Microsoft OAuth | Not supported | Out of scope v1 |
| Enterprise API key | Enterprise tier | Separate from user session |

---

## 7. Feature Access Matrix by Role

Legend: ✅ Allowed · 🔒 Plan required · 👁 Read-only · ❌ Blocked · ⚙ Admin only

### 7.1 Product Modules

| Module / Action | Admin | Manager | Member | Viewer |
|-----------------|-------|---------|--------|--------|
| **Home feed** | ✅ | ✅ | ✅ | 👁 |
| **Advanced Search** | ✅ | ✅ | ✅ | 👁 |
| **View company profile** | ✅ | ✅ | ✅ | 👁 |
| **Reveal contact email** | ✅ | ✅ | ✅ | ❌ |
| **Export CSV** | ✅ | ✅ | ✅ | ❌ |
| **Save search and alert** | ✅ | ✅ | ✅ | ❌ |
| **Intent module** | 🔒 | 🔒 | 🔒 | 👁 |
| **Saved searches** | ✅ | ✅ | ✅ | 👁 |
| **Alerts feed** | ✅ | ✅ | ✅ | 👁 |
| **Workflows** | 🔒 | 🔒 | 🔒 | ❌ |
| **CRM connectors setup** | ⚙ | ✅ | ❌ | ❌ |
| **CRM manual export** | 🔒 | 🔒 | 🔒 | ❌ |
| **AI insights** | 🔒 | 🔒 | 🔒 | 👁 |
| **AI outreach generate** | 🔒 | 🔒 | 🔒 | ❌ |
| **Plan and billing** | ⚙ | ❌ | ❌ | ❌ |
| **User management** | ⚙ | ❌ | ❌ | ❌ |
| **CSV Excel data upload** | ⚙ | ❌ | ❌ | ❌ |
| **Scraper monitoring** | ⚙ | ❌ | ❌ | ❌ |
| **Settings own profile** | ✅ | ✅ | ✅ | ✅ |

🔒 = Requires Professional, Intelligence, or Enterprise plan depending on feature (see §8).

### 7.2 Data Ingestion Access

| Action | Admin | Manager | Member | Viewer |
|--------|-------|---------|--------|--------|
| Upload CSV | ✅ | ❌ | ❌ | ❌ |
| Upload Excel | ✅ | ❌ | ❌ | ❌ |
| Download import template | ✅ | ❌ | ❌ | ❌ |
| View import history | ✅ | ❌ | ❌ | ❌ |
| View scraper run logs | ✅ | ❌ | ❌ | ❌ |
| Trigger scraper manually | ✅ | ❌ | ❌ | ❌ |

---

## 8. Plan Tier vs Role (Entitlements)

Role controls **who** can do something. Plan tier controls **what features exist** for the workspace.

```mermaid
flowchart LR
    User["User with Role"]
    RoleCheck["Role Check"]
    PlanCheck["Plan Check"]
    Feature["Feature Access"]

    User --> RoleCheck --> PlanCheck --> Feature
```

### 8.1 Feature by Plan Tier

| Feature | Starter | Professional | Intelligence | Enterprise |
|---------|---------|--------------|--------------|------------|
| Company search | Limited | Full | Full | Full |
| Brand and agency search | No | Full | Full | Full |
| Contact data | Limited views | Full | Full | Full |
| Intent signals | No | Yes | Yes | Yes |
| Media spend data | No | Yes | Yes | Yes |
| Saved searches and alerts | No | Yes | Yes | Yes |
| Workflows | No | No | Yes | Yes |
| CRM integrations | No | No | Yes | Yes |
| AI opportunity insights | No | No | Yes | Yes |
| AI outreach | No | No | Yes | Yes |
| Team management | No | No | No | Yes |
| REST API access | No | No | No | Yes |
| Custom intelligence feeds | No | No | No | Yes |

### 8.2 Combined Example

| User | Role | Plan | Search Brands | Export | Upload CSV | AI Outreach |
|------|------|------|---------------|--------|------------|-------------|
| Sarah | Admin | Intelligence | Yes | Yes | Yes | Yes |
| Mike | Member | Professional | Yes | Yes | No | No |
| Lisa | Viewer | Professional | View only | No | No | No |
| Tom | Member | Starter | No | Limited | No | No |

---

## 9. API Access Control

### 9.1 Middleware Stack

```mermaid
flowchart LR
    REQ["HTTP Request"]
    M1["AuthFilter session"]
    M2["WorkspaceFilter"]
    M3["RoleFilter"]
    M4["EntitlementFilter"]
    M5["RateLimitFilter"]
    CTRL["Controller"]

    REQ --> M1 --> M2 --> M3 --> M4 --> M5 --> CTRL
```

### 9.2 Route Protection Examples

| Route | Auth | Role | Plan |
|-------|------|------|------|
| `GET /api/v1/search/*` | Session | member+ | per feature |
| `GET /api/v1/intent/*` | Session | member+ | Professional+ |
| `POST /api/v1/ai/*` | Session | member+ | Intelligence+ |
| `POST /api/v1/connectors/*` | Session | admin, manager | Intelligence+ |
| `GET /api/v1/admin/users` | Session | admin | Enterprise for multi-seat |
| `POST /api/v1/admin/imports` | Session | admin | any paid |
| `POST /api/v1/billing/*` | Session | admin | any |
| `GET /api/v1/*` with API key | API key | — | Enterprise |

### 9.3 Session Payload

After login, session stores:

```json
{
  "user_id": 123,
  "workspace_id": "uuid",
  "role": "member",
  "plan_tier": "professional",
  "email": "user@company.com"
}
```

Entitlement service reads `workspace_id` + `plan_tier` — not user role — for feature flags. Role is checked separately for admin actions.

---

## Document History

| Version | Date | Changes |
|---------|------|---------|
| 1.0 | 2026-07-28 | Initial diagrams and access control document |

---

*For implementation details see TECHNICAL_SPECIFICATION-AOLL.md §11 (Billing & Entitlements) and §12 (Security).*
