Skip to main content

MILESTONE 5.1 - Phase 1: Persona System Foundation - COMPLETE

Date Completed: 2025-10-22 Status: ✅ READY FOR M5.2 (Headline Generation) Total Implementation: 3 migrations + 5 services/repositories + 1 API route file Total Code: 1,500+ lines of production code Total Commits: 2 comprehensive commits


Executive Summary

M5.1 Phase 1 establishes the complete database schema and API surface for the persona-based adaptive intelligence system. This foundation enables:

  1. 12 Personas across S&OP and Financial decision flows to be defined and stored
  2. User Profile Management - Track each user's persona assignment and learned preferences
  3. Interaction Tracking - Audit trail of all user actions for learning
  4. API Routes - Full REST API for persona operations and user interactions

The system is now ready for M5.2 (Headline Generation) to build on this foundation.


What Was Built

1. Database Migrations (3 new files)

personas table

CREATE TABLE personas (
id UUID PRIMARY KEY
tenant_id UUID NOT NULL
name VARCHAR(100) NOT NULL
description TEXT
flow VARCHAR(50) - 'S&OP' or 'Financial'
role_index INTEGER - 1-7 for S&OP, 1-5 for Financial

-- Decision Archetype
primary_authority VARCHAR(100) - e.g., "CEO/COO"
decision_focus VARCHAR(200)
primary_dashboard VARCHAR(50) - 'pre_read', 'workbench', 'dashboard'

-- Configuration
key_metrics JSONB - [{id, weight}, ...]
detail_level ENUM - 'executive', 'medium', 'high'
headline_type ENUM - 'impact', 'variance', 'forecast', 'anomaly'
hero_chart_type VARCHAR(50) - 'waterfall', 'trend', 'gap', etc.

-- Learning & Data
context_factors JSONB - ['weather', 'policy', 'economic', ...]
required_data_sources JSONB - ['demand', 'inventory', ...]
actions JSONB - ['approve_plan', 'adjust_production', ...]

-- Templates
default_profile JSONB - PersonaProfile structure
page_templates JSONB - [PageTemplate, ...]

created_at TIMESTAMP
updated_at TIMESTAMP

UNIQUE(tenant_id, name)
INDEX(tenant_id, flow)
)

persona_user_profiles table

CREATE TABLE persona_user_profiles (
id UUID PRIMARY KEY
user_id UUID NOT NULL UNIQUE
tenant_id UUID NOT NULL
persona_id UUID NOT NULL

-- Learned Preferences
detail_preference INTEGER (0-100)
external_data_usage INTEGER (0-100)
decision_speed INTEGER (0-100)
collaboration_frequency INTEGER (0-100)

metric_preferences JSONB - {metric_id: score}
action_preferences JSONB - {action_id: score}
data_source_preferences JSONB - {source_id: score}
context_preferences JSONB - ['pre_read', 'workbench', 'dashboard']

-- Interaction History
total_interactions INTEGER
last_interaction_at TIMESTAMP
last_interaction_days_ago INTEGER
interaction_summary JSONB - {headline_views, chart_interactions, ...}

-- Persona Matching
persona_alignment_score FLOAT (0-100)
persona_reassessment_recommended BOOLEAN
suggested_persona_id UUID

status ENUM - 'active', 'inactive', 'pending_reassessment'
created_at TIMESTAMP
updated_at TIMESTAMP

FOREIGN KEY(user_id) REFERENCES users.id
FOREIGN KEY(tenant_id) REFERENCES tenants.tenant_id
FOREIGN KEY(persona_id) REFERENCES personas.id
INDEX(user_id, status)
)

persona_interactions table

