Research: optional standalone runtime
Date: 2026-10-13 | Status: Design research complete; implementation verified
R1. Shared engine and minimal dependencies
Decision: Extract async engine functions within the existing worker package. Keep Celery adapters and their locks/retries/metrics separate. Move infrastructure libraries into distributed extras.
Rationale: Scanner/discovery/ingestion/delivery already use async functions but eagerly import Celery, Valkey locks, and metric objects. Backend app and operations also eagerly load Prometheus/Celery/Redis. A mode flag alone cannot provide a minimal installation.
Alternatives considered: Scanner duplication creates drift; Celery eager mode still needs Celery and does not provide persistent scheduling; another package or generic queue adds unnecessary structure.
R2. SQLite lifecycle
Decision: Extend existing SQLite config with foreign keys, busy timeout, WAL, shared engine resources, and Alembic initialization/upgrades.
Rationale: SQLite is already the default driver. Models/migrations have JSON/list variants; SQLite search has portable ranking and PostgreSQL trigram creation is guarded. Existing tests often use create_all, so full revision-chain support still needs verification. SQLite WAL supports concurrent readers with one writer and needs local shared memory. Alembic batch migrations support reconstruction where SQLite cannot alter a table directly.
Alternatives considered: A separate storage layer or production create_all bypasses existing models/migration history. Support one app on local disk and short transactions.
R3. Runner lifecycle
Decision: Use immediate discovery plus existing heartbeat/cooldown, daily midnight-UTC sync, and dedicated bounded scan/catalog/notification consumers managed by FastAPI lifespan.
Rationale: FastAPI lifespan provides resource startup/shutdown boundaries. The current app has no lifespan and Gunicorn defaults to multiple workers; standalone needs a dedicated one-worker launcher. Large initial catalogs cannot block startup.
Alternatives considered: Request background tasks cannot manage periodic/recovery work; APScheduler and a generic SQLite queue are unnecessary for these fixed jobs. Multiple web workers would create multiple schedulers.
R4. Pending alert durability
Decision: Standalone commits a notification outbox with scan results; distributed keeps current Celery semantics.
Rationale: Current scan results commit before Celery dispatch. Volatile local dispatch would lose alerts during shutdown between persistence and sending. Retain the existing notification policy of three retries with 120-second delays. Upstream acceptance followed by a crash can duplicate delivery; no exactly-once claim.
Alternatives considered: A volatile queue loses alerts; adopting a durable queue for all distributed jobs expands scope.
R5. Python-served frontend
Decision: Package root-based frontend assets with Python and use guarded SPA fallback after API routing.
Rationale: The API client defaults to /api; Vite base changes with GITHUB_REPOSITORY, requiring an explicit standalone root build. Existing cookie/CSRF behavior fits one origin but origin validation still applies. Installed assets cannot depend on repository-relative paths.
Alternatives considered: Node serving/reverse proxy adds a runtime process; serving TypeScript source bypasses production builds.
R6. Admin capabilities
Decision: Preserve DB administration and basic local health/history. Disable trends and expose unsupported broker fields honestly.
Rationale: Current operations queries Celery/Valkey and trends proxies Prometheus. Fake healthy values would hide failures. Explicit local retention is 1,000 records / 24 hours, cleared on restart; durable pending alerts are separate. Sentry remains optional.
Alternatives considered: SQLite time-series storage recreates excluded infrastructure; hiding all operations removes useful health/sync controls.
Implementation verification
Full SQLite revision chain with foreign keys, core-only installation/imports, parsing responsiveness, installed assets, pending delivery recovery, and distributed adapter parity. These checks are complete; see verification evidence.