tractatus/docs/planning/PHASE_3_ARCHITECTURE_DIAGRAM.md
TheFlow ac2db33732 fix(submissions): restructure Economist package and fix article display
- Create Economist SubmissionTracking package correctly:
  * mainArticle = full blog post content
  * coverLetter = 216-word SIR— letter
  * Links to blog post via blogPostId
- Archive 'Letter to The Economist' from blog posts (it's the cover letter)
- Fix date display on article cards (use published_at)
- Target publication already displaying via blue badge

Database changes:
- Make blogPostId optional in SubmissionTracking model
- Economist package ID: 68fa85ae49d4900e7f2ecd83
- Le Monde package ID: 68fa2abd2e6acd5691932150

Next: Enhanced modal with tabs, validation, export

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 08:47:42 +13:00

29 KiB

Phase 3: Project Context Awareness - Architecture Diagram


System Architecture Overview

┌───────────────────────────────────────────────────────────────────────┐
│                         PHASE 3 ARCHITECTURE                          │
└───────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│                              FRONTEND LAYER                             │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐                │
│  │   Navbar     │  │ Rule Manager │  │   Project    │                │
│  │              │  │              │  │   Manager    │                │
│  │ ┌──────────┐ │  │ • View Rules │  │ • List       │                │
│  │ │ Project  │ │  │ • Rendered   │  │ • Create     │                │
│  │ │ Selector │ │  │   Text       │  │ • Edit       │                │
│  │ │ Dropdown │ │  │ • Template   │  │ • Delete     │                │
│  │ └────┬─────┘ │  │ • Variables  │  │              │                │
│  └──────┼────────┘  └──────┬───────┘  └──────┬───────┘                │
│         │                  │                 │                         │
│         └──────────────────┴─────────────────┘                         │
│                            │                                           │
│                            ▼                                           │
│                   ┌─────────────────┐                                  │
│                   │  API Request    │                                  │
│                   │  with projectId │                                  │
│                   └────────┬────────┘                                  │
└─────────────────────────────┼───────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                            BACKEND LAYER                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐    │
│  │   Projects       │  │   Variables      │  │   Rules (Enh.)   │    │
│  │   Controller     │  │   Controller     │  │   Controller     │    │
│  ├──────────────────┤  ├──────────────────┤  ├──────────────────┤    │
│  │ GET    /projects │  │ GET    /vars     │  │ GET    /rules    │    │
│  │ POST   /projects │  │ POST   /vars     │  │   ?project=...   │    │
│  │ PUT    /projects │  │ PUT    /vars     │  │                  │    │
│  │ DELETE /projects │  │ DELETE /vars     │  │ Returns:         │    │
│  └────────┬─────────┘  └────────┬─────────┘  │ • text           │    │
│           │                     │             │ • renderedText   │    │
│           │                     │             │ • variables      │    │
│           │                     │             └────────┬─────────┘    │
│           │                     │                      │               │
│           ▼                     ▼                      ▼               │
│  ┌─────────────────────────────────────────────────────────────┐      │
│  │           VARIABLE SUBSTITUTION SERVICE                     │      │
│  ├─────────────────────────────────────────────────────────────┤      │
│  │                                                             │      │
│  │  substituteVariables(ruleText, projectId)                  │      │
│  │  ┌───────────────────────────────────────────────────┐     │      │
│  │  │ 1. Extract ${VAR} from text                       │     │      │
│  │  │ 2. Query VariableValue for projectId              │     │      │
│  │  │ 3. Build substitution map: {VAR: value}           │     │      │
│  │  │ 4. Replace ${VAR} with actual value               │     │      │
│  │  │ 5. Return renderedText + metadata                 │     │      │
│  │  └───────────────────────────────────────────────────┘     │      │
│  │                                                             │      │
│  │  extractVariables(text) → ['VAR1', 'VAR2']                 │      │
│  │  getAllVariables() → [{name, usageCount}]                  │      │
│  │  validateProjectVariables(projectId) → {missing}           │      │
│  │                                                             │      │
│  └─────────────────────────────────────────────────────────────┘      │
│                                                                         │
└─────────────────────────────┬───────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                          DATABASE LAYER (MongoDB)                       │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐    │
│  │   projects       │  │ variableValues   │  │ governanceRules  │    │
│  ├──────────────────┤  ├──────────────────┤  ├──────────────────┤    │
│  │ id (PK)          │  │ projectId (FK)   │  │ id               │    │
│  │ name             │  │ variableName     │  │ text (template)  │    │
│  │ description      │  │ value            │  │ scope            │    │
│  │ techStack        │  │ description      │  │ variables[]      │    │
│  │ active           │  │ category         │  │ applicableProjs  │    │
│  └──────────────────┘  └──────────────────┘  └──────────────────┘    │
│                                                                         │
│  Index: (id)          Index: (projectId, variableName)                 │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Data Flow: Variable Substitution

┌─────────────────────────────────────────────────────────────────────────┐
│                    VARIABLE SUBSTITUTION FLOW                           │
└─────────────────────────────────────────────────────────────────────────┘

STEP 1: User Selects Project
┌────────────────┐
│ User clicks    │
│ "Tractatus" in │
│ project picker │
└───────┬────────┘
        │
        ▼
┌────────────────────────────────┐
│ localStorage.setItem(          │
│   'currentProject',            │
│   'tractatus'                  │
│ )                              │
└───────┬────────────────────────┘
        │
        ▼

STEP 2: Frontend Requests Rules with Context
┌────────────────────────────────┐
│ GET /api/admin/rules?          │
│     project=tractatus          │
└───────┬────────────────────────┘
        │
        ▼

STEP 3: Backend Filters Applicable Rules
┌─────────────────────────────────────────────────┐
│ Query:                                          │
│ {                                               │
│   $or: [                                        │
│     { scope: 'UNIVERSAL' },                     │
│     { applicableProjects: 'tractatus' }         │
│   ],                                            │
│   active: true                                  │
│ }                                               │
└───────┬─────────────────────────────────────────┘
        │
        ▼

STEP 4: For Each Rule, Extract Variables
┌─────────────────────────────────────────────────┐
│ Rule Text:                                      │
│ "MongoDB database MUST be named ${DB_NAME}      │
│  in ${ENVIRONMENT}."                            │
│                                                 │
│ Extracted Variables:                            │
│ ['DB_NAME', 'ENVIRONMENT']                      │
└───────┬─────────────────────────────────────────┘
        │
        ▼

STEP 5: Lookup Variable Values for Project
┌─────────────────────────────────────────────────┐
│ Query variableValues:                           │
│ {                                               │
│   projectId: 'tractatus',                       │
│   variableName: {                               │
│     $in: ['DB_NAME', 'ENVIRONMENT']             │
│   }                                             │
│ }                                               │
│                                                 │
│ Results:                                        │
│ [                                               │
│   {variableName: 'DB_NAME', value: 'tractatus_dev'}, │
│   {variableName: 'ENVIRONMENT', value: 'development'} │
│ ]                                               │
└───────┬─────────────────────────────────────────┘
        │
        ▼

STEP 6: Build Substitution Map
┌─────────────────────────────────────────────────┐
│ Substitution Map:                               │
│ {                                               │
│   'DB_NAME': 'tractatus_dev',                   │
│   'ENVIRONMENT': 'development'                  │
│ }                                               │
└───────┬─────────────────────────────────────────┘
        │
        ▼

STEP 7: Replace Placeholders
┌─────────────────────────────────────────────────┐
│ Original:                                       │
│ "MongoDB database MUST be named ${DB_NAME}      │
│  in ${ENVIRONMENT}."                            │
│                                                 │
│ Regex: /\$\{([A-Z_]+)\}/g                       │
│                                                 │
│ Rendered:                                       │
│ "MongoDB database MUST be named tractatus_dev   │
│  in development."                               │
└───────┬─────────────────────────────────────────┘
        │
        ▼

STEP 8: Return Enriched Response
┌─────────────────────────────────────────────────┐
│ {                                               │
│   "id": "inst_019",                             │
│   "text": "...${DB_NAME}...${ENVIRONMENT}...",  │
│   "renderedText": "...tractatus_dev...development...", │
│   "variables": [                                │
│     {"name": "DB_NAME", "value": "tractatus_dev"}, │
│     {"name": "ENVIRONMENT", "value": "development"} │
│   ],                                            │
│   "scope": "UNIVERSAL"                          │
│ }                                               │
└───────┬─────────────────────────────────────────┘
        │
        ▼

STEP 9: Frontend Displays
┌─────────────────────────────────────────────────┐
│ ┌─────────────────────────────────────────────┐ │
│ │ inst_019 | SYSTEM | HIGH                    │ │
│ │                                             │ │
│ │ Rendered (for Tractatus):                   │ │
│ │ MongoDB database MUST be named tractatus_dev│ │
│ │ in development.                             │ │
│ │                                             │ │
│ │ Template: ...${DB_NAME}...${ENVIRONMENT}... │ │
│ │ Variables: DB_NAME=tractatus_dev,           │ │
│ │           ENVIRONMENT=development           │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘

UI Component Hierarchy

┌─────────────────────────────────────────────────────────────────────────┐
│                            ADMIN INTERFACE                              │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│ Navbar (All Pages)                                                      │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Tractatus Admin  [Project: Tractatus ▼]  Dashboard  Rules  [Logout]│ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
                                │
                ┌───────────────┼───────────────┐
                │               │               │
                ▼               ▼               ▼
    ┌────────────────┐  ┌───────────────┐  ┌─────────────┐
    │ Rule Manager   │  │ Project       │  │ Dashboard   │
    │                │  │ Manager       │  │             │
    ├────────────────┤  ├───────────────┤  └─────────────┘
    │ • List Rules   │  │ • List Projs  │
    │ • Rendered     │  │ • Add Project │
    │   Text         │  │ • Edit Proj   │
    │ • Template     │  │               │
    │ • Variables    │  │   ┌─────────┐ │
    │ • Edit Rule    │  │   │ Project │ │
    │                │  │   │ Editor  │ │
    │   ┌──────────┐ │  │   ├─────────┤ │
    │   │ Variable │ │  │   │ • Meta  │ │
    │   │ Editor   │ │  │   │ • Vars  │ │
    │   │ Modal    │ │  │   │         │ │
    │   └──────────┘ │  │   │ ┌─────┐ │ │
    └────────────────┘  │   │ │ Var │ │ │
                        │   │ │ Edit│ │ │
                        │   │ └─────┘ │ │
                        │   └─────────┘ │
                        └───────────────┘

Component Interaction Diagram

┌─────────────────────────────────────────────────────────────────────────┐
│                      COMPONENT INTERACTIONS                             │
└─────────────────────────────────────────────────────────────────────────┘

Event Flow: User Changes Project Selection

┌─────────────────┐
│ ProjectSelector │  (1) User clicks project dropdown
└────────┬────────┘
         │
         │ (2) Emits 'projectChanged' event
         │     { projectId: 'tractatus' }
         │
         ├──────────────────────┬───────────────────┐
         │                      │                   │
         ▼                      ▼                   ▼
┌────────────────┐   ┌──────────────────┐   ┌─────────────┐
│  Rule Manager  │   │ Project Manager  │   │  Dashboard  │
└────────┬───────┘   └────────┬─────────┘   └──────┬──────┘
         │                    │                     │
         │ (3) Listens        │ (3) Listens         │ (3) Listens
         │     to event       │     to event        │     to event
         │                    │                     │
         │ (4) Reloads        │ (4) Updates         │ (4) Updates
         │     rules with     │     current         │     stats for
         │     new context    │     selection       │     project
         │                    │                     │
         ▼                    ▼                     ▼
┌─────────────────────────────────────────────────────────┐
│         localStorage.setItem('currentProject', id)      │
└─────────────────────────────────────────────────────────┘

Database Relationships

┌─────────────────────────────────────────────────────────────────────────┐
│                        DATABASE RELATIONSHIPS                           │
└─────────────────────────────────────────────────────────────────────────┘

┌──────────────────┐
│   projects       │
│                  │
│ id (PK) ─────────┼──────────┐
│ name             │          │
│ techStack        │          │ 1:N
│ active           │          │
└──────────────────┘          │
                              │
                              ▼
                    ┌──────────────────┐
                    │ variableValues   │
                    │                  │
                    │ projectId (FK) ──┼─── References projects.id
                    │ variableName     │
                    │ value            │
                    │                  │
                    │ UNIQUE(projectId,│
                    │  variableName)   │
                    └──────────────────┘
                              │
                              │ Referenced by
                              │ (through variables[] field)
                              │
                              ▼
                    ┌──────────────────┐
                    │ governanceRules  │
                    │                  │
                    │ id               │
                    │ text (template)  │
                    │ variables[] ─────┼─── e.g., ['DB_NAME', 'DB_PORT']
                    │ scope            │
                    │ applicableProj[] ┼─── e.g., ['tractatus', 'family-history']
                    └──────────────────┘

Example Query Flow:
1. Get rules for project "tractatus"
2. Find rules where scope=UNIVERSAL OR 'tractatus' in applicableProjects
3. For each rule, extract variables[] field
4. Query variableValues where projectId='tractatus' AND variableName IN variables[]
5. Substitute ${VAR} with values
6. Return enriched rules

API Endpoints Overview

┌─────────────────────────────────────────────────────────────────────────┐
│                         API ENDPOINTS (Phase 3)                         │
└─────────────────────────────────────────────────────────────────────────┘

PROJECTS API
├─ GET    /api/admin/projects              → List all projects
├─ GET    /api/admin/projects/:id          → Get project + variables
├─ POST   /api/admin/projects              → Create project
├─ PUT    /api/admin/projects/:id          → Update project
└─ DELETE /api/admin/projects/:id          → Soft delete project

VARIABLES API
├─ GET    /api/admin/projects/:id/variables     → Get all vars for project
├─ POST   /api/admin/projects/:id/variables     → Create/update variable
├─ PUT    /api/admin/projects/:id/variables/:var → Update variable value
├─ DELETE /api/admin/projects/:id/variables/:var → Delete variable
└─ GET    /api/admin/variables/global           → All unique variable names

RULES API (Enhanced)
└─ GET    /api/admin/rules?project=:id     → Get rules with substitution
                                             (Enhanced existing endpoint)

Substitution Algorithm Pseudocode

function substituteVariables(ruleText, projectId) {
  // Step 1: Extract variable placeholders
  const regex = /\$\{([A-Z_]+)\}/g;
  const variableNames = [...new Set(
    [...ruleText.matchAll(regex)].map(m => m[1])
  )];

  if (variableNames.length === 0) {
    return {
      renderedText: ruleText,
      variables: []
    };
  }

  // Step 2: Query database for values
  const values = await VariableValue.find({
    projectId: projectId,
    variableName: { $in: variableNames }
  });

  // Step 3: Build substitution map
  const substitutionMap = {};
  values.forEach(v => {
    substitutionMap[v.variableName] = v.value;
  });

  // Step 4: Replace placeholders
  const renderedText = ruleText.replace(
    regex,
    (match, varName) => substitutionMap[varName] || match
  );

  // Step 5: Build metadata
  const variables = variableNames.map(name => ({
    name: name,
    value: substitutionMap[name] || null,
    missing: !substitutionMap[name]
  }));

  return {
    renderedText,
    variables,
    hasAllValues: variables.every(v => !v.missing)
  };
}

Architecture Complexity: Medium Integration Points: 3 (Models, Services, Controllers) New Collections: 2 (projects, variableValues) Enhanced Collections: 1 (governanceRules - query logic only)


Diagram Created: 2025-10-11 For: Phase 3 Implementation Status: Ready for Development