Files

9.4 KiB

Codebase Concerns

Analysis Date: 2026-04-30

Tech Debt

Backend startup duplication and config drift:

  • Issue: backend/src/index.ts contains two parallel server setup paths (the exported createApp(...) flow and the top-level runtime bootstrap). Plugin/route registration and rate-limit defaults are duplicated in both branches.
  • Files: backend/src/index.ts
  • Impact: Configuration behavior can diverge between test/programmatic app construction and production startup (for example, createApp uses fixed rateLimit max 300, while runtime startup uses process.env.RATE_LIMIT_MAX fallback 100).
  • Fix approach: Extract one canonical app-construction function and let both runtime startup and tests consume it; remove duplicated registration blocks.

Notification architecture leakage and duplicated composition logic:

  • Issue: Notification delivery service code imports a route-layer helper (sendShoutrrrNotification) from settings routes, and large HTML/text reminder composition blocks are duplicated across manual and automatic reminder paths.
  • Files: backend/src/services/notifications/delivery.ts, backend/src/routes/settings.ts, backend/src/routes/planner.ts, backend/src/services/reminder-scheduler.ts
  • Impact: Layer boundary violations increase coupling, and duplicated notification formatting logic makes behavior regressions likely when changing message content or channel behavior.
  • Fix approach: Move sendShoutrrrNotification to a service-layer module, make routes call service APIs only, and centralize email/push payload builders for planner + scheduler flows.

Migration artifact ambiguity in drizzle numbering:

  • Issue: There are two migration files with 0008_ prefix, but the journal tracks only one 0008 tag and then jumps to 0009.
  • Files: backend/drizzle/0008_add_obsolete_medications.sql, backend/drizzle/0008_add_prescription_tracking.sql, backend/drizzle/meta/_journal.json
  • Impact: Developer confusion and higher risk of migration-order mistakes during future schema changes.
  • Fix approach: Align migration file names and journal tags so each migration number is unique and journal order is obvious.

Monolithic UI/editor and route modules with broad lint suppressions:

  • Issue: Core interaction files are very large and rely on file-level biome-ignore-all suppressions for multiple rule categories.
  • Files: frontend/src/pages/MedicationsPage.tsx, frontend/src/components/MobileEditModal.tsx, frontend/src/components/SharedSchedule.tsx, frontend/src/components/MedDetailModal.tsx, backend/src/routes/medications.ts
  • Impact: Refactors become high-risk; local regressions are harder to isolate; suppressed rule categories hide legitimate quality issues in future edits.
  • Fix approach: Split by domain slices (state orchestration vs rendering vs helper transforms), then replace file-level suppressions with narrow, local exceptions only where justified.

Known Bugs

Environment-dependent behavior mismatch between test app factory and runtime app:

  • Symptoms: Programmatic app creation and runtime startup can apply different operational defaults (rate limiting and selected config pathways).
  • Files: backend/src/index.ts
  • Trigger: Using createApp(...) in tests/integration contexts while production startup uses the top-level runtime branch.
  • Workaround: Explicitly pass runtime-equivalent options into createApp(...) in tests until startup construction is unified.

Security Considerations

