You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7.8 KiB

Software Architect Audit Report (March 27, 2026)

Clarification Questions

  1. Should a new theme be creatable with empty categories/topic (draft mode), or must it be valid at creation?
  2. Should GET /themes/{id}/schedule return 404 when absent, or 200 with null?
  3. Which defaults are canonical for themes: DB/spec (max_items_per_category=4, summary_length=3) or UI/handler (5, 2)?

Assumptions

  • Documentation in docs/ is the intended target behavior.
  • This is architecture-focused (entry points, service boundaries, major modules), not a line-by-line audit of all files.

Prioritized Findings

P0

  • Theme creation contract is internally inconsistent and likely broken in practice.
    • Evidence: UI creates empty topic/categories in /Users/oabrivard/Projects/rust/ai_synth/frontend/src/pages/ThemeManager.tsx:144, while backend rejects empty topic/categories in /Users/oabrivard/Projects/rust/ai_synth/backend/src/models/theme.rs:43 and enforces validation in /Users/oabrivard/Projects/rust/ai_synth/backend/src/handlers/themes.rs:45.
    • Why it matters: blocks core onboarding flow.
    • Direction: align API contract + UI create flow (draft-support or valid seeded defaults).

P1

  • Schedule API contract drift across spec, backend, tests, and frontend typing.

    • Evidence: spec says ScheduleResponse or 404 in /Users/oabrivard/Projects/rust/ai_synth/docs/technical_specs.md:420; backend returns 200 null in /Users/oabrivard/Projects/rust/ai_synth/backend/src/handlers/schedules.rs:40; tests expect 200 null in /Users/oabrivard/Projects/rust/ai_synth/backend/tests/api_schedules_test.rs:77; frontend assumes non-null in /Users/oabrivard/Projects/rust/ai_synth/frontend/src/components/settings/SettingsSchedule.tsx:48.
    • Why it matters: runtime fragility and contract confusion.
    • Direction: choose one contract and align all layers.
  • Theme defaults are inconsistent with DB/spec.

    • Evidence: DB migration defaults 4/3 in /Users/oabrivard/Projects/rust/ai_synth/backend/migrations/20260326000028_create_themes_and_migrate.sql:8; handler uses 5/2 in /Users/oabrivard/Projects/rust/ai_synth/backend/src/handlers/themes.rs:56; UI uses 5/2 in /Users/oabrivard/Projects/rust/ai_synth/frontend/src/pages/ThemeManager.tsx:51.
    • Why it matters: non-deterministic behavior and drift.
    • Direction: establish a single source of truth for defaults.
  • Reliability gap: job-store TTL cleanup exists but is not scheduled at runtime.

    • Evidence: cleanup function exists in /Users/oabrivard/Projects/rust/ai_synth/backend/src/services/job_store.rs:153; startup schedules other tasks but not job-store cleanup in /Users/oabrivard/Projects/rust/ai_synth/backend/src/main.rs:66; docs expect periodic cleanup in /Users/oabrivard/Projects/rust/ai_synth/docs/technical_specs.md:778.
    • Why it matters: stale in-memory entries and lock leakage risk over time.
    • Direction: add periodic job_store.cleanup_expired() task.
  • Scheduled generation path does not enforce 15-minute timeout used by manual generation.

    • Evidence: manual timeout in /Users/oabrivard/Projects/rust/ai_synth/backend/src/handlers/generation.rs:89; scheduler calls pipeline directly in /Users/oabrivard/Projects/rust/ai_synth/backend/src/services/scheduler.rs:57; requirement states 15-minute cap in /Users/oabrivard/Projects/rust/ai_synth/docs/requirements.md:30.
    • Why it matters: scheduled runs can overrun and block throughput.
    • Direction: apply same timeout semantics to scheduled execution.