CREATE TABLE persona_interactions (
id UUID PRIMARY KEY
user_id UUID NOT NULL
tenant_id UUID NOT NULL
persona_id UUID NOT NULL

-- Interaction Type
interaction_type ENUM:
- headline_viewed: User viewed a headline
- chart_interacted: User clicked/hovered on chart
- metric_focused: User focused on metric
- external_data_used: User accessed external data
- action_taken: User executed action
- detail_expanded: User expanded detail section
- collaborated: User added comment/annotation
- shared: User shared page/insight
- feedback_given: User provided feedback

-- Context
page_type VARCHAR(50) - 'pre_read', 'workbench', 'dashboard'
page_id UUID
element_id UUID
element_type VARCHAR(50) - 'headline', 'hero_chart', 'detail_section'

-- Tracking
metadata JSONB - {chart_type, metric_name, action_id}
duration_seconds INTEGER
feedback_sentiment ENUM - 'positive', 'neutral', 'negative'
feedback_comment TEXT

created_at TIMESTAMP

FOREIGN KEY(user_id) REFERENCES users.id
FOREIGN KEY(tenant_id) REFERENCES tenants.tenant_id
FOREIGN KEY(persona_id) REFERENCES personas.id
INDEX(user_id, created_at)
INDEX(persona_id, created_at)
)

2. Services (2 new files)

PersonaService (PersonaService.js - 340 lines)

Manages persona definitions, templates, and aggregation.

Key Methods:

  • getPersonasForTenant(tenantId, flow?) - List personas
  • getPersonaById(personaId) - Get persona details
  • getPersonaByName(tenantId, name) - Find persona by name
  • createPersona(tenantId, personaData) - Create new persona
  • updatePersona(personaId, updates) - Update persona
  • deletePersona(personaId) - Delete persona
  • initializeDefaultPersonas(tenantId) - Initialize 12 default personas at tenant setup

Built-in Personas (auto-initialized):

S&OP Flow (7 personas):

  1. S&OP Executive - Strategic trade-off approval
  2. Supply Chain Director - Capacity and supply management
  3. Sales VP - Demand forecast accuracy
  4. Finance VP (FP&A) - Profitability and variance
  5. Demand Planner - Statistical forecasting
  6. Supply Planner - Production scheduling
  7. Marketing VP - Promotion ROI and demand shaping

Financial Flow (5 personas): 8. CFO - Capital allocation and ROIC 9. FP&A VP - Scenario modeling and variance 10. Controller - Data integrity and compliance 11. Treasurer - Cash flow and working capital 12. Head of IR - Investor narrative and guidance

Each persona includes:

  • Key metrics (weighted)
  • Detail level preference
  • Headline type and hero chart type
  • Required data sources
  • Default learning profile

PersonaProfileService (PersonaProfileService.js - 280 lines)

Manages user persona profiles and learning.

Key Methods:

  • initializePersonaProfile(userId, tenantId, personaId) - Create profile for new user
  • getPersonaProfile(userId) - Get user's profile with persona details
  • updatePersonaProfile(userId, updates) - Update user preferences
  • recordInteraction(userId, tenantId, personaId, data) - Track interaction
  • getUserInteractionHistory(userId, days, type?) - Get interaction audit trail
  • calculatePersonaAlignment(userId) - Score how well user fits assigned persona
  • shouldReassessPersona(userId) - Determine if reassessment needed
  • reassignPersona(userId, newPersonaId) - Move user to different persona

Learning Logic:

  • Real-time profile updates as users interact
  • Preferences stored as learned deviations from persona defaults
  • Alignment scoring (0-100) based on interaction patterns
  • Automatic reassessment flag when alignment drops below 60%

3. Repositories (3 new files)

PersonaRepository (dal/PersonaRepository.js)

Data access for personas.

Key Methods:

  • findByTenant(tenantId) - Get all personas for tenant
  • findByName(tenantId, name) - Find by name
  • findByFlow(tenantId, flow) - Get personas by flow
  • findByRoleIndex(tenantId, flow, roleIndex) - Get persona by role
  • updatePageTemplates(personaId, templates) - Update templates
  • updateDefaultProfile(personaId, profile) - Update learning profile

UserPersonaProfileRepository (dal/UserPersonaProfileRepository.js)

Extended access for persona user profiles.

Key Methods:

  • findByUserId(userId) - Get user's profile
  • findByPersonaId(personaId) - Get all users for a persona
  • findNeedingReassessment(tenantId) - Get users flagged for reassessment
  • countActiveByPersonaId(personaId) - Count active users
  • updateLastInteraction(userId, timestamp) - Track interaction timing
  • updateAlignmentScore(userId, score) - Update alignment
  • getAverageMetricsForPersona(personaId) - Aggregate for persona evolution

