Skip to main content

ADR-170: Multi-Project Executive Dashboard with Autonomous Refresh

Status

Accepted — 2026-02-16 (v2.0.0 extends original proposal with D6-D8)

Context

The trajectory dashboard (ADR-163) currently serves a single-project view: one data.json file generated from one sessions.db. As the CODITECT platform manages 98 submodules across 16 categories, users need:

  1. Multi-project filtering — Select which projects to display in the dashboard
  2. RBAC integration — Only show projects the authenticated user has access to
  3. Cloud replication — Replicate local SQLite databases to cloud PostgreSQL so dashboards work from any browser
  4. Executive snapshots — Snapshot-first presentation with drill-down capability
  5. Licensed user gating — Dashboard only accessible to authenticated, licensed CODITECT users

Current Architecture

Local Machine                          Cloud (GCP)
┌─────────────────┐ ┌──────────────────┐
│ sessions.db │ backup only → │ GCS Bucket │
│ org.db │ │ (cold storage) │
│ platform.db │ └──────────────────┘
│ projects.db │
└────────┬────────┘

Python adapter

data.json

React Dashboard
(localhost:5174)

Target Architecture

Local Machine                          Cloud (GCP)
┌─────────────────┐ sync (ADR-053) ┌──────────────────┐
│ sessions.db │ ──────────────→ │ PostgreSQL │
│ org.db │ │ (multi-tenant) │
│ platform.db │ │ │
│ projects.db │ │ Context API │
└────────┬────────┘ │ (ADR-053) │
│ └────────┬─────────┘
Local Dashboard │
(localhost:5174) Cloud Dashboard
(app.coditect.ai)

RBAC (ADR-092)
JWT + 2FA + OAuth

Decision

D1: Project Selector UI

Add a global project selector to the trajectory dashboard that:

  • Shows all projects the user has access to (from projects.db locally, or cloud API when authenticated)
  • Supports multi-select: view one project or compare across projects
  • Persists selection in localStorage (local) or user preferences (cloud)
  • Filters ALL dashboard data through selected project scope

D2: Data Adapter Multi-Project Support

Extend dashboard_data_adapter.py to:

  • Accept --project <id> flag to scope data extraction to one project
  • Accept --all-projects to generate per-project data bundles
  • Generate data-{project-id}.json files for each project
  • Generate a projects-index.json with project metadata and available data files

D3: RBAC Integration via Existing Django Backend

Leverage the existing multi-tenant RBAC system (ADR-092):

  • No new auth system needed — reuse backend/users/, backend/tenants/, backend/permissions/
  • User model: User → TenantMembership → Tenant → Team → Project
  • Permission check: can_view_analytics permission on project scope
  • JWT token passed from dashboard to API for authorization

D4: Cloud Database Replication

Extend ADR-053 cloud sync to support dashboard data:

  • Push tool_analytics data to cloud PostgreSQL via Context API
  • Cloud adapter queries PostgreSQL instead of SQLite
  • Data stays fresh via periodic sync (configurable: 5min, 15min, 1hr)
  • Offline queue for disconnected usage

D5: Licensed User Gate

Dashboard access requires:

  • Valid CODITECT license (checked via backend/licenses/ API)
  • Active tenant membership
  • Appropriate permission (can_view_analytics or is_admin)
  • Local mode: no auth required (single-user)
  • Cloud mode: JWT required for all API calls

D6: Autonomous Dashboard Refresh

Dashboards must refresh automatically without manual /project-status --update commands. This builds on the two-phase architecture (ADR-199) to minimize token consumption:

Tiered Refresh Strategy:

TriggerPhase 1 (Metrics)Phase 2 (Narrative)Token Cost
Every /session-log entryAlwaysNo0
TRACK task marked [x] (completion)AlwaysYes~12K
/orient (session start)AlwaysYes~12K
/checkpoint (session end)AlwaysYes~12K
Explicit /project-status --updateAlwaysYes~12K

Phase 1 (Node.js, 0 AI tokens, <1s): Re-runs generate-project-dashboard-data.js to reparse all TRACK files and regenerate metrics JSON + AI brief. Vite dev server auto-reloads the browser dashboard when public/project-dashboard-data.json changes.

Phase 2 (AI, ~12K tokens): Reads the compact brief and generates narrative analysis (executive summary, risks, recommendations, track narratives). Only triggered on meaningful state changes.

Task Completion Detection Hook:

A PostToolUse:Edit hook watches for task completion markers in TRACK files:

# hooks/post-track-completion.py
# Trigger: PostToolUse:Edit on files matching TRACK-*.md
# Detection: new_string contains "[x]" that was not in old_string
# Action: Run Phase 1 + set narrative-refresh flag

