Commit Graph

120 Commits

Author SHA1 Message Date
admin
7ed9571cb9 fix: apply numbered list normalization to all PDF text blocks including nested fields
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 12:26:46 -05:00
admin
6c9ee877c9 fix: normalize numbered lists in PDFKit fallback renderer
The Puppeteer path uses <br> tags; the PDFKit fallback now normalizes
"1) ... 2) ..." patterns to newline-separated text via PDFKit's
native text rendering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 12:22:46 -05:00
admin
8620ea87b7 fix: normalize numbered lists and FY labels in PDF export
- Convert "1) ... 2) ..." inline lists to line-separated items in PDF
- Use FY-3/FY-2/FY-1 labels in financial table (was FY3/FY2/FY1)
- Applies to both top-level and nested field values

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 12:18:07 -05:00
admin
53dd849096 fix: normalize inline numbered lists in CSV export
Converts "1) Item. 2) Item." patterns to line-separated items within
quoted CSV cells, matching the frontend normalizeToMarkdown behavior.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 12:10:28 -05:00
admin
cbe7761558 fix: query documents table for analytics instead of empty events table
The document_processing_events table was never populated. Analytics
endpoints now query the documents table directly using status and
timestamp columns. Also updated upload page labels to remove outdated
"Agentic RAG" references.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 12:05:25 -05:00
admin
8f9c225ebc feat: improve readability of list fields in CIM review
- Add normalizeToMarkdown() that converts inline "1) ... 2) ..." patterns
  to properly spaced markdown numbered lists for existing documents
- Update Zod schema descriptions to instruct LLM to use newline-separated
  numbered items in list fields (keyAttractions, potentialRisks, etc.)
- Fixes wall-of-text rendering in investment thesis and next steps sections

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:37:25 -05:00
admin
69ece61750 fix: preserve newlines in CSV export for readable multi-line fields
Newlines within quoted CSV cells render correctly in Excel and Google
Sheets. Previously all newlines were collapsed to spaces, making
bullet lists and paragraphs unreadable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:29:35 -05:00
admin
9007c4b270 fix: use FY-3/FY-2/FY-1 labels in CSV export for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:29:17 -05:00
admin
d4b1658929 feat: wire Analytics tab to real data, add markdown rendering, fix UI labels
- Analytics endpoints now query document_processing_events table instead of
  returning hardcoded zeros (/documents/analytics, /processing-stats,
  /health/agentic-rag)
- Add react-markdown for rich text rendering in CIM review template
  (readOnly textarea fields now render markdown formatting)
