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.
117 lines
7.8 KiB
Markdown
117 lines
7.8 KiB
Markdown
# 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.
|