def should_trigger(tool_input):
file_path = tool_input.get("file_path", "")
if "/TRACK-" not in file_path or not file_path.endswith(".md"):
return False
old_string = tool_input.get("old_string", "")
new_string = tool_input.get("new_string", "")
# Task was just completed
return "[x]" in new_string and "[x]" not in old_string

Session Log Integration:

The /session-log skill gains two post-append steps:

  • Step 12: Always run Phase 1 (node scripts/generate-project-dashboard-data.js) from the project root — 0 tokens, <1s
  • Step 13: If --tasks flag was provided (indicating tracked work with potential completion), trigger Phase 2 via subagent

Key design constraint: The refresh mechanism must be project-aware — only projects with dashboard_enabled: true (see D7) trigger refresh. Running the generator for a project without a dashboard is a no-op.

D7: Project Dashboard Registration

Not all projects have dashboards. A registration mechanism determines which projects are refresh-eligible:

Registry Location: projects.dbprojects table

Schema Extension:

ALTER TABLE projects ADD COLUMN dashboard_enabled BOOLEAN DEFAULT FALSE;
ALTER TABLE projects ADD COLUMN dashboard_config JSON DEFAULT NULL;
-- dashboard_config example:
-- {
-- "generator_script": "scripts/generate-project-dashboard-data.js",
-- "project_root": "submodules/dev/coditect-biosciences-qms-platform",
-- "output_dir": "public/",
-- "track_dir": "research/tracks/",
-- "phase2_enabled": true
-- }

Discovery Flow:

def get_dashboard_config(project_id: str) -> dict | None:
"""Return dashboard config if project has dashboard enabled, else None."""
conn = sqlite3.connect(get_projects_db_path())
row = conn.execute(
"SELECT dashboard_config FROM projects WHERE project_id = ? AND dashboard_enabled = 1",
(project_id,)
).fetchone()
return json.loads(row[0]) if row else None

Initial Registration (BIO-QMS):

UPDATE projects SET
dashboard_enabled = 1,
dashboard_config = json('{
"generator_script": "scripts/generate-project-dashboard-data.js",
"project_root": "submodules/dev/coditect-biosciences-qms-platform",
"output_dir": "public/",
"track_dir": "research/tracks/",
"phase2_enabled": true
}')
WHERE project_id = 'BIO-QMS';

Guard in Hooks/Skills:

All refresh triggers (hooks, session-log steps, orient, checkpoint) MUST check get_dashboard_config() before running the generator. If None, skip silently.

D8: Meta-Dashboard Orchestration (Cloud)

For cloud deployment with multiple tenants/projects, a meta-level dashboard provides cross-project visibility:

Architecture:

Meta-Dashboard (app.coditect.ai/dashboard)
├── Project Selector (from projects.db + RBAC filter)
├── Cross-Project KPIs (aggregate metrics)
│ ├── Total tasks across all projects
│ ├── Overall velocity (weighted average)
│ ├── At-risk projects (any with critical risks)
│ └── Activity heatmap (which projects active)
├── Per-Project Cards (clickable → project dashboard)
│ ├── Project name + progress ring
│ ├── Last updated timestamp
│ ├── Active tracks count
│ └── Top risk indicator
└── Drill-Down → Individual Project Dashboard
└── Full 61-project-status-dashboard.jsx experience

Data Aggregation:

  • Each project's Phase 1 generator produces project-dashboard-data.json
  • A meta-generator aggregates all project JSONs into meta-dashboard-data.json
  • Meta-generator runs on demand or on a schedule (e.g., every 15 min in cloud)

Cloud Replication (extends D4):

Local Machine                          Cloud (GCP)
┌─────────────────────┐ ADR-053 ┌──────────────────┐
│ BIO-QMS/ │ ──────────→ │ PostgreSQL │
│ dashboard-data.json│ │ dashboard_data │
│ PILOT/ │ │ (per-project) │
│ dashboard-data.json│ │ │
│ projects.db │ │ Meta-Dashboard │
│ (dashboard_enabled)│ │ (aggregated) │
└─────────────────────┘ └──────────────────┘

RBAC Integration: The meta-dashboard respects ADR-092 RBAC — users only see projects they have can_view_analytics permission for. The project cards render dynamically based on the authenticated user's project access.

Consequences