PersonaInteractionRepository (dal/PersonaInteractionRepository.js)

Data access for interaction tracking.

Key Methods:

  • findByUserIdAndDate(userId, days) - Get user's interactions
  • findByUserAndType(userId, type, days) - Filter by interaction type
  • countByUserId(userId, days) - Count interactions
  • getInteractionSummary(userId, days) - Summary by type
  • findByPersonaId(personaId, days) - Get persona's interactions
  • getPersonaStats(personaId, days) - Aggregate statistics
  • findPositiveFeedback(personaId, days) - Get positive interactions

4. API Routes (1 new file)

personaRoutes.js - 10 Endpoints

Public Endpoints (authenticated users):

  1. GET /api/personas - List personas

    • Query: flow (optional: 'S&OP' or 'Financial')
    • Returns: All personas for tenant, optionally filtered by flow
  2. GET /api/personas/:personaId - Get persona details

    • Returns: Complete persona definition
  3. GET /api/my-persona - Get current user's profile

    • Returns: User's assigned persona and learned preferences
  4. POST /api/my-persona/interactions - Record interaction

    • Body: interaction_type, page_type, element_id, metadata, duration_seconds, feedback
    • Returns: Created interaction record
  5. GET /api/my-persona/interactions - Get interaction history

    • Query: days (default 30), type (optional filter)
    • Returns: List of interactions + summary
  6. GET /api/my-persona/alignment - Get persona alignment score

    • Returns: Current score, reassessment status, suggested persona
  7. PUT /api/my-persona/reassign - Reassign to different persona

    • Body: new_persona_id
    • Returns: Updated profile
  8. GET /api/personas/:personaId/stats - Get persona statistics

    • Query: days (default 30)
    • Returns: User count, interaction stats, breakdown by type
  9. PUT /api/personas/:personaId - Update persona (admin)

    • Body: Any persona fields
    • Returns: Updated persona
  10. POST /api/init-personas - Initialize default personas (setup/admin)

    • Returns: Created 12 personas

Architecture

Three-Layer Pattern (Consistent with M2-M4)

Routes (personaRoutes.js)

Services (PersonaService, PersonaProfileService)

Repositories (PersonaRepository, UserPersonaProfileRepository, PersonaInteractionRepository)

Database (PostgreSQL: personas, persona_user_profiles, persona_interactions)

Integration Points

  • Authentication: All routes require authMiddleware
  • Multi-tenancy: All queries scoped by tenant_id
  • Server.js: Routes registered at /api path

Key Decisions

1. Persona Storage as First-Class Entities

Rather than embedding personas in code, we store them in the database. This enables:

  • Easy customization per tenant
  • Version control and audit trail
  • Dynamic persona updates without code changes
  • A/B testing different persona configurations

2. Default Personas at Initialization

When a tenant is created, we auto-populate 12 personas:

  • 7 S&OP personas (operational decision-making)
  • 5 Financial personas (financial/strategic decisions)

These are role-based archetypes that can be customized per tenant.

3. Two-Level Learning

  • Individual Level: User's preferences stored in persona_user_profiles for immediate personalization
  • Aggregate Level: (prepared for M5.6) Persona templates evolve based on all users in that persona

4. Interaction Recording

Every user action (headline view, chart click, action taken, feedback) is recorded with full context:

  • Which element they interacted with
  • How long they spent
  • Their feedback sentiment
  • Metadata about the element

This enables:

  • Individual profile learning in real-time
  • Persona template evolution over time
  • Recommending actions from similar users

5. Alignment Scoring

System calculates how well a user's behavior matches their assigned persona:

  • Compares interaction patterns to persona defaults
  • Flags for reassessment if score drops below 60%
  • Suggests alternative persona if one fits better

Testing Ready

All components are production-ready:

  • ✅ Migrations with proper foreign keys
  • ✅ Services with comprehensive methods
  • ✅ Repositories using BaseRepository pattern
  • ✅ Routes with authentication and error handling
  • ✅ Multi-tenancy enforced throughout
  • ✅ Integration with existing auth system

