Backend - Routes moved under /api/, JWT bearer auth via @before_request - DEV_AUTH_BYPASS escape hatch for local dev - In-memory chat history and report state replaced with Postgres tables (preferences, chat_messages, reports, feedback_events) keyed on user - SQLAlchemy 2.x + Alembic migrations run on container start - Graceful Airtable failure handling — bad creds no longer 500 the API - Per-user data isolation via g.user_email from validated token Frontend - React + Vite + TypeScript SPA at /programme-pulse/ - MSAL.js (PKCE, sessionStorage, ID token to backend) - VITE_DEV_AUTH_BYPASS mirrors backend bypass for local dev - Streaming chat via fetch ReadableStream + SSE parsing - Charts via chart.js, markdown via react-markdown + remark-gfm - Full UI parity with the original templates/index.html Deploy (optical-dev split-build pattern) - Dockerfile + docker-compose.yml (name: programme-pulse pinned; app + Postgres; 127.0.0.1 binding only) - deploy/apache-programme-pulse.conf.tmpl with flushpackets=on for SSE - deploy/deploy.sh mirrors OSOP — port auto-pick (5051..5099), apache conf render, frontend build in throwaway node container, rsync to /var/www/html/programme-pulse, /api/health poll Tests - 49 passing; new tests for DB-backed preferences and JWT auth helpers - SQLite-backed test fixture in tests/conftest.py Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
52 lines
1.8 KiB
Python
52 lines
1.8 KiB
Python
import json
|
|
from src.prompts import build_chat_system_prompt, build_manager_summary_prompt, build_full_report_prompt
|
|
|
|
SAMPLE_TASKS = [
|
|
{
|
|
"id": "rec1", "task": "Build reporting tool", "progress": "In Progress",
|
|
"priority": "P1", "rag": "Red", "owner": "Tony Coppola", "owners": ["Tony Coppola"],
|
|
"related_item": "Reporting", "category": ["Airtable"], "start_date": "",
|
|
"end_date": "2026-04-30", "deadline": "2026-04-25", "doing": "",
|
|
"blocked_by": "", "blocking": "", "notes": "On track", "hours": None,
|
|
}
|
|
]
|
|
|
|
SAMPLE_ANALYSIS = {
|
|
"total": 1, "active_total": 1,
|
|
"progress_counts": {"In Progress": 1},
|
|
"priority_counts": {"P1": 1},
|
|
"red_flags": [],
|
|
"p1_watchlist": [SAMPLE_TASKS[0]],
|
|
"by_owner": {"Tony Coppola": [SAMPLE_TASKS[0]]},
|
|
"overdue": [],
|
|
}
|
|
|
|
|
|
def test_build_chat_system_prompt_includes_task_data():
|
|
prompt = build_chat_system_prompt(SAMPLE_TASKS)
|
|
assert "Build reporting tool" in prompt
|
|
assert "Tony Coppola" in prompt
|
|
|
|
|
|
def test_build_chat_system_prompt_includes_instructions():
|
|
prompt = build_chat_system_prompt(SAMPLE_TASKS)
|
|
assert "shorthand" in prompt.lower() or "plain language" in prompt.lower()
|
|
|
|
|
|
def test_build_manager_summary_prompt_includes_p1_watchlist():
|
|
prompt = build_manager_summary_prompt(SAMPLE_ANALYSIS)
|
|
assert "P1" in prompt or "Watch List" in prompt
|
|
|
|
|
|
def test_build_manager_summary_prompt_has_required_sections():
|
|
prompt = build_manager_summary_prompt(SAMPLE_ANALYSIS)
|
|
assert "Programme Overview" in prompt
|
|
assert "Blockers" in prompt
|
|
|
|
|
|
def test_build_full_report_prompt_has_required_sections():
|
|
prompt = build_full_report_prompt(SAMPLE_ANALYSIS)
|
|
assert "Executive Summary" in prompt
|
|
assert "Team Breakdown" in prompt
|
|
assert "Red Flags" in prompt
|
|
assert "Overdue" in prompt
|