- Fix upload page references from "Firebase Storage" to "Cloud Storage"
- Fix financial year labels from "FY3" to "FY-3" in DocumentViewer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:27:46 -05:00
admin
4a25e551ce feat: UI polish - toast notifications, skeletons, empty states, error boundary
- Replace emoji icons with Lucide icons throughout
- Add custom toast notification system (replaces alert/confirm)
- Add ConfirmModal for delete confirmations
- Add loading skeleton cards instead of basic spinner
- Add empty states for documents, analytics sections
- Add ErrorBoundary wrapping Dashboard
- Extract TabButton component from repeated inline pattern
- Fix color tokens (raw red/blue -> error/primary design tokens)
- Add CSS fade transition on tab changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:18:05 -05:00
admin
00c156b4fd fix: add null guards to Analytics component preventing white screen
API responses with missing nested fields (sessionStats, agentStats,
qualityStats, averageProcessingTime, averageApiCalls) caused .toFixed()
and .map() to crash on undefined. Added ?? null coalescing throughout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:08:29 -05:00
admin
38a0f0619d chore: complete v1.0 Analytics & Monitoring milestone
Archive milestone artifacts (roadmap, requirements, audit, phase directories)
to .planning/milestones/. Evolve PROJECT.md with validated requirements and
decision outcomes. Create MILESTONES.md and RETROSPECTIVE.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 10:34:18 -05:00
admin
8bad951d63 fix: resolve tech debt from v1.0 milestone audit
- Frontend admin email now reads from VITE_ADMIN_EMAIL env var instead of hardcoded literal
- Consolidate retention cleanup: remove runRetentionCleanup, add document_processing_events to existing cleanupOldData
- Replace personal email in defineString('EMAIL_WEEKLY_RECIPIENT') default with empty string

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 10:26:24 -05:00
admin
5d3ebbe27a docs(roadmap): add phase 5 tech debt cleanup from v1.0 audit 2026-02-25 10:23:39 -05:00
admin
0f2aba93dd docs: add v1.0 milestone audit report
15/15 requirements satisfied, 5/5 E2E flows verified, 5 tech debt items (no blockers).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 10:20:01 -05:00
admin
9dfccf47b8 docs(phase-04): complete phase execution and verification 2026-02-25 10:08:28 -05:00
admin
f48c82f192 docs: update prior phase summaries with commit hashes and self-check results
- 02-03-SUMMARY.md: fill in plan metadata docs commit hash (was TBD)
- 03-02-SUMMARY.md: add self-check PASSED section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 16:55:45 -05:00
admin
cafdd6937d docs(04-02): complete App.tsx wiring plan
- Create 04-02-SUMMARY.md with execution results
- Update STATE.md: phase 4 complete, new decisions logged, 100% progress
- Update ROADMAP.md: phase 4 marked Complete (2/2 plans done)
2026-02-24 16:41:25 -05:00
admin
6c345a6cdb feat(04-02): wire AlertBanner and AdminMonitoringDashboard into Dashboard
- Add AlertBanner import and render above nav (admin + active alerts only)
- Add AdminMonitoringDashboard import replacing UploadMonitoringDashboard in monitoring tab
- Add activeAlerts state (AlertEvent[]) with isAdmin-gated useEffect fetch
- Add handleAcknowledge with optimistic update and re-fetch on failure
- Remove UploadMonitoringDashboard import (replaced by AdminMonitoringDashboard)
2026-02-24 16:38:52 -05:00
admin
6ab8af3cde docs(04-01): complete adminService monitoring extensions and frontend components plan
- SUMMARY.md created for 04-01
- STATE.md updated to Phase 4 Plan 2, decisions logged
- ROADMAP.md progress updated for phase 4 (1/2 summaries)
- REQUIREMENTS.md: ALRT-03 marked complete
2026-02-24 16:37:13 -05:00
admin
b457b9e5f3 feat(04-01): create AlertBanner and AdminMonitoringDashboard components
- AlertBanner filters to active service_down/service_degraded alerts only
- AlertBanner renders red banner with AlertTriangle icon and X Acknowledge button
- AdminMonitoringDashboard fetches health+analytics concurrently via Promise.all
- Health panel shows 1x4 grid of service status cards with colored dots
- Analytics panel shows 1x5 stat cards with range selector and Refresh button
- Both components follow existing Tailwind/lucide-react/cn() patterns
2026-02-24 16:35:20 -05:00
admin
f84a822989 feat(04-01): extend adminService with monitoring API methods and types
- Add AlertEvent interface (snake_case per backend raw model data)
- Add ServiceHealthEntry interface (camelCase per backend admin.ts remapping)
- Add AnalyticsSummary interface (camelCase per analyticsService.ts)
- Add getHealth(), getAnalytics(range), getAlerts(), acknowledgeAlert(id) methods
2026-02-24 16:34:29 -05:00
admin
9c4b9a5e12 docs(04-frontend): create phase plan 2026-02-24 16:29:50 -05:00
admin
21eea7f828 docs(04-frontend): research phase frontend integration 2026-02-24 16:15:11 -05:00
admin
400342456f docs(phase-03): complete phase execution and verification 2026-02-24 15:49:41 -05:00
admin
c9edaec8d6 docs(03-01): complete admin API endpoints plan
- 03-01-SUMMARY.md: requireAdminEmail middleware + four admin endpoints
- STATE.md: decisions, session continuity updated
- ROADMAP.md: phase 3 progress updated
- REQUIREMENTS.md: INFR-02, HLTH-01 marked complete

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 15:46:19 -05:00
admin
081c5357c1 docs(03-02): complete analytics instrumentation plan
- Create 03-02-SUMMARY.md with task outcomes and decisions
- Update STATE.md: advance to Phase 3 Plan 2 complete
- Update ROADMAP.md: mark plan progress for phase 3
- Mark ANLY-02 requirement complete in REQUIREMENTS.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 15:45:59 -05:00
admin
4169a3731f feat(03-01): create admin routes and mount at /admin
- admin.ts: four endpoints (GET /health, GET /analytics, GET /alerts, POST /alerts/:id/acknowledge)
- Auth chain: addCorrelationId + verifyFirebaseToken + requireAdminEmail (router-level)
- Health: queries all four service names matching healthProbeService output
- Analytics: validates range format (/^\d+[hd]$/) then delegates to getAnalyticsSummary()
- Alerts: findActive() returns all active alerts; acknowledge returns 404 on not-found
- Response envelope: { success, data, correlationId } matching codebase pattern
- index.ts: mounts admin router at /admin alongside existing routes
2026-02-24 15:44:41 -05:00
admin
dabd4a5ecf feat(03-02): instrument processJob with fire-and-forget analytics events
- Add import for recordProcessingEvent from analyticsService
- Emit upload_started after markAsProcessing (job processing start)
- Emit completed with duration_ms after markAsCompleted (job success)
- Emit failed with duration_ms and error_message in catch block (job failure)
- All calls are void/fire-and-forget (no await) per PITFALL-6 constraint
- Null-guard on job in catch block prevents runtime errors
2026-02-24 15:44:12 -05:00
admin
301d0bf159 feat(03-01): add requireAdminEmail middleware and getAnalyticsSummary function
- requireAdmin.ts: returns 404 (not 403) for non-admin users per locked decision
- Reads env vars inside function body to avoid Firebase Secrets timing issue
- Fails closed if neither ADMIN_EMAIL nor EMAIL_WEEKLY_RECIPIENT configured
- analyticsService.ts: adds AnalyticsSummary interface and getAnalyticsSummary()
- Uses getPostgresPool() for aggregate SQL (COUNT/AVG not supported by Supabase JS)
- Parameterized interval with $1::interval cast for PostgreSQL compatibility
2026-02-24 15:43:53 -05:00
admin
ad464cb633 docs(03): create phase plan 2026-02-24 15:37:15 -05:00
admin
4807e85610 docs(03): research phase domain 2026-02-24 15:33:12 -05:00
admin
6c8af6d35f docs(03): capture phase context 2026-02-24 15:27:36 -05:00
admin
a29d449e58 docs(phase-02): complete phase execution and verification 2026-02-24 14:40:39 -05:00
admin
e4a7699938 docs(02-04): complete runHealthProbes + runRetentionCleanup plan
- Phase 2 plan 4 complete — two scheduled Cloud Function exports added
- SUMMARY.md created with decisions, deviations, and phase readiness notes
- STATE.md updated: phase 2 complete, plan counter at 4/4
- ROADMAP.md updated: phase 2 all 4 plans complete
- Requirements HLTH-03 and INFR-03 marked complete

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 14:37:00 -05:00
admin
1f9df623b4 feat(02-04): add runHealthProbes scheduled Cloud Function export
- Runs every 5 minutes, separate from processDocumentJobs (PITFALL-2, HLTH-03)
- Calls healthProbeService.runAllProbes() then alertService.evaluateAndAlert()
- Uses dynamic import() pattern matching processDocumentJobs
- retryCount: 0 — probes re-run in 5 minutes, no retry needed
- Lists all required secrets: anthropicApiKey, openaiApiKey, databaseUrl, supabaseServiceKey, supabaseAnonKey
2026-02-24 14:35:01 -05:00
admin
0acacd1269 docs(02-03): complete alertService plan
- SUMMARY.md with deduplication, lazy transporter, and email decisions
- STATE.md: plan 3/4, 50% progress, decisions recorded
- ROADMAP.md: phase 02 updated (3/4 summaries)
- REQUIREMENTS.md: ALRT-01, ALRT-02, ALRT-04 marked complete
2026-02-24 14:33:05 -05:00
admin
4b5afe2132 test(02-03): add alertService unit tests (8 passing)
- healthy probes trigger no alert logic
- down probe creates alert_events row and sends email
- degraded probe uses alert_type service_degraded
- deduplication suppresses row creation and email within cooldown
- recipient read from process.env.EMAIL_WEEKLY_RECIPIENT
- missing recipient skips email but still creates alert row
- email failure does not throw (non-throwing pipeline)
- multiple probes processed independently
- vi.mock factories use inline vi.fn() only (no TDZ hoisting errors)
2026-02-24 14:30:16 -05:00
admin
91f609cf92 feat(02-03): create alertService with deduplication and email
- evaluateAndAlert() iterates ProbeResults and skips healthy probes
- Maps 'down' -> 'service_down', 'degraded' -> 'service_degraded'
- Deduplication via AlertEventModel.findRecentByService with configurable cooldown
- Creates alert_events row before sending email (suppression skips both)
- Recipient read from process.env.EMAIL_WEEKLY_RECIPIENT (never hardcoded)
- createTransporter() called inside function scope (Firebase Secret timing fix)
- Email failures caught and logged, never re-thrown
2026-02-24 14:28:20 -05:00
admin
520b6b1fe2 docs(02-01): complete analytics service plan
- Created 02-01-SUMMARY.md with full execution documentation
- Updated ROADMAP.md with phase 2 plan progress (2 of 4 plans with summaries)
- Marked requirements ANLY-01 and ANLY-03 complete in REQUIREMENTS.md
- Added 02-01 key decisions to STATE.md
2026-02-24 14:26:41 -05:00
admin
018fb7a24c docs(02-02): complete health probe service plan
- SUMMARY.md: 4 probers, 9 unit tests, nodemailer installed
- STATE.md: advanced to phase 2 plan 2, added 5 key decisions
- ROADMAP.md: updated phase 2 progress (2/4 summaries)
- REQUIREMENTS.md: marked HLTH-02 and HLTH-04 complete
2026-02-24 14:25:45 -05:00
admin
cf30811b97 test(02-01): add analyticsService unit tests
- 6 tests: recordProcessingEvent (4 tests) + deleteProcessingEventsOlderThan (2 tests)
- Verifies fire-and-forget: void return (undefined), no throw on Supabase failure
- Verifies error logging on Supabase failure without rethrowing
- Verifies null coalescing for optional fields (duration_ms, error_message, stage)
- Verifies cutoff date math (~30 days ago) and row count return
- Uses makeSupabaseChain() pattern from Phase 1 model tests
2026-02-24 14:23:42 -05:00
admin
a8ba884043 test(02-02): add healthProbeService unit tests
- 9 tests covering all 4 probers and orchestrator
- Verifies all probes return 4 ProbeResults with correct service names
- Verifies results persisted via HealthCheckModel.create 4 times
- Verifies one probe failure does not abort other probes
- Verifies LLM probe 429 returns degraded not down
- Verifies Supabase probe uses getPostgresPool (not PostgREST)
- Verifies Firebase Auth distinguishes expected vs unexpected errors
- Verifies latency_ms is a non-negative number
- Verifies HealthCheckModel.create failure is isolated
2026-02-24 14:23:35 -05:00
admin
41298262d6 feat(02-02): install nodemailer and create healthProbeService
- Install nodemailer + @types/nodemailer (needed by Plan 03)
- Create healthProbeService.ts with 4 probers: document_ai, llm_api, supabase, firebase_auth
- Each probe makes a real authenticated API call
- Each probe returns structured ProbeResult with status, latency_ms, error_message
- LLM probe uses cheapest model (claude-haiku-4-5) with max_tokens 5
- Supabase probe uses getPostgresPool().query('SELECT 1') not PostgREST
- Firebase Auth probe distinguishes expected vs unexpected errors
- runAllProbes orchestrator uses Promise.allSettled for fault isolation
- Results persisted via HealthCheckModel.create() after each probe
2026-02-24 14:22:38 -05:00
admin
ef88541511 feat(02-01): create analytics migration and analyticsService
- Migration 013: document_processing_events table with CHECK constraint on event_type
- Indexes on created_at (retention queries) and document_id (per-doc history)
- RLS enabled following migration 012 pattern
- analyticsService.recordProcessingEvent(): void return (fire-and-forget, never throws)
- analyticsService.deleteProcessingEventsOlderThan(): Promise<number> (retention delete)
- getSupabaseServiceClient() called per-method, never cached at module level
2026-02-24 14:22:05 -05:00
admin
73f8d8271e docs(02-backend-services): create phase plan 2026-02-24 14:14:54 -05:00
admin
fcb3987c56 docs(02): research phase backend services domain 2026-02-24 14:08:02 -05:00
admin
13454fe860 docs(phase-01): complete phase execution and verification 2026-02-24 14:00:10 -05:00
admin
20e3bec887 docs(01-02): complete model unit tests plan
- SUMMARY: 33 tests for HealthCheckModel (14) and AlertEventModel (19)
- STATE: Advanced to plan 02 complete, added 3 mock pattern decisions
- ROADMAP: Phase 1 Data Foundation marked complete (2/2 plans)
2026-02-24 12:22:12 -05:00
admin
e630ff744a test(01-02): add AlertEventModel unit tests
- Tests cover create (valid, default status active, explicit status, with details JSONB)
- Input validation (empty name, invalid alert_type, invalid status)
- Supabase error handling (throws descriptive message)
- findActive (all active, filtered by service, empty array)
- acknowledge (sets status+timestamp, throws on not found via PGRST116)
- resolve (sets status+timestamp, throws on not found)
- findRecentByService (found within window, null when absent — deduplication use case)
- deleteOlderThan (cutoff date, returns count)
- All 41 tests pass (14 HealthCheck + 19 AlertEvent + 8 existing)
2026-02-24 12:22:12 -05:00