Server-side outbound notification surface is broad and sensitive to parser correctness:

  • Risk: The app performs server-side HTTP requests to user-configurable notification URLs, including multiple protocol handlers (pushover://, telegram://, gotify://, generic webhook URLs).
  • Files: backend/src/routes/settings.ts
  • Current mitigation: URL sanitation/validation and hostname checks are present (sanitizeNotificationUrl, validateNotificationHostname usage in route logic).
  • Recommendations: Add focused security regression tests for sanitizer bypasses and callback URL edge cases, and keep all outbound request execution in a dedicated service layer.

Auth-off bootstrap path creates implicit default user state:

  • Risk: In auth-disabled mode, startup creates/relies on a default user path automatically.
  • Files: backend/src/db/client.ts
  • Current mitigation: Controlled by AUTH_ENABLED environment setting.
  • Recommendations: Add startup log warnings when running without auth outside development and enforce explicit environment confirmation in deployment templates.

Performance Bottlenecks

Reminder scheduling uses repeated full scans over users and medication/dose datasets:

  • Problem: Reminder checks iterate all user settings and compute stock/prescription reminders with repeated in-memory loops over medication and dose collections.
  • Files: backend/src/services/reminder-scheduler.ts, backend/src/utils/scheduler-utils.ts
  • Cause: Polling/check strategy prioritizes correctness and compatibility over incremental indexing.
  • Improvement path: Introduce incremental candidate selection (changed-medication windows, per-user next-check indices) and reduce repeated whole-set scans.

Intake reminder scheduler polls every minute and may scale linearly with active schedules:

  • Problem: Intake reminder check loop runs continuously at 60s interval and processes all due reminders/users each tick.
  • Files: backend/src/services/intake-reminder-scheduler.ts
  • Cause: Fixed-interval scheduler (CHECK_INTERVAL_MS = 60 * 1000) with loop-driven due-item selection.
  • Improvement path: Move toward next-due-time scheduling or bucketing strategy; keep minute polling as fallback only.

Fragile Areas

Reminder state persistence and lock handling mix sync file IO with best-effort catches:

  • Files: backend/src/services/notifications/state.ts, backend/src/services/reminder-scheduler.ts
  • Why fragile: Reminder state writes are synchronous file writes and some read paths swallow errors (catch {}), while lock/state files are local filesystem coordination primitives.
  • Safe modification: Keep file format backward-compatible, add explicit error telemetry, and add tests for concurrent/failed write scenarios before changing scheduler state logic.
  • Test coverage: No direct tests detected for notifications/delivery.ts and only limited direct state-function assertions.

Desktop/mobile medication edit parity depends on two large independent UI paths:

  • Files: frontend/src/pages/MedicationsPage.tsx, frontend/src/components/MobileEditModal.tsx, frontend/src/components/medications/MedicationEditCoordinator.tsx
  • Why fragile: The same editing domain is implemented in separate surfaces, each with dense UI logic and custom interaction handling.
  • Safe modification: Apply shared form-section components first, then update desktop and mobile in the same change; validate both paths with targeted tests.
  • Test coverage: Coverage exists (MedicationEditCoordinator, MobileEditModal, MedicationDialogs tests), but parity regressions remain a recurring risk due to file size/complexity.

Scaling Limits

Current reminder architecture is single-node/local-state oriented:

  • Current capacity: Scheduler state and lock coordination are local files under data directory (reminder-state.json, scheduler-locks/*).
  • Limit: Horizontal multi-instance scaling can duplicate work or require externalized coordination.
  • Scaling path: Move reminder state/locks to DB or distributed lock backend and make scheduler execution leader-aware.

SQLite file-backed persistence constrains concurrent write scaling:

  • Current capacity: Single SQLite file with local filesystem path resolution.
  • Limit: Higher write concurrency and distributed deployments will hit filesystem/database locking and throughput limits.
  • Scaling path: Keep SQLite for local/small deployments; define migration path to managed DB for larger multi-user workloads.

Dependencies at Risk

Route-to-service coupling in notification stack:

  • Risk: Service-layer delivery module depends on route-layer helper import.
  • Impact: Refactors of route modules can break unrelated notification infrastructure and complicate testing boundaries.
  • Migration plan: Move shared notification send helpers into backend/src/services/notifications/* and keep route modules thin.

Missing Critical Features

Risk-driven scheduler stress/integration test suite for state-lock edge cases:

  • Problem: Complex scheduler/state code paths rely on file coordination and mixed channel delivery outcomes, but dedicated stress/chaos-style verification is limited.
  • Blocks: High-confidence scaling and reliability changes in reminder subsystems.

Test Coverage Gaps

Notification delivery abstraction lacks direct unit tests:

  • What's not tested: Direct behavior of SMTP transport creation/result validation and push delivery helpers in the dedicated delivery module.
  • Files: backend/src/services/notifications/delivery.ts
  • Risk: Regressions in recipient validation, SMTP response handling, or provider fallback can ship unnoticed.
  • Priority: High

Reminder state persistence/locking has limited direct verification:

  • What's not tested: Corrupted file recovery, concurrent state writes, and lock stale-file behavior under failure modes.
  • Files: backend/src/services/notifications/state.ts, backend/src/services/reminder-scheduler.ts
  • Risk: Duplicate sends or missed sends after crashes/restarts are difficult to detect early.
  • Priority: High

Concerns audit: 2026-04-30