Next Steps

M5.2: Headline Generation Engine

With personas now defined and users assigned, M5.2 will:

  1. Build AnomalyDetector service (2+ std dev detection)
  2. Build ImpactQuantifier service ($, %, timeline)
  3. Build HeadlineGenerator service (LLM + rules)
  4. Generate data-driven headlines based on persona

Example: Same anomaly, different headlines:

  • Supply Chain Director: "Frankfurt inventory 23% above optimal"
  • CFO: "Working capital headwind: $2.3M"
  • Demand Planner: "Forecast bias +3% suggests model issue"

M5.3: Hero Section & Page Templates

Build Executive-focused visual hierarchy:

  • Hero chart (waterfall, trend, gap, etc)
  • Key metrics in persona-relevant units
  • Context badges (weather, policy, economic)

M5.4: Anomaly Detection & Impact

Connect to M3 (weather, policy, economics):

  • Detect anomalies with external factor context
  • Quantify impact with causal attribution

M5.5: External Data Integration

Link M3.1 (weather), M3.2 (policy, economics) to page gen

M5.6: Persona Learning & Adaptation

Implement persona template evolution:

  • Weekly aggregation of all users in persona
  • Update persona defaults based on learned patterns
  • Improve initial profile for new users

File Summary

New Files (8 total, 1,500+ lines)

Database Migrations:

  • backend/migrations/20251022000001_create_personas_table.cjs (60 lines)
  • backend/migrations/20251022000002_create_persona_user_profiles_table.cjs (65 lines)
  • backend/migrations/20251022000003_create_persona_interactions_table.cjs (65 lines)

Services:

  • backend/src/services/PersonaService.js (340 lines)
  • backend/src/services/PersonaProfileService.js (280 lines)

Repositories:

  • backend/src/dal/PersonaRepository.js (95 lines)
  • backend/src/dal/UserPersonaProfileRepository.js (180 lines)
  • backend/src/dal/PersonaInteractionRepository.js (200 lines)

Routes:

  • backend/src/routes/personaRoutes.js (350 lines)

Server Integration:

  • Modified: backend/server.js (+2 lines for import and registration)

Git Commits

Commit 1: Database & Services

[M5.1] Phase 1: Persona System Foundation - Database & Services

Add comprehensive persona system foundation for role-based adaptive intelligence:
- 3 database migrations (personas, persona_user_profiles, persona_interactions)
- 2 services (PersonaService, PersonaProfileService)
- 3 repositories (PersonaRepository, UserPersonaProfileRepository, PersonaInteractionRepository)
- All 12 personas defined with complete specifications

Commit 2: API Routes

[M5.1] Add API routes for persona management

Implement REST API endpoints for persona system:
- 10 endpoints for persona operations and user interactions
- Full interaction tracking audit trail
- Alignment scoring and reassessment logic
- Integration with server.js

Success Metrics

Functional:

  • 12 personas fully defined with all metadata
  • User profile initialization works
  • Interaction recording functional
  • Alignment scoring implemented
  • API routes integrated into server

Data Model:

  • Foreign keys correctly reference tenant_id
  • Multi-tenancy enforced
  • Indices optimized for common queries
  • JSONB fields for flexible configuration

API Contract:

  • 10 endpoints covering all operations
  • Proper HTTP status codes
  • Clear error messages
  • Authentication required everywhere

Code Quality:

  • Consistent 3-layer pattern
  • JSDoc comments throughout
  • BaseRepository inheritance
  • Clear separation of concerns

What's Ready for Demo

M5.1 enables:

  1. Persona selection at registration - Users pick a role, get assigned to persona
  2. Persona profiles - System tracks each user's preferences
  3. Interaction tracking - Complete audit trail of user decisions
  4. API foundation - All endpoints ready for frontend integration

This foundation supports M5.2-M5.6 to build the complete intelligent page generation system.


Status: ✅ COMPLETE - M5.1 Phase 1 Foundation Ready Date: 2025-10-22 Next Phase: M5.2 - Headline Generation Engine Impact: Enables persona-based adaptive intelligence - ChainAlign's "secret sauce"