Each service plugin now independently initializes its own DB connection
via shared/db/init.ts instead of depending on a central service-store
plugin. This removes the inter-plugin dependency ordering and the
plugin-registry singleton, making each service self-contained.
- Move db-adapter, repository, mappers, migrations, adapters to shared/db/
- Create shared/db/config.ts (reusable dbConfigSchema) and init.ts
- Delete service-store plugin and plugin-registry
- Add db config block to each service's ConfigSchema + sec-config template
- Move event_log purge timer into service-admin-http
- Update all import paths across shared modules and plugins
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cloud cameras are now a distinct type ('cloud') managed entirely by
sync. Bidirectional: cameras added in vendor cloud appear automatically,
removed cameras get deleted. Cloud cameras and their entities are
read-only in admin UI — no manual editing.
- Camera type CHECK widened to include 'cloud'
- New columns: cloud_account_id, cloud_vendor_camera_id,
cloud_stream_url, cloud_stream_type
- Repo: upsertCloudCamera, deleteCloudCamerasNotIn,
listCloudCamerasByAccount
- Sync replaces import: full reconciliation per account
- Hik-Connect: fetch HLS preview URLs via previewURLs endpoint
- Tuya: fetch stream URLs during sync (not just on demand)
- Kiosk API: GET /api/kiosk/cameras/:id/stream returns fresh
relay URL from vendor (session-based URLs expire)
- Cloud cameras show read-only detail page with cloud badge
- Coolify compose: postgres 18 as default, BF_DB=postgres,
server depends_on postgres healthy
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PG migrations still had the original table structure (layouts with
template_id/display_id, layout_cells with region_name) that SQLite
dropped in v0.5. PG deploy would fail because repo code expects the
final schema.
Fixes: layouts table (removed template_id/display_id/is_default),
layout_cells (removed region_name), added display_layouts join table,
kiosks.encrypt_key_encrypted, entities.name UNIQUE, all missing
indexes (sessions active, event_log received, audit_log actor,
firmware version/arch unique), foreign keys on pairing_codes/
event_log/firmware/rollouts, kiosk_gpio_bindings.created_at +
CHECK constraints.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add cloud_accounts table to PostgreSQL tenant migrations (was only
in SQLite).
- Artifact cleanup now skips releases referenced by active/queued/paused
rollouts (CASCADE would delete the rollout).
- Add invisible cursor theme install to setup-pi-kiosk.sh (was only
in pi-gen image build).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>