P2

  • Core pipeline and key pages are too large.

    • Evidence: /Users/oabrivard/Projects/rust/ai_synth/backend/src/services/synthesis.rs, /Users/oabrivard/Projects/rust/ai_synth/backend/src/services/scraper.rs, /Users/oabrivard/Projects/rust/ai_synth/frontend/src/pages/ThemeManager.tsx, /Users/oabrivard/Projects/rust/ai_synth/frontend/src/pages/Settings.tsx.
    • Why it matters: weaker SRP, higher cognitive load, slower onboarding/review/testing.
    • Direction: split by bounded responsibilities (phase modules/services/hooks/components).
  • Frontend architectural consistency drift (API and data-loading patterns).

    • Evidence: direct fetch in /Users/oabrivard/Projects/rust/ai_synth/frontend/src/pages/GenerateSynthesis.tsx:241 despite centralized client in /Users/oabrivard/Projects/rust/ai_synth/frontend/src/api/client.ts:25; guideline preference for createResource in /Users/oabrivard/Projects/rust/ai_synth/docs/dev_guidelines.md:174.
    • Direction: enforce API client boundary and consistent data-loading patterns.

SOLID Scorecard

Dimension Score (/5) Notes
Single Responsibility 2 Several large multi-responsibility modules.
Open/Closed 4 LLM provider abstraction/factory is extensible.
Liskov Substitution 4 Provider implementations conform to trait contract cleanly.
Interface Segregation 3 Mostly good boundaries with a few broad surfaces.
Dependency Inversion 3 Good trait usage for LLM, pipeline still tightly coupled in places.
Overall maintainability 3 Good foundations, but contract drift + module size are bottlenecks.

Refactoring Plan

  1. Phase 0: Contract decisions (0.5-1 day, low risk).
    • Decide canonical behavior for theme creation, schedule GET semantics, and defaults.
  2. Phase 1: Correctness alignment (1-2 days, medium risk).
    • Align backend/frontend/tests with chosen contracts.
  3. Phase 2: Reliability hardening (1 day, low-medium risk).
    • Add job-store cleanup scheduling and timeout parity in scheduler.
  4. Phase 3: Backend decomposition (3-5 days, medium risk).
    • Split synthesis pipeline into phase modules with explicit contexts.
  5. Phase 4: Frontend decomposition (3-5 days, medium risk).
    • Split large pages into composables/components and remove direct page-level fetch.
  6. Phase 5: Drift prevention (1-2 days, low risk).
    • Add conformance tests/checks for contracts/defaults and PR architecture checklist.

Architecture/SOLID Scorecard

Dimension Score (/5) Notes
Layering clarity 3 Clear module boundaries, but some runtime orchestration gaps.
SRP 2 Multiple "god files" in backend and frontend.
OCP 4 LLM provider abstraction/factory is cleanly extensible.
DIP 3 Core synthesis is trait-based for LLM, but still tightly coupled to DB/functions.
Testability 3 Strong unit/integration coverage in backend; scheduler/e2e gaps remain.
Spec alignment 2 Multiple contract/default mismatches.

Refactoring Plan (Architecture-Level)

Phase 1 (1-2 days) — Contract and reliability fixes

  • Align theme creation contract (UI + model validation + tests).
  • Align schedule GET semantics across docs/handler/tests/frontend types.
  • Add periodic job_store.cleanup_expired() background task.
  • Apply 15-minute timeout to scheduled generation path.

Phase 2 (3-5 days) — Backend decomposition

  • Split services/synthesis.rs into submodules:
    • init.rs (load settings/theme/provider)
    • phase1_personalized.rs
    • phase2_fallback.rs
    • finalize.rs
    • tracing.rs
  • Introduce explicit pipeline context structs to reduce argument fanout.

Phase 3 (3-5 days) — Frontend decomposition

  • Extract page-level logic from ThemeManager and Settings into composables/hooks:
    • useThemeEditor, useSourcesManager, useScheduleConfig, useSettingsForm
  • Normalize API usage through api/client.ts only.

Phase 4 (2-3 days) — Conformance hardening

  • Add spec-conformance tests for defaults, schedule contract, and theme creation.
  • Add architecture fitness checks (lint/custom tests) for forbidden contract drifts.

Quick Wins (< 1 day)

  1. Add scheduled timeout wrapper in scheduler.rs.
  2. Add job-store periodic cleanup task in main.rs.
  3. Fix ThemeManager create payload to pass valid initial theme and categories.
  4. Unify schedule GET typing with actual backend behavior.