Positive

  • Users can manage what they see across 98+ submodules
  • Dashboard works from any browser when authenticated
  • Local context data is safely backed up to cloud
  • Team collaboration enabled via shared project views
  • Executive-level visibility across the full CODITECT platform
  • Autonomous refresh eliminates manual /project-status --update commands — dashboards stay current without user intervention
  • Tiered token strategy — Phase 1 (free) runs constantly, Phase 2 (~12K tokens) only on meaningful state changes
  • Project registration prevents wasted computation on projects without dashboards
  • Meta-dashboard provides organizational-level visibility for executives, team leads, and tenant admins

Negative

  • Increased complexity in data adapter (multi-project generation)
  • Cloud database costs (~$50/month for small PostgreSQL)
  • Sync latency for cloud data (5-15 min delay)
  • Must maintain both local and cloud data paths
  • Hook-based refresh adds ~1s latency to every /session-log call (Phase 1 generator)
  • Phase 2 narrative refresh consumes ~12K tokens per trigger — must be gated to avoid runaway costs

Neutral

  • Existing RBAC models unchanged — just consumed by new UI
  • Local-only mode continues to work without any auth
  • data.json format extended but backward-compatible
  • projects.db schema gains two columns — non-breaking, defaults to disabled

Risks

RiskSeverityMitigation
Phase 2 triggered too frequently (token burn)HighGate behind task-completion detection only; debounce within session
Generator script fails silentlyMediumHook logs errors to hooks.log; /session-log Step 12 checks exit code
projects.db schema migration breaks existing toolsLowALTER TABLE ADD COLUMN with defaults — no existing queries affected
Meta-dashboard data staleness in cloudMediumLast-updated timestamp per project; visual staleness indicator (>1hr = yellow, >24hr = red)
Vite HMR doesn't pick up JSON changeLowVite public dir watching is reliable; fallback: manual browser refresh

Implementation Plan

Phase 0: Autonomous Refresh Foundation (PILOT Critical Path)

Priority: Immediate — This phase unblocks the PILOT dashboard experience.

StepDeliverableFilesEffort
0.1projects.db schema migration — add dashboard_enabled, dashboard_config columnsscripts/migrations/add_dashboard_columns.py1 hr
0.2Register BIO-QMS as first dashboard-enabled projectMigration script (SQL INSERT)30 min
0.3get_dashboard_config() utility functionscripts/core/dashboard_registry.py1 hr
0.4Parameterize generate-project-dashboard-data.js — accept --project <id> arg, remove hardcoded BIO-QMS filtersscripts/generate-project-dashboard-data.js2 hr
0.5hooks/post-track-completion.py — PostToolUse:Edit hook detecting [x] in TRACK fileshooks/post-track-completion.py2 hr
0.6Extend /session-log skill with Step 12 (Phase 1 auto-run) and Step 13 (conditional Phase 2)commands/session-log.md1 hr
0.7Extend /orient and /checkpoint to trigger Phase 1+2 for dashboard-enabled projectscommands/orient.md, commands/checkpoint.md1 hr
0.8Integration test — mark a task [x], verify dashboard JSON regenerates within 2sManual verification30 min

Exit criteria: BIO-QMS dashboard auto-refreshes on task completion, session log, orient, and checkpoint without manual /project-status --update.

Phase 1: Multi-Project Local

StepDeliverableFiles
1.1Project selector component in dashboard UIcomponents/ProjectSelector.jsx
1.2--project flag in data adapter (from Phase 0.4)generate-project-dashboard-data.js
1.3Per-project data-{project-id}.json generationGenerator script
1.4projects-index.json with project metadata and available data filesGenerator script
1.5Register PILOT as second dashboard-enabled projectMigration SQL
1.6Dashboard landing page shows project selector when multiple projects registeredviewer.jsx

Phase 2: Executive Snapshot Enhancement

StepDeliverableFiles
2.1CompletionGauge, ProgressRing, AnimatedCounter componentscomponents/
2.2Track progress strip with % complete from TRACK filesDashboard JSX
2.3Session logs page with monthly digestNew dashboard page
2.4Drill-down modals for deep explorationModal components
2.5Meta-generator script — aggregates per-project JSONsscripts/generate-meta-dashboard-data.js
2.6Meta-dashboard JSX — cross-project KPIs, project cards, drill-downdashboards/meta-dashboard.jsx

Phase 3: Cloud Replication (Track A.9)

StepDeliverableFiles
3.1Extend Context API push to include dashboard databackend/context/views.py
3.2Cloud data adapter (queries PostgreSQL)backend/dashboard/views.py
3.3API endpoints for dashboard data (GET /api/v1/dashboard/)Django views
3.4Sync status indicator in dashboard UIDashboard JSX
3.5Cloud meta-dashboard aggregation (cron job or Cloud Run)Cloud infrastructure
3.6Staleness indicators — yellow (>1hr), red (>24hr) per projectDashboard JSX

