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>
70 lines
1.6 KiB
Python
70 lines
1.6 KiB
Python
import pytest
|
|
from pathlib import Path
|
|
from src.reporter import manager_summary_to_markdown, build_manager_summary_docx, build_full_report_docx
|
|
|
|
SAMPLE_ANALYSIS = {
|
|
"total": 5, "active_total": 3,
|
|
"progress_counts": {"In Progress": 2, "Not Started": 1, "Complete": 2},
|
|
"priority_counts": {"P1": 3, "P2": 2},
|
|
"red_flags": [],
|
|
"p1_watchlist": [],
|
|
"by_owner": {},
|
|
"overdue": [],
|
|
}
|
|
|
|
SAMPLE_CLAUDE_TEXT = """## Programme Overview
|
|
|
|
Things are moving well this week.
|
|
|
|
## P1 Watch List
|
|
|
|
- Build reporting tool: In Progress — on track
|
|
|
|
## Blockers
|
|
|
|
No blockers this week.
|
|
"""
|
|
|
|
SAMPLE_FULL_CLAUDE_TEXT = """## Executive Summary
|
|
|
|
5 total tasks, 3 active.
|
|
|
|
## Red Flags
|
|
|
|
No red flags.
|
|
|
|
## Team Breakdown
|
|
|
|
Tony Coppola is working on the reporting tool.
|
|
|
|
## P1 Watch List
|
|
|
|
- Tony — Build reporting tool Red: In Progress — on track
|
|
|
|
## Overdue Tasks
|
|
|
|
No overdue tasks.
|
|
"""
|
|
|
|
|
|
def test_manager_summary_to_markdown_contains_header(tmp_path):
|
|
md = manager_summary_to_markdown(SAMPLE_ANALYSIS, SAMPLE_CLAUDE_TEXT)
|
|
assert "Programme Pulse" in md
|
|
assert "Programme Overview" in md
|
|
|
|
|
|
def test_manager_summary_to_markdown_includes_stats(tmp_path):
|
|
md = manager_summary_to_markdown(SAMPLE_ANALYSIS, SAMPLE_CLAUDE_TEXT)
|
|
assert "5" in md # total tasks
|
|
|
|
|
|
def test_build_manager_summary_docx_creates_file(tmp_path):
|
|
path = build_manager_summary_docx(SAMPLE_ANALYSIS, SAMPLE_CLAUDE_TEXT, tmp_path)
|
|
assert path.exists()
|
|
assert path.suffix == ".docx"
|
|
|
|
|
|
def test_build_full_report_docx_creates_file(tmp_path):
|
|
path = build_full_report_docx(SAMPLE_ANALYSIS, SAMPLE_FULL_CLAUDE_TEXT, tmp_path)
|
|
assert path.exists()
|
|
assert path.suffix == ".docx"
|