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:
- Multi-project filtering — Select which projects to display in the dashboard
- RBAC integration — Only show projects the authenticated user has access to
- Cloud replication — Replicate local SQLite databases to cloud PostgreSQL so dashboards work from any browser
- Executive snapshots — Snapshot-first presentation with drill-down capability
- 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.dblocally, 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-projectsto generate per-project data bundles - Generate
data-{project-id}.jsonfiles for each project - Generate a
projects-index.jsonwith 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_analyticspermission 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_analyticsdata 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_analyticsoris_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:
| Trigger | Phase 1 (Metrics) | Phase 2 (Narrative) | Token Cost |
|---|---|---|---|
Every /session-log entry | Always | No | 0 |
TRACK task marked [x] (completion) | Always | Yes | ~12K |
/orient (session start) | Always | Yes | ~12K |
/checkpoint (session end) | Always | Yes | ~12K |
Explicit /project-status --update | Always | Yes | ~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
--tasksflag 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.db → projects 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 --updatecommands — 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-logcall (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.dbschema gains two columns — non-breaking, defaults to disabled
Risks
| Risk | Severity | Mitigation |
|---|---|---|
| Phase 2 triggered too frequently (token burn) | High | Gate behind task-completion detection only; debounce within session |
| Generator script fails silently | Medium | Hook logs errors to hooks.log; /session-log Step 12 checks exit code |
projects.db schema migration breaks existing tools | Low | ALTER TABLE ADD COLUMN with defaults — no existing queries affected |
| Meta-dashboard data staleness in cloud | Medium | Last-updated timestamp per project; visual staleness indicator (>1hr = yellow, >24hr = red) |
| Vite HMR doesn't pick up JSON change | Low | Vite 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.
| Step | Deliverable | Files | Effort |
|---|---|---|---|
| 0.1 | projects.db schema migration — add dashboard_enabled, dashboard_config columns | scripts/migrations/add_dashboard_columns.py | 1 hr |
| 0.2 | Register BIO-QMS as first dashboard-enabled project | Migration script (SQL INSERT) | 30 min |
| 0.3 | get_dashboard_config() utility function | scripts/core/dashboard_registry.py | 1 hr |
| 0.4 | Parameterize generate-project-dashboard-data.js — accept --project <id> arg, remove hardcoded BIO-QMS filters | scripts/generate-project-dashboard-data.js | 2 hr |
| 0.5 | hooks/post-track-completion.py — PostToolUse:Edit hook detecting [x] in TRACK files | hooks/post-track-completion.py | 2 hr |
| 0.6 | Extend /session-log skill with Step 12 (Phase 1 auto-run) and Step 13 (conditional Phase 2) | commands/session-log.md | 1 hr |
| 0.7 | Extend /orient and /checkpoint to trigger Phase 1+2 for dashboard-enabled projects | commands/orient.md, commands/checkpoint.md | 1 hr |
| 0.8 | Integration test — mark a task [x], verify dashboard JSON regenerates within 2s | Manual verification | 30 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
| Step | Deliverable | Files |
|---|---|---|
| 1.1 | Project selector component in dashboard UI | components/ProjectSelector.jsx |
| 1.2 | --project flag in data adapter (from Phase 0.4) | generate-project-dashboard-data.js |
| 1.3 | Per-project data-{project-id}.json generation | Generator script |
| 1.4 | projects-index.json with project metadata and available data files | Generator script |
| 1.5 | Register PILOT as second dashboard-enabled project | Migration SQL |
| 1.6 | Dashboard landing page shows project selector when multiple projects registered | viewer.jsx |
Phase 2: Executive Snapshot Enhancement
| Step | Deliverable | Files |
|---|---|---|
| 2.1 | CompletionGauge, ProgressRing, AnimatedCounter components | components/ |
| 2.2 | Track progress strip with % complete from TRACK files | Dashboard JSX |
| 2.3 | Session logs page with monthly digest | New dashboard page |
| 2.4 | Drill-down modals for deep exploration | Modal components |
| 2.5 | Meta-generator script — aggregates per-project JSONs | scripts/generate-meta-dashboard-data.js |
| 2.6 | Meta-dashboard JSX — cross-project KPIs, project cards, drill-down | dashboards/meta-dashboard.jsx |
Phase 3: Cloud Replication (Track A.9)
| Step | Deliverable | Files |
|---|---|---|
| 3.1 | Extend Context API push to include dashboard data | backend/context/views.py |
| 3.2 | Cloud data adapter (queries PostgreSQL) | backend/dashboard/views.py |
| 3.3 | API endpoints for dashboard data (GET /api/v1/dashboard/) | Django views |
| 3.4 | Sync status indicator in dashboard UI | Dashboard JSX |
| 3.5 | Cloud meta-dashboard aggregation (cron job or Cloud Run) | Cloud infrastructure |
| 3.6 | Staleness indicators — yellow (>1hr), red (>24hr) per project | Dashboard JSX |
Phase 4: Authenticated Dashboard (Track B.5)
| Step | Deliverable | Files |
|---|---|---|
| 4.1 | JWT authentication flow in React dashboard | Auth components |
| 4.2 | Login/logout UI with OAuth (Google, GitHub) | Auth UI |
| 4.3 | Permission-based project filtering (can_view_analytics) | Dashboard + API |
| 4.4 | User preferences persistence (selected projects, timeframe, theme) | Backend + localStorage |
| 4.5 | Tenant-scoped meta-dashboard — admin sees all tenant projects | RBAC integration |
Organizational Visibility Levels
The dashboard system supports four levels of visibility, each building on the previous:
| Level | Audience | View | Data Source |
|---|---|---|---|
| Individual | Developer/Engineer | Single project dashboard with full track detail | Local project-dashboard-data.json |
| Team | Team Lead | Multi-project selector, comparative track views | Multiple project JSONs |
| Tenant | Tenant Admin | All tenant projects, cross-project KPIs, resource allocation | Meta-dashboard JSON + RBAC |
| Organization | Executive/CTO | All tenants, portfolio health, strategic initiatives | Cloud 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
Related ADRs
| ADR | Title | Relevance |
|---|---|---|
| ADR-053 | Cloud Sync Architecture | Data replication to cloud (D4, D8) |
| ADR-092 | Multi-Tenant RBAC | Permission model for project access (D3, D5, D8) |
| ADR-118 | Four-Tier Database Architecture | sessions.db, org.db, projects.db schema (D7) |
| ADR-155 | Project-Scoped Session Logs | Per-project data isolation (D6) |
| ADR-163 | Agentic Trajectory Dashboard | Original dashboard architecture (D1, D2) |
| ADR-199 | Two-Phase Project Status Token Optimization | Phase 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.aiexists — auth is integrated into the main API - 48+ fine-grained permissions already defined in
permissions/models.py - Context API at
backend/context/views.pyalready supports push/pull operations generate-project-dashboard-data.jscurrently has 4+ hardcodedBIO-QMSfilters (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.dbalready 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)