Phase 4: Authenticated Dashboard (Track B.5)

StepDeliverableFiles
4.1JWT authentication flow in React dashboardAuth components
4.2Login/logout UI with OAuth (Google, GitHub)Auth UI
4.3Permission-based project filtering (can_view_analytics)Dashboard + API
4.4User preferences persistence (selected projects, timeframe, theme)Backend + localStorage
4.5Tenant-scoped meta-dashboard — admin sees all tenant projectsRBAC integration

Organizational Visibility Levels

The dashboard system supports four levels of visibility, each building on the previous:

LevelAudienceViewData Source
IndividualDeveloper/EngineerSingle project dashboard with full track detailLocal project-dashboard-data.json
TeamTeam LeadMulti-project selector, comparative track viewsMultiple project JSONs
TenantTenant AdminAll tenant projects, cross-project KPIs, resource allocationMeta-dashboard JSON + RBAC
OrganizationExecutive/CTOAll tenants, portfolio health, strategic initiativesCloud aggregated data

Each level is a superset of the one below. RBAC (ADR-092) controls access boundaries — a developer cannot see tenant-level data unless granted can_view_analytics at that scope.

Data Flow Summary

TRACK Files ─────┐
Session Logs ────┤
MASTER-TRACK ────┤

Phase 1: Node.js Generator ──────→ project-dashboard-data.json
(0 tokens, <1s) │
│ Vite HMR

Browser Dashboard

Phase 2: AI Narrative ──────────→ narrative merged into JSON
(~12K tokens) │
│ (only on task completion,
│ orient, checkpoint)

Dashboard with AI Analysis

Meta-Generator ──────→ meta-dashboard-data.json
(aggregates all projects) │

Meta-Dashboard
(cross-project KPIs)

Cloud Sync (ADR-053) ──→ PostgreSQL ──→ Cloud Dashboard
(app.coditect.ai)

Trigger Flow (Autonomous Refresh)

Developer marks task [x] in TRACK file


PostToolUse:Edit hook fires

├─── Is file TRACK-*.md? ──── No ──→ Skip
│ │
│ Yes
│ │
│ Does new_string have [x] not in old_string? ── No ──→ Skip
│ │
│ Yes
│ │
▼ ▼
Detect project from CWD


get_dashboard_config(project_id)

├─── None (no dashboard) ──→ Skip silently


Run Phase 1 (node generator)


Run Phase 2 (AI narrative via subagent)


Dashboard auto-reloads in browser
ADRTitleRelevance
ADR-053Cloud Sync ArchitectureData replication to cloud (D4, D8)
ADR-092Multi-Tenant RBACPermission model for project access (D3, D5, D8)
ADR-118Four-Tier Database Architecturesessions.db, org.db, projects.db schema (D7)
ADR-155Project-Scoped Session LogsPer-project data isolation (D6)
ADR-163Agentic Trajectory DashboardOriginal dashboard architecture (D1, D2)
ADR-199Two-Phase Project Status Token OptimizationPhase 1/Phase 2 architecture that D6 builds on

Notes

  • The existing Django backend at submodules/cloud/coditect-cloud-infra/backend/ already has all auth models
  • No dedicated auth.coditect.ai exists — auth is integrated into the main API
  • 48+ fine-grained permissions already defined in permissions/models.py
  • Context API at backend/context/views.py already supports push/pull operations
  • generate-project-dashboard-data.js currently has 4+ hardcoded BIO-QMS filters (lines ~281, 295, 425, 616) that must be parameterized in Phase 0.4
  • The dashboard JSX (61-project-status-dashboard.jsx) is already project-agnostic — only the data layer needs parameterization
  • projects.db already has 17 registered projects but no dashboard-related columns
  • Vite dev server HMR reliably detects public/ file changes and triggers browser reload
  • BIO-QMS is the first dashboard-enabled project; PILOT will be second after Phase 1.5

ADR Version: 2.0.0 Created: 2026-02-09 Updated: 2026-02-16 Author: CODITECT Core Team

Changelog:

  • v2.0.0 — Extended with D6 (Autonomous Dashboard Refresh), D7 (Project Dashboard Registration), D8 (Meta-Dashboard Orchestration). Added Phase 0 implementation plan. Added organizational visibility levels, trigger flow, data flow summary, and risk assessment. Changed status from Proposed to Accepted.
  • v1.0.0 — Original proposal with D1-D5 (Multi-Project Selector, Data Adapter, RBAC, Cloud Replication, Licensed User Gate)