Database Reference¶
Describe the Borealis PostgreSQL schema, table ownership, runtime interactions, and legacy migration structures so operators and Codex agents can troubleshoot and change schema safely.
Scope¶
- Primary runtime database: PostgreSQL (set via
BOREALIS_DATABASE_URL). Linux Engine container deployments use thepostgres-dbservice on127.0.0.1:5432. - Assembly catalog tables live in PostgreSQL
assemblies.*.
Quick Relationship Map¶
sites (id) --------------------< device_sites (site_id)
| |
| +---- device hostname mapping (logical to devices.hostname)
|
+------------------------< device_approvals (site_id, soft relation)
|
+------------------------< credentials (site_id, ON DELETE SET NULL)
devices (guid) ----------------< refresh_tokens (guid)
devices (guid) ----------------< device_keys (guid)
devices (guid) ----------------< device_approvals (guid, optional)
agent enrollment fingerprint ---< enrollment_code_failures (logical identity)
scheduled_jobs (id) ----------< scheduled_job_runs (job_id)
scheduled_job_runs (id) ------< scheduled_job_run_activity (run_id)
scheduled_job_runs (id) ------< scheduled_job_run_targets (run_id)
activity_history (id) --------< scheduled_job_run_activity (activity_id, unique)
watchdogs (id) ---------------< watchdog_sites (watchdog_id)
watchdogs (id) ---------------< watchdog_targets (watchdog_id)
watchdogs (id) ---------------< watchdog_device_overrides (watchdog_id)
watchdogs (id) ---------------< watchdog_device_state (watchdog_id)
watchdogs (id) ---------------< watchdog_incidents (watchdog_id)
users (id/username) ----------< device_approvals.approved_by_user_id (soft relation)
users (id) -------------------< user_site_assignments (user_id)
sites (id) -------------------< user_site_assignments (site_id)
Important PostgreSQL Behavior¶
- Borealis uses PostgreSQL as the live Engine database, so engine troubleshooting should focus on server-side constraints, indexes, sequences, and transaction boundaries.
- Constraint enforcement, indexes, and transactions are handled server-side by PostgreSQL.
- Some Borealis relations remain intentionally soft in schema/API logic, so application code still performs explicit cleanup and validation for tables such as
device_sitesand approval mappings. - Borealis now treats database connections as short-lived pooled resources. Request handlers and background services should fetch rows, release the connection, and then perform Python-side enrichment, JSON shaping, crypto, GitHub lookups, or target expansion outside the transaction boundary.
- Healthy pooled sessions often appear in
pg_stat_activityasstate = idle,wait_event = ClientRead, and a recentROLLBACKstatement. That pattern means the session is clean and ready to be reused. - Unhealthy sessions usually appear as
state = idle in transactionwith an olderSELECT,UPDATE, orINSERTstill attached. That pattern means Borealis is holding a transaction open after the SQL work is already done.
Connection Lifecycle Guidelines¶
Healthy patterns¶
- Open the connection immediately before the SQL work starts.
- Execute the minimum required statements.
- Fetch the rows or commit the write.
- Close or return the connection to the pool immediately.
- Perform non-DB work after the connection has been released:
- JSON parsing and payload shaping.
- Device/filter/watchdog target expansion.
- Aegis encryption or decryption.
- GitHub or other network lookups.
- AG Grid summary aggregation and UI formatting.
Unhealthy patterns¶
- Holding a connection open while calling
resolve_target_entries(),fetch_devices(), or other target-resolution helpers. - Holding a connection open while decrypting credentials or encrypting secret blobs.
- Holding a connection open while fetching repo hashes, waiting on Socket.IO, or calling other integrations.
- Returning large payloads after
cur.fetchall()without first closing the connection. - Reusing a write transaction for post-commit readback when the response can be assembled in a fresh short-lived read.
Practical symptoms¶
QueuePooltimeout errors inEngine/Services/api-backend/logs/error.log.- Operators seeing random
500responses on otherwise unrelated routes such as/api/auth/me. - Socket reconnect churn or delayed page refreshes when the Engine is under load.
pg_stat_activityshowing manyidle in transactionrows older than a few seconds.- Pages that should be read-only becoming slower as more operators are online.
Operator CLI check for live PostgreSQL sessions¶
- Operators with root access on the Engine host can inspect Borealis PostgreSQL sessions directly during troubleshooting.
- Run this command from the Engine host shell:
- Healthy pooled connections usually appear as
state = idle,wait_event = ClientRead, and a recentROLLBACKstatement. - Problematic sessions usually appear as
state = idle in transactionwith an olderSELECT,UPDATE, orINSERTstill attached. - If Borealis feels slow, this command is the fastest way to distinguish normal pooled connections from sessions that are holding transactions open too long.
Engine Tuning Profiles¶
- Legacy systemd deployments auto-detected the Engine host profile during deployment and re-deployment.
- Container deployments render conservative DB pool values into
Engine/Deploy/compose.env; tune those values explicitly for larger installations until profile-aware container tuning is added. - Profile selection is based on detected CPU and RAM only.
- Storage is displayed in the CLI as deployment guidance, but it does not change the selected profile or the applied DB tuning.
- The launcher writes the selected profile metadata and tuning values into
Engine/database.envand then applies the PostgreSQL settings with launcher-managedALTER SYSTEMstatements. - The current auto-selected single-node profiles are:
HomelabSmall BusinessMSP / ProductionEnterprise- The roadmap-only
Enterprise Clusteredprofile inREADME.mdis not auto-selected today because Borealis does not yet support clustered orchestration.
Profile selection thresholds¶
- Borealis scores CPU and RAM separately, then uses the lower of the two ranks as the effective profile so an unbalanced host does not get over-tuned.
- CPU thresholds:
Homelab: fewer than8vCPUSmall Business:8-15vCPUMSP / Production:16-23vCPUEnterprise:24+vCPU- RAM thresholds:
Homelab: fewer than16 GiBSmall Business:16-31 GiBMSP / Production:32-63 GiBEnterprise:64 GiB+
Shared values across all auto-configured profiles¶
- Engine DB connect timeout:
BOREALIS_DB_CONNECT_TIMEOUT = 15- Engine idle-in-transaction safety timeout:
BOREALIS_DB_IDLE_IN_TXN_TIMEOUT_MS = 60000- PostgreSQL autovacuum scale factors:
autovacuum_vacuum_scale_factor = 0.02autovacuum_analyze_scale_factor = 0.01- PostgreSQL WAL and planner defaults:
wal_compression = oncheckpoint_timeout = 15mincheckpoint_completion_target = 0.9random_page_cost = 1.1
Homelab¶
- Intended host shape:
- fewer than
8vCPU or fewer than16 GiBRAM - Engine DB pool:
BOREALIS_DB_POOL_SIZE = 10BOREALIS_DB_MAX_OVERFLOW = 10- effective pooled Engine connection burst capacity:
20 - PostgreSQL connection ceiling:
max_connections = 80- PostgreSQL memory and cache:
shared_buffers = max(1 GiB, min(25% of RAM, 4 GiB))effective_cache_size = max(4 GiB, min(62.5% of RAM, 12 GiB))work_mem = 4 MBmaintenance_work_mem = 256 MB- PostgreSQL worker and planner parallelism:
max_worker_processes = 8max_parallel_workers = 8max_parallel_workers_per_gather = 2- PostgreSQL autovacuum:
autovacuum_max_workers = 3autovacuum_vacuum_cost_limit = 1000autovacuum_naptime = 30s- PostgreSQL WAL / IO:
max_wal_size = 4GBmin_wal_size = 512MBeffective_io_concurrency = 16
Small Business¶
- Intended host shape:
- at least
8vCPU and at least16 GiBRAM, but below16vCPU or below32 GiBRAM - Engine DB pool:
BOREALIS_DB_POOL_SIZE = 12BOREALIS_DB_MAX_OVERFLOW = 16- effective pooled Engine connection burst capacity:
28 - PostgreSQL connection ceiling:
max_connections = 120- PostgreSQL memory and cache:
shared_buffers = max(4 GiB, min(25% of RAM, 8 GiB))effective_cache_size = max(8 GiB, min(62.5% of RAM, 16 GiB))work_mem = 8 MBmaintenance_work_mem = 512 MB- PostgreSQL worker and planner parallelism:
max_worker_processes = 8max_parallel_workers = 8max_parallel_workers_per_gather = 2- PostgreSQL autovacuum:
autovacuum_max_workers = 4autovacuum_vacuum_cost_limit = 1500autovacuum_naptime = 20s- PostgreSQL WAL / IO:
max_wal_size = 6GBmin_wal_size = 1GBeffective_io_concurrency = 32
MSP / Production¶
- Intended host shape:
- at least
16vCPU and at least32 GiBRAM, but below24vCPU or below64 GiBRAM - Engine DB pool:
BOREALIS_DB_POOL_SIZE = 20BOREALIS_DB_MAX_OVERFLOW = 20- effective pooled Engine connection burst capacity:
40 - PostgreSQL connection ceiling:
max_connections = 150- PostgreSQL memory and cache:
shared_buffers = max(8 GiB, min(25% of RAM, 16 GiB))effective_cache_size = max(20 GiB, min(62.5% of RAM, 32 GiB))work_mem = 8 MBmaintenance_work_mem = 512 MB- PostgreSQL worker and planner parallelism:
max_worker_processes = 12max_parallel_workers = 12max_parallel_workers_per_gather = 4- PostgreSQL autovacuum:
autovacuum_max_workers = 5autovacuum_vacuum_cost_limit = 2000autovacuum_naptime = 15s- PostgreSQL WAL / IO:
max_wal_size = 8GBmin_wal_size = 1GBeffective_io_concurrency = 64
Enterprise¶
- Intended host shape:
- at least
24vCPU and at least64 GiBRAM - Engine DB pool:
BOREALIS_DB_POOL_SIZE = 24BOREALIS_DB_MAX_OVERFLOW = 24- effective pooled Engine connection burst capacity:
48 - PostgreSQL connection ceiling:
max_connections = 180- PostgreSQL memory and cache:
shared_buffers = max(12 GiB, min(25% of RAM, 24 GiB))effective_cache_size = max(32 GiB, min(62.5% of RAM, 64 GiB))work_mem = 16 MBmaintenance_work_mem = 1 GiB- PostgreSQL worker and planner parallelism:
max_worker_processes = 16max_parallel_workers = 16max_parallel_workers_per_gather = 4- PostgreSQL autovacuum:
autovacuum_max_workers = 6autovacuum_vacuum_cost_limit = 2500autovacuum_naptime = 15s- PostgreSQL WAL / IO:
max_wal_size = 12GBmin_wal_size = 2GBeffective_io_concurrency = 64
Maintenance rule¶
- If you change the profile thresholds or any profile-tuned values in
Engine.shor container PostgreSQL configuration, update this section inDocs/Reference/Data and Schema/db-reference.mdin the same change so the operator and Codex guidance stays accurate.
Container PostgreSQL Operations¶
- Runtime state:
Engine/Services/postgres-db/state. - Compose environment:
Engine/Deploy/compose.env. - Default database URL shape:
postgresql://borealis:<generated-password>@127.0.0.1:5432/borealis. Data/Engine/Containers/sterilize-systemd-runtime.shattempts a logical dump of the legacyborealisdatabase before disabling host PostgreSQL and renamingEngine/toEngine.old/.- Preserved dumps land under the legacy runtime after rename, usually
Engine.old/Deploy/legacy-postgres-borealis-<timestamp>.sql. - Import after first container deployment with
./Data/Engine/Containers/import-legacy-postgres-dump.sh Engine.old/Deploy/<dump>.sql. - Do not run host PostgreSQL on
127.0.0.1:5432after migration; it conflicts withpostgres-db.
Preferred remediation pattern¶
conn = db_conn_factory()
try:
cur = conn.cursor()
cur.execute("SELECT ...")
rows = cur.fetchall()
finally:
conn.close()
# Safe to do slower work now.
payload = [shape_row(row) for row in rows]
payload = enrich_payload(payload)
return payload
Patterns to avoid¶
conn = db_conn_factory()
try:
cur = conn.cursor()
cur.execute("SELECT ...")
rows = cur.fetchall()
payload = enrich_payload(rows) # bad: could do crypto/network/target expansion here
return payload
finally:
conn.close()
Detailed Codex Breakdown
API endpoints¶
None. This page documents persistence structures used by many endpoints.
Related documentation¶
Source map¶
- Runtime schema setup:
Data/Engine/Containers/api-backend/data/database.py - Startup migrations:
Data/Engine/Containers/api-backend/data/database_migrations.py - Scheduler database behavior:
Data/Engine/Containers/api-backend/data/services/API/scheduled_jobs/job_scheduler.py - Scheduler queue leasing:
Data/Engine/Containers/api-backend/data/services/job_scheduler/queue.py - Assembly schema source:
Data/Engine/Containers/api-backend/data/assembly_management/databases.py - Bundled official assembly snapshot:
Data/Engine/Containers/api-backend/data/Official_Assemblies/
Troubleshooting queries¶
-- 1) List user-managed Borealis tables in PostgreSQL
SELECT schemaname, tablename
FROM pg_tables
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
ORDER BY schemaname, tablename;
-- 2) Site-to-enrollment code map (current source of truth)
SELECT id, name, enrollment_code
FROM sites
ORDER BY LOWER(name);
-- 3) Pending approvals with site context
SELECT da.id, da.approval_reference, da.hostname_claimed, da.enrollment_code, da.status, s.name AS site_name
FROM device_approvals da
LEFT JOIN sites s ON s.id = da.site_id
WHERE LOWER(da.status) = 'pending'
ORDER BY da.created_at ASC;
-- 4) Recent wrong-code enrollment attempts
SELECT hostname_claimed, enrollment_code_mask, remote_addr, attempt_count, last_seen_at
FROM enrollment_code_failures
ORDER BY last_seen_at DESC;
-- 5) Device-to-site assignments
SELECT d.guid, d.hostname, s.id AS site_id, s.name AS site_name
FROM devices d
LEFT JOIN device_sites ds ON ds.device_hostname = d.hostname
LEFT JOIN sites s ON s.id = ds.site_id
ORDER BY LOWER(d.hostname);
-- 5) Check for orphaned hostname mappings (no matching device row)
SELECT ds.device_hostname, ds.site_id
FROM device_sites ds
LEFT JOIN devices d ON d.hostname = ds.device_hostname
WHERE d.hostname IS NULL;
-- 6) Check for orphaned site mappings (no matching site row)
SELECT ds.device_hostname, ds.site_id
FROM device_sites ds
LEFT JOIN sites s ON s.id = ds.site_id
WHERE s.id IS NULL;
-- 7) Scheduled run/activity linkage health
SELECT r.id AS run_id, r.job_id, r.status, a.id AS link_id, a.activity_id
FROM scheduled_job_runs r
LEFT JOIN scheduled_job_run_activity a ON a.run_id = r.id
ORDER BY r.id DESC
LIMIT 200;
-- 8) Confirm legacy columns are gone (expect 0 rows)
SELECT COUNT(*) AS has_legacy_sites_col
FROM pragma_table_info('sites')
WHERE name = 'enrollment_code_id';
-- 9) Identify sessions that are cleanly pooled and waiting for reuse
SELECT pid, state, wait_event, query_start, now() - query_start AS age, left(query, 200) AS query
FROM pg_stat_activity
WHERE datname = 'borealis'
ORDER BY query_start;
-- 10) Focus only on bad pooled sessions (these should be rare and short-lived)
SELECT pid, usename, state, wait_event, xact_start, now() - xact_start AS txn_age, left(query, 200) AS query
FROM pg_stat_activity
WHERE datname = 'borealis'
AND state = 'idle in transaction'
ORDER BY xact_start NULLS LAST;
Change-management checklist for schema edits¶
- Update creation/migration code first (
database.py,database_migrations.py, scheduler table init, or assembly DB manager). - Update this document and any affected domain docs (
device-auditing.md,scheduled-jobs.md,security-and-trust.md). - Update unit tests that rely on local schema fixtures (
Data/Engine/Unit_Tests/conftest.py). - Verify runtime startup applies schema without errors by checking
Engine/Services/api-backend/logs/engine.log.
Data-model guidance for the current enrollment design¶
- Keep site/code association in
sites.enrollment_codeunless the enrollment model changes fundamentally. - Keep
device_sitesas hostname-to-site map for UI and filter joins. - Treat
device_approvals.enrollment_codeas immutable audit snapshot of the code used at request time. - Treat
enrollment_code_failures.enrollment_code_maskas operator visibility only; do not persist full wrong codes.
Codex checklist for DB connection hygiene¶
- Start with the hottest request or loop, not the easiest file. Prioritize watchdogs, device inventory, scheduled jobs, workflows, and auth-sensitive routes.
- Search for
conn =,_db_conn(),_conn(),cur.fetchall(),commit(), andconn.close()in the target module before editing. - Look for any work between the last SQL statement and
conn.close(): - payload shaping loops
json.loads()or other parsingresolve_target_entries()orfetch_devices()- Aegis crypto helpers
- GitHub or other integration lookups
- If that work does not require the live cursor or transaction, move it after
conn.close(). - For write paths, keep the transaction open only for validation reads that must be consistent with the write. Do not leave the connection open for response shaping.
- If a route resolves filters or device targets more than once, fetch one inventory snapshot and reuse it for the whole request.
- If a helper repeatedly asks for repo or catalog metadata, add a short TTL cache so repeated reads do not create unnecessary external latency while DB connections are checked out.
- After each fix, test the route and inspect
pg_stat_activityto confirm pooled sessions return toidlerather thanidle in transaction.
Engine runtime database tables (engine.*)¶
Enrollment, Identity, and Site Mapping¶
sites¶
- Status: Active.
- Purpose: Site records and static enrollment codes.
- Columns:
id,name,description,created_at,enrollment_code,auto_approve_until. - Constraints and indexes:
idprimary key.nameunique.uq_sites_enrollment_codeunique index onenrollment_code.- Used by:
- Enrollment request lookup (
/api/agent/enroll/request) viaenrollment_code. - Site CRUD APIs (
/api/sites*). - Admin code listing (
GET /api/admin/enrollment-codes). - Device, filter, and scheduled-job joins through
device_sites. - Notes:
- Rebuild migration removes legacy
enrollment_code_idif present. - Current design stores site-code association directly in this table.
auto_approve_untilstores a UTC epoch timestamp for temporary site-level auto-approval. Enrollment only auto-approves while the timestamp is in the future and hostname conflict checks are safe.
device_approvals¶
- Status: Active.
- Purpose: Enrollment approval queue and history.
- Columns:
id,approval_reference,guid,hostname_claimed,ssl_key_fingerprint_claimed,enrollment_code,site_id,status,client_nonce,server_nonce,agent_pubkey_der,created_at,updated_at,approved_by_user_id,onboarding_job_id,onboarding_run_id,onboarding_target. - Constraints and indexes:
idprimary key.approval_referenceunique.idx_da_statusonstatus.idx_da_fp_statuson(ssl_key_fingerprint_claimed, status).idx_da_siteonsite_id.idx_da_onboarding_jobononboarding_job_id.- Used by:
- Enrollment request and poll endpoints.
- Admin approval APIs (
/api/admin/device-approvals*). - Notes:
statuslifecycle typicallypending -> approved|denied|expired -> completed.site_idandapproved_by_user_idare soft relations (not enforced FK in schema).- Automatic local-network onboarding stores source job/run/target context when the agent submits it. Approval trust flow remains unchanged.
- Rebuild migration removes legacy
enrollment_code_idif present.
enrollment_code_failures¶
- Status: Active.
- Purpose: Rolling visibility for agents actively submitting wrong enrollment codes.
- Columns:
id,hostname_claimed,ssl_key_fingerprint_claimed,enrollment_code_mask,remote_addr,first_seen_at,last_seen_at,attempt_count,last_error. - Constraints and indexes:
idprimary key.uq_enrollment_code_failures_fpunique onssl_key_fingerprint_claimed.idx_enrollment_code_failures_last_seenonlast_seen_at.- Used by:
- Enrollment request endpoint records
invalid_enrollment_codefailures after payload and key validation. GET /api/admin/device-approvals?status=wrong_codereturns failures seen in the recent active window.- Notes:
- Stores masked codes only. Full submitted enrollment codes stay out of the table.
- A later valid enrollment request from the same fingerprint clears the failure row.
- Old rows are opportunistically pruned by the enrollment request path.
devices¶
- Status: Active (core inventory and identity table).
- Purpose: Canonical device identity and inventory snapshot.
- Columns:
guid,hostname,description,created_at,last_enrollment_at,agent_hash,agent_role_health,memory,network,software,services,storage,cpu,sessions,processes,device_type,domain,external_ip,internal_ip,last_reboot,last_seen,cpu_percent,memory_percent,last_user,operating_system,uptime,agent_id,connection_type,connection_endpoint,agent_release_channel_override,agent_release_channel,agent_branch,agent_update_channel,agent_update_target_build_id,agent_update_state,agent_update_error,agent_update_source,agent_vnc_password,ssl_key_fingerprint,token_version,status,key_added_at. - Constraints and indexes:
guidprimary key.uq_devices_hostnameunique onhostname.idx_devices_ssl_keyonssl_key_fingerprint.idx_devices_statusonstatus.- Used by:
- Device auth (
guid + fingerprint + token_versionvalidation). - Enrollment finalize/upsert.
- Heartbeats and inventory detail updates.
- Per-role health snapshots for the Device Details
Agent Roles Healthpanel. - VNC/VPN agent routing (
agent_id,agent_vnc_password). - Scheduled-jobs online host snapshot (
last_seen). - Notes:
- Fingerprint change increments
token_versionand revokes active refresh tokens. statussupports revocation states used by auth and token refresh checks.
device_keys¶
- Status: Active.
- Purpose: Device key-fingerprint history and retirement tracking.
- Columns:
id,guid,ssl_key_fingerprint,added_at,retired_at. - Constraints and indexes:
idprimary key.uq_device_keys_guid_fingerprintunique on(guid, ssl_key_fingerprint).idx_device_keys_guidonguid.- Used by:
- Enrollment finalize.
- Agent details updates.
- Notes:
- Old active key rows are marked with
retired_atwhen key material changes.
refresh_tokens¶
- Status: Active.
- Purpose: Long-lived refresh token state.
- Columns:
id,guid,token_hash,dpop_jkt,created_at,expires_at,revoked_at,last_used_at. - Constraints and indexes:
idprimary key.idx_refresh_tokens_guidonguid.idx_refresh_tokens_expires_atonexpires_at.- Used by:
- Enrollment poll finalization (
INSERT). - Token refresh endpoint (
/api/agent/token/refresh). - Enrollment key-rotation logic (
revoked_atupdate).
device_sites¶
- Status: Active.
- Purpose: Site assignment map for hostnames.
- Columns:
device_hostname,site_id,assigned_at. - Constraints and indexes:
device_hostnameunique.- FK declared:
site_id -> sites(id) ON DELETE CASCADE. - Used by:
- Enrollment finalize site assignment.
- Site assignment APIs (
/api/sites/assign,/api/sites/device_map). - Device listing/filter joins for site name.
- Scheduled-job device summaries.
- Notes:
- Mapping key is hostname, not GUID.
- There is no FK to
devices.hostname; this is a logical relationship.
user_site_assignments¶
- Status: Active.
- Purpose: Operator-to-site RBAC scope assignments.
- Columns:
user_id,site_id,assigned_at. - Constraints and indexes:
- Unique index on
(user_id, site_id). idx_user_site_assignments_user_idonuser_id.idx_user_site_assignments_site_idonsite_id.- Used by:
/api/user_site_assignments/selectionand/api/user_site_assignments/assign.- Inventory, approvals, filters, quick jobs, scheduled jobs, tunnel/shell/VNC site-scope checks.
- Notes:
- Admins do not need rows in this table; they implicitly see all sites.
- Operators with no rows here have no site visibility until an admin assigns at least one site.
device_vpn_config¶
- Status: Dormant (schema present, no active read/write paths in current Engine source).
- Purpose: Reserved per-agent VPN configuration metadata.
- Columns:
agent_id,allowed_ports,updated_at,updated_by. - Constraints and indexes:
agent_idprimary key.- Notes:
- Created by migrations; currently unused by active APIs/services.
Operations and UI State¶
activity_history¶
- Status: Active.
- Purpose: Execution/activity ledger for quick jobs and job-like actions.
- Columns:
id,hostname,script_path,script_name,script_type,ran_at,status,stdout,stderr. - Constraints and indexes:
idautoincrement primary key.- Used by:
- Quick-run execution (
/api/scripts/quick_run). - Scheduled-jobs execution parity records.
- WebSocket
quick_job_resultupdates. - Activity APIs (
/api/device/activity/*). - Linked from
scheduled_job_run_activity.activity_id.
device_list_views¶
- Status: Active.
- Purpose: Saved table views for the device list UI.
- Columns:
id,name,columns_json,filters_json,created_at,updated_at. - Constraints and indexes:
idautoincrement primary key.nameunique.- Used by:
/api/device_list_views*CRUD endpoints.- Notes:
- Current schema has no user ownership column; views are globally stored.
device_filters¶
- Status: Active.
- Purpose: Saved filter definitions for target selection and device segmentation.
- Columns:
id,name,description,archived,criteria_mode,site_mode,basic_criteria_json,advanced_criteria_json,last_edited_by,created_at,updated_at. - Constraints and indexes:
idautoincrement primary key.nameunique.- Used by:
/api/device_filters*endpoints.DeviceFilterMatcherfor match counts and scheduled-job target expansion.- Notes:
- Active site membership is stored in
device_filter_sites. - Archived filters are excluded from scheduler pickers and runtime resolution.
metadata_field_definitions¶
- Status: Active.
- Purpose: Global Agent Metadata Field descriptions for fixed fields
Field 001throughField 500. - Columns:
field_number,description,updated_at,updated_by. - Constraints and indexes:
field_numberprimary key.idx_metadata_field_definitions_updatedonupdated_at.- Used by:
/api/metadata_fieldslist/update endpoints.- Device Summary Metadata Fields tab labels.
- Device Filter metadata-field picker.
- Notes:
- Empty descriptions fall back to default labels such as
Field 001.
device_metadata_fields¶
- Status: Active.
- Purpose: Sparse per-device Agent Metadata Field values with timestamp conflict metadata.
- Columns:
device_guid,field_number,field_key,value,modified_at,source,actor,created_at,updated_at. - Constraints and indexes:
(device_guid, field_number)primary key.idx_device_metadata_fields_guidondevice_guid.idx_device_metadata_fields_number_valueon(field_number, value).- Used by:
/api/devices/<device_id>/metadata_fields*endpoints./api/agent/heartbeatmetadata sync.DeviceFilterMatchermetadata-field criteria.- Notes:
- Values are base64-encoded at rest, capped at 1024 decoded characters, and omitted from agent payloads after blank clears are acknowledged.
device_filter_sites¶
- Status: Active.
- Purpose: Normalized site membership for saved device filters.
- Columns:
filter_id,site_id. - Constraints and indexes:
- No dedicated primary key; uniqueness is maintained by filter-write paths.
- Used by:
/api/device_filters*write paths.
watchdogs¶
- Status: Active.
- Purpose: Saved watchdog policy definitions.
- Columns:
id,name,description,archived,enabled,severity,match_mode,site_mode,criteria_json,actions_json,evaluation_interval_seconds,cooldown_seconds,auto_resolve_after_seconds,min_consecutive_matches,boot_grace_seconds,last_edited_by,created_at,updated_at,last_evaluated_at. - Used by:
/api/watchdogs*.WatchdogRuntimeService.- Notes:
- Watchdog definitions are saved independently from runtime state and incident history.
- Saving a watchdog immediately triggers a fresh evaluation pass.
watchdog_sites¶
- Status: Active.
- Purpose: Normalized site-scope rows for watchdogs with explicit site membership.
- Columns:
watchdog_id,site_id. - Used by:
- Watchdog save paths.
- RBAC visibility checks.
watchdog_targets¶
- Status: Active.
- Purpose: Saved dynamic or explicit watchdog targets.
- Columns:
id,watchdog_id,kind,target_json,created_at. - Used by:
- Watchdog target resolution.
- Filter-backed device expansion.
- Notes:
kindisfilterordevice.target_jsonstores the normalized target payload used by runtime expansion.
watchdog_device_overrides¶
- Status: Active.
- Purpose: Device-specific suppressions and disables for one watchdog/device pair.
- Columns:
id,watchdog_id,device_guid,hostname,site_id,state,reason,created_by,created_at,expires_at,updated_at. - Used by:
- Device Watchdogs tab.
- Alerts suppression flow.
watchdog_device_state¶
- Status: Active.
- Purpose: Last-known per-device watchdog evaluation state.
- Columns:
id,watchdog_id,device_guid,hostname,site_id,state,consecutive_matches,first_matched_at,clear_started_at,last_evaluated_at,last_matched_at,last_sample_json,current_incident_id,last_action_at,updated_at. - Used by:
- Watchdog list state summaries.
- Device Watchdogs tab.
- Incident reconciliation and cooldown logic.
- Notes:
statecan includenormal,pending,triggered,suppressed,disabled, andstale_data.
watchdog_incidents¶
- Status: Active.
- Purpose: Watchdog incident history and operator-facing alert queue rows.
- Columns:
id,watchdog_id,device_guid,hostname,site_id,severity,state,title,message,sample_json,rule_summary_json,action_summary_json,opened_at,updated_at,resolved_at,resolution_reason,acknowledged_at,acknowledged_by,trigger_count. - Used by:
GET /api/watchdogs/incidents.- Device Watchdogs tab.
- Acknowledgement and auto-resolve flows.
DeviceFilterMatcher.load_filters()for site-mode hydration.
device_software_inventory¶
- Status: Active.
- Purpose: Normalized installed-software inventory for reliable filtering.
- Columns:
id,device_guid,name,name_normalized,version,source,captured_at,metadata_json. - Constraints and indexes:
idautoincrement primary key.idx_device_software_inventory_guidondevice_guid.idx_device_software_inventory_nameonname_normalized.idx_device_software_inventory_sourceonsource.idx_device_software_inventory_guid_name_sourceon(device_guid, name_normalized, source).- Used by:
/api/agent/detailsingestion refresh.DeviceFilterMatchersoftware-aware matching.- Notes:
- Raw software blobs still live on
devices.softwarefor UI detail display, but matching uses this normalized table first.
Scheduling and Automation¶
scheduled_jobs¶
- Status: Active.
- Purpose: Scheduled-job definitions.
- Columns:
id,name,components_json,targets_json,schedule_type,start_ts,duration_stop_enabled,expiration,execution_context,credential_id,use_service_account,job_kind,enabled,created_at,updated_at. - Constraints and indexes:
idautoincrement primary key.- Used by:
/api/scheduled_jobs*CRUD endpoints.- Scheduler background loop.
- Notes:
credential_idis logical linkage tocredentials.id; no FK constraint in schema.job_kind = automationis normal scheduled automation.job_kind = onboardingis automatic local-network device enrollment.job_kind = agent_maintenancerecords on-demand Agent update and branch/channel switch requests.- Onboarding jobs store discovery entries and exclusion entries inside the JSON
targets_jsononboarding_scoperecord. Inline#comments remain in these saved JSON entries and are stripped only when runtime parsing expands the target list. New onboarding target rows preserve the raw matching scope entry intarget_inputso comments such as10.0.0.56 # LAB-AIO-01can help correlate pending approvals back to the summary row. Agent branch, target platform, remote ports, Windows fallback methods, and per-job onboarding concurrency live in the JSONcomponents_jsondevice_onboardingrecord. No remote machine credential material is copied into either JSON payload.
scheduled_job_runs¶
- Status: Active.
- Purpose: Execution state for scheduled occurrences. Legacy script jobs still use per-target rows; Engine-side Ansible jobs can now use shared rows per playbook component.
- Columns:
id,job_id,scheduled_ts,started_ts,finished_ts,status,error,created_at,updated_at,target_hostname,skip_reason,shared_execution,component_index,component_kind,component_name. - Constraints and indexes:
idautoincrement primary key.- FK declared:
job_id -> scheduled_jobs(id) ON DELETE CASCADE. idx_runs_job_sched_targeton(job_id, scheduled_ts, target_hostname).- Used by:
- Scheduler dispatch and status updates.
- WebSocket quick result handler for run state transitions.
- Scheduled-jobs run history and device status endpoints.
- Notes:
- Zero-target occurrences are stored as
status = Skippedwithskip_reason = no_devices_targeted. - Shared Ansible rows leave
target_hostnameempty and useshared_execution = 1.
scheduled_job_run_activity¶
- Status: Active.
- Purpose: Link table from scheduled runs to
activity_historyrows. - Columns:
id,run_id,activity_id,component_kind,script_type,component_path,component_name,created_at. - Constraints and indexes:
idautoincrement primary key.- FK declared:
run_id -> scheduled_job_runs(id) ON DELETE CASCADE. - FK declared:
activity_id -> activity_history(id) ON DELETE CASCADE. idx_run_activity_runonrun_id.idx_run_activity_activityunique onactivity_id.- Used by:
- Scheduler component dispatch bookkeeping.
- WebSocket run status propagation and run activity lookups.
scheduled_job_onboarding_targets¶
- Status: Active.
- Purpose: Per-target status for automatic local-network onboarding jobs.
- Columns:
id,run_id,job_id,scheduled_ts,site_id,target_input,target_address,target_hostname,ssh_port,status,detail,stdout_snippet,stderr_snippet,approval_reference,created_at,updated_at,finished_at. - Constraints and indexes:
idautoincrement primary key.- FK declared:
run_id -> scheduled_job_runs(id) ON DELETE CASCADE. - FK declared:
job_id -> scheduled_jobs(id) ON DELETE CASCADE. idx_onboarding_targets_runonrun_id.idx_onboarding_targets_jobon(job_id, scheduled_ts).idx_onboarding_targets_statusonstatus.- Used by:
- Automatic local-network onboarding runner.
- Scheduled Jobs result summaries.
/api/onboarding/jobs/<job_id>/targets.- Notes:
- stdout/stderr are sanitized snippets only. Stored machine and domain credentials remain in
credentialsand are not copied into onboarding attempts. - Approval status is not duplicated here.
/api/onboarding/jobs/<job_id>/targetsjoins back todevice_approvalsby saved approval reference or onboarding context, then falls back through hostname/IP matching for legacy rows, and hydrates approval id/status for UI display and inline approval actions.
scheduled_job_onboarding_target_events¶
- Status: Active.
- Purpose: Persistent per-target onboarding timeline used by the WebUI Detailed Breakdown table.
- Columns:
id,target_row_id,run_id,job_id,status,task,detail,stdout_snippet,stderr_snippet,started_at,finished_at,created_at,updated_at. - Constraints and indexes:
idautoincrement primary key.- FK declared:
target_row_id -> scheduled_job_onboarding_targets(id) ON DELETE CASCADE. - FK declared:
run_id -> scheduled_job_runs(id) ON DELETE CASCADE. - FK declared:
job_id -> scheduled_jobs(id) ON DELETE CASCADE. idx_onboarding_target_events_targeton(target_row_id, started_at).idx_onboarding_target_events_runonrun_id.- Used by:
- Automatic local-network onboarding runner.
/api/onboarding/jobs/<job_id>/targets, nested under each target astimelineandevents.- Notes:
- Rows are appended when target task/status changes. Active prior rows are closed with
finished_at; terminal rows are written as completed/failed/skipped snapshots. - stdout/stderr are sanitized snippets captured for the specific task event, not raw remote logs.
scheduled_job_run_targets¶
- Status: Active.
- Purpose: Frozen point-in-time target membership for each scheduled occurrence or shared Ansible playbook run.
- Columns:
id,run_id,device_guid,hostname,site_id,resolved_from_filter_id,inventory_hostname,wireguard_peer_ip,resolved_connection,resolution_status,resolution_reason,resolved_from_filter_ids_json,created_at. - Constraints and indexes:
idautoincrement primary key.- FK declared:
run_id -> scheduled_job_runs(id) ON DELETE CASCADE. idx_scheduled_job_run_targets_runonrun_id.idx_scheduled_job_run_targets_filteronresolved_from_filter_id.idx_scheduled_job_run_targets_hostonhostname.- Used by:
- Scheduler snapshot creation.
- Scheduled-job device history endpoint.
- Notes:
- Legacy rows may still repeat a host when more than one saved filter contributed to the same occurrence target.
- Shared Ansible rows store the generated inventory alias and target-resolution outcome per device.
job_scheduler_work_items¶
- Status: Active.
- Purpose: Durable work queue for
job-schedulerandsite-worker-<uuid>containers. - Columns:
id,dedupe_key,kind,site_id,lane,job_id,run_id,target_id,payload_json,status,attempt_count,priority,available_at,lease_owner,lease_expires_at,heartbeat_at,worker_guid,container_name,error,created_at,updated_at,started_at,finished_at. - Used by:
job-schedulerscheduled ticking and service-action dispatch.- Site-worker onboarding execution.
- Notes:
- Work kinds include
onboarding_run,scheduled_run,scheduled_workflow_run,agent_maintenance_run, andservice_action. scheduled_run,scheduled_workflow_run, andagent_maintenance_runpayloads include task-link metadata for Server Info and the Sites Active Site Workers canvas; secrets stay out ofpayload_json.- Credentials are not stored in
payload_json; workers retrieve decrypted credential material from the internal API only while executing. lease_ownerpluslease_expires_atprotect work from duplicate claims and allow stale work to be reclaimed.
job_scheduler_workers¶
- Status: Active.
- Purpose: Worker lifecycle/status visibility for ephemeral site workers.
- Columns:
worker_guid,container_name,site_id,status,started_at,last_seen_at,idle_since,stopped_at,current_lanes_json,claimed_count,task_links_json,docker_state,exit_code,created_at,updated_at. - Used by:
- Server Info Workers view.
- Sites Active Site Workers canvas.
- Task-scheduler worker reconciliation.
- Notes:
- Worker container names use random UUIDs (
site-worker-<uuid>) and do not include site names. - Terminal site-worker rows are lifecycle records, not job history.
job-schedulerprunes stopped/lost site workers afterBOREALIS_WORKER_HISTORY_SECONDS(default 60 seconds), and/api/server/workers?history_seconds=60hides old terminal rows even if legacy rows lackstopped_at.
job_scheduler_service_snapshots¶
- Status: Active.
- Purpose: Last known Compose service visibility snapshot written by
job-schedulerfor Server Info whenapi-backendhas no Docker socket. - Columns:
service_key,payload_json,updated_at. - Used by:
/api/server/overviewand/api/server/servicesfallback service rows.- Task-scheduler Compose reconciliation.
- Notes:
api-backendreads this table only for display. Docker-backed service actions are queued intojob_scheduler_work_itemsand executed byjob-scheduler.
credentials¶
- Status: Active for scheduler and WebUI credential selection; protected at rest after Aegis Cipher setup.
- Purpose: Stored credential materials for remote execution contexts.
- Columns:
id,name,description,site_id,credential_type,connection_type,username,password_encrypted,private_key_encrypted,private_key_passphrase_encrypted,become_method,become_username,become_password_encrypted,metadata_json,created_at,updated_at. - Constraints and indexes:
idautoincrement primary key.nameunique.- FK declared:
site_id -> sites(id) ON DELETE SET NULL. - Used by:
/api/credentialsCRUD endpoints.- Scheduled Ansible job resolution for
sshandwinrmexecution contexts. - Notes:
- Before Aegis setup, legacy plaintext values may still exist in the
*_encryptedcolumns as migration input. - After Aegis setup, secret columns store ASCII
aegis:v1:envelopes even though the schema type remainsBLOB. - The runtime decrypts credential secrets on demand through
Data/Engine/Containers/api-backend/data/services/aegis_cipher.py. - Operator-facing credential APIs now wait for bootstrap phase
login_required; stale operator sessions no longer bypass the lock state after restart. - If
metadata_jsoncontainsaegis_secret_state = "reset_required", the record survived an Aegis force reset but one or more stored secret fields were intentionally destroyed and must be re-entered.
aegis_cipher_state¶
- Status: Active after the first Aegis Cipher setup.
- Purpose: Singleton state row for the Engine-global Aegis KDF parameters and verification token.
- Columns:
id,kdf_name,kdf_params_json,verification_token,created_at,updated_at. - Constraints and indexes:
idprimary key, with Borealis usingid = 1.- Used by:
Data/Engine/Containers/api-backend/data/services/aegis_cipher.pysetup, unlock, rotation, migration, and force-reset flows./api/bootstrap/state,/api/bootstrap/aegis/setup,/api/bootstrap/aegis/unlock,/api/bootstrap/admin/*,/api/aegis/status,/api/aegis/rotate, and/api/aegis/force_reset.- Notes:
kdf_params_jsonstores the per-installscryptparameters and Base64 salt.verification_tokenstores an Aegis-encrypted constant plaintext that validates the entered cipher without persisting the derived key.- The derived key is never stored in the database; it lives only in Engine memory for the process lifetime.
- A force reset deletes the singleton row after protected secret material is destroyed, allowing a fresh Aegis setup to start from a clean state.
ansible_play_recaps¶
- Status: Active for Engine-side scheduled Ansible execution; broader API/UI surfacing is still incomplete.
- Purpose: Intended run recap storage for Ansible executions.
- Columns:
id,run_id,hostname,agent_id,playbook_path,playbook_name,scheduled_job_id,scheduled_run_id,activity_job_id,status,recap_text,recap_json,started_ts,finished_ts,created_at,updated_at. - Constraints and indexes:
idautoincrement primary key.run_idunique.idx_ansible_recaps_host_createdon(hostname, created_at).idx_ansible_recaps_statusonstatus.- Used by:
- Engine-side scheduled Ansible runs executed from the Linux Engine.
- Future recap/report APIs and UI views.
agent_service_account¶
- Status: Dormant (schema present, no active read/write paths in current Engine source).
- Purpose: Reserved per-agent service account credential storage.
- Columns:
agent_id,username,password_hash,password_encrypted,last_rotated_utc,version. - Constraints and indexes:
agent_idprimary key.- Notes:
password_encryptedremains outside Aegis Cipher v1 scope because the table has no active runtime read or write paths today.
Access Management¶
users¶
- Status: Active.
- Purpose: Operator identity, login state, and recovery state.
- Columns:
id,username,display_name,password_sha512,role,last_login,created_at,updated_at,mfa_enabled,mfa_disabled,mfa_secret,auth_reset_required,auth_reset_at,auth_source,directory_provider_id,directory_subject,directory_domain,directory_dn,directory_groups_json,directory_last_sync_at,directory_disabled,directory_disabled_at. - Constraints and indexes:
idautoincrement primary key.usernameunique.- Used by:
- Login and MFA flows.
- Bootstrap setup and admin recovery flows.
- User administration APIs.
- Device approval auditing (
approved_by_user_idlookup by id or username). - Notes:
- Usernames, display names, and roles remain plaintext so bootstrap recovery can identify existing administrators before operator login is available.
- After Aegis setup,
password_sha512stores an Aegis envelope containing the SHA-512 password hash, andmfa_secretstores an Aegis envelope containing the operator's TOTP seed. auth_reset_required=1means a force reset destroyed that operator's auth secrets; Borealis blocks normal login until an admin recovery or admin password reset clears the flag.- Initial deployment no longer seeds a default admin automatically; bootstrap creates the first administrator after Aegis is configured.
mfa_disabled=0means MFA is required by default, even before the operator has completed first-time setup.mfa_secretremaining empty withmfa_disabled=0causes the next successful password login to enter MFA setup immediately.auth_source='local'uses Borealis password/passkey auth.auth_source='directory'uses an LDAP/AD provider, keeps Borealis TOTP MFA, and blocks local password/passkey management.directory_disabled=1disables the JIT cache row and invalidates active sessions through request-time user revalidation.
directory_providers¶
- Status: Active.
- Purpose: LDAP, LDAPS, and Active Directory provider configuration.
- Columns:
id,name,provider_type,enabled,priority,domain_suffix,server_urls_json,host_overrides_json,use_ldaps,tls_required,tls_ca_pem,base_dn,bind_dn,bind_password_encrypted,user_search_filter,username_attribute,display_name_attribute,email_attribute,member_of_attribute,group_search_base_dn,nested_groups,kerberos_realm,kerberos_kdc,kerberos_keytab_encrypted,sync_interval_seconds,last_sync_at,last_sync_status,last_sync_message,last_test_at,last_test_status,last_test_message,created_at,updated_at. - Constraints and indexes:
idautoincrement primary key.nameunique.- Index on
enabled, priority. - Used by:
- Directory Services admin APIs.
/api/auth/logindirectory credential-provider routing.- Notes:
- Aegis protects
bind_password_encryptedandkerberos_keytab_encrypted. - Providers must pass
/api/directory/providers/<id>/testbefore enablement. - LDAPS is strict by default; optional PEM trust anchors supplement system trust.
directory_provider_group_mappings¶
- Status: Active.
- Purpose: Allowed/admin group role mapping for directory-authenticated operators.
- Columns:
id,provider_id,group_dn,role,created_at,updated_at. - Constraints and indexes:
idautoincrement primary key.- Unique index on
provider_id, group_dn, role. - Index on
provider_id. - Used by:
- Directory authentication role assignment and admission checks.
- Notes:
role='Admin'grants Borealis Admin.role='User'grants Borealis User and acts as allowed-group membership.
directory_provider_site_mappings¶
- Status: Active.
- Purpose: Directory user-group to Borealis site-scope mapping.
- Columns:
id,provider_id,label,group_dns_json,site_ids_json,position,created_at,updated_at. - Constraints and indexes:
idautoincrement primary key.- Index on
provider_id, position. - Used by:
- Directory Services provider editor Site Assignment tab.
- Directory authentication JIT cache updates that replace
user_site_assignmentsfor non-admin directory users. - Notes:
- Admin directory users remain globally scoped through role semantics.
- User directory groups are unioned across matching mapping rows; each matching mapping contributes all configured
site_ids_jsonentries. - Saving provider site mappings immediately reapplies site scope for cached directory users using their stored
directory_groups_json; directory login and sync also refresh the assignments.
user_passkeys¶
- Status: Active.
- Purpose: Stored WebAuthn passkeys for operator sign-in.
- Columns:
id,user_id,credential_id,public_key,sign_count,label,transports_json,aaguid,created_at,last_used_at,credential_lookup_hmac,secret_encrypted. - Constraints and indexes:
idautoincrement primary key.- Unique index on
credential_lookup_hmac. - Used by:
- Passkey registration, authentication, listing, rename, and delete endpoints.
- Notes:
label,transports_json,created_at, andlast_used_atstay plaintext so the UI can render passkey inventory quickly after operator login.credential_lookup_hmacstoresHMAC-SHA256(app_secret, normalized_credential_id)so Borealis can locate a passkey without keeping the raw credential id in a unique plaintext index.secret_encryptedstores an Aegis envelope containing JSON forcredential_id,public_key,sign_count, andaaguid.- Legacy
credential_id,public_key,sign_count, andaaguidcolumns remain for migration compatibility and may be blanked after the passkey has been migrated intosecret_encrypted.
github_token¶
- Status: Active.
- Purpose: Persisted GitHub API token for repo hash checks and integration.
- Columns:
token,reset_required,reset_at. - Constraints and indexes:
- No explicit primary key.
- Used by:
- GitHub integration store/load.
/api/github/tokenadmin endpoint.- Notes:
- Service writes token by deleting all rows then inserting one row.
- Reads use
SELECT token FROM github_token LIMIT 1orSELECT token, reset_required, reset_at FROM github_token LIMIT 1depending on whether reset-state metadata is needed. - Before Aegis setup, a legacy plaintext token may exist and is migrated during setup.
- After Aegis setup,
tokenstores an ASCIIaegis:v1:envelope, and a locked Engine treats it as unavailable until unlock. - After an Aegis force reset, Borealis can preserve a row with
token = NULL,reset_required = 1, andreset_atset so the WebUI can warn that the GitHub token must be re-entered.
Assembly Catalog Tables (assemblies.*)¶
Domains and Tables¶
assemblies.official_assemblies(AssemblyDomain.OFFICIAL)assemblies.community_assemblies(AssemblyDomain.COMMUNITY)assemblies.user_created_assemblies(AssemblyDomain.USER)
Each table has the same schema:
assemblies.<domain>¶
- Status: Active.
- Purpose: Assembly summary fields and inline payload JSON.
- Columns:
assembly_guid,display_name,summary,assembly_type,assembly_subtype,payload_json,source_repo,source_path,source_version,content_hash,payload_size_bytes,created_at,updated_at. - Constraints and indexes:
assembly_guidprimary key.idx_assemblies_typeonassembly_type.- Notes:
- Payload JSON is stored inline in
payload_json. assembly_typeis the authoritative routing discriminator for editors and execution pipelines.metadata_jsonandpayload_typeare removed from the active schema.- Engine startup validates this schema strictly and fails fast if legacy columns are still present.
source_repo,source_path, andsource_versiontrack Aurora provenance for official assemblies.content_hashstores the Engine-computed canonical SHA-256 used for update detection.- The bundled official snapshot is versioned under
Data/Engine/Containers/api-backend/data/Official_Assemblies/as a seed snapshot and synced intoassemblies.official_assemblieson startup.
assemblies.official_catalog_state¶
- Status: Active.
- Purpose: Tracks bundled seed state plus the latest Aurora catalog metadata applied to each official assembly GUID.
- Columns:
assembly_guid,bundled_hash,remote_hash,catalog_hash,applied_hash,last_applied_source,repo_url,source_url,source_repo,source_path,source_version,last_catalog_sync_at,updated_at. - Constraints and indexes:
assembly_guidprimary key.- Notes:
catalog_hashreflects the latest hash seen in the active official catalog source.applied_hashreflects the version currently written intoassemblies.official_assemblies.last_catalog_sync_atcaptures when Borealis last synced catalog metadata for that GUID.
Deprecated and Removed Schema¶
Removed Tables¶
enrollment_install_codes(removed; superseded bysites.enrollment_code).enrollment_install_codes_persistent(removed; superseded bysites.enrollment_code).payloadsin assembly DBs (removed by migration to consolidatedassembliesschema).
Auto-Migrated Legacy Columns¶
sites.enrollment_code_idis removed by startup rebuild migration.device_approvals.enrollment_code_idis removed by startup rebuild migration.device_filters.scopeanddevice_filters.apply_to_all_sitesare removed by startup rebuild migration.
Deprecated API Surface (still present intentionally)¶
POST /api/admin/enrollment-codesreturns410(legacy_endpoint_removed_use_sites_api).DELETE /api/admin/enrollment-codes/<code_id>returns410(legacy_endpoint_removed_use_sites_api).
Codex remediation workflow¶
- Reproduce the route or background loop that is suspected of exhausting the pool.
- Inspect
pg_stat_activityand note whether the bad rows areidle in transaction, long-livedactive, or simply a large number of healthyidlesessions. - Read the corresponding service code and mark every line between the final SQL statement and
conn.close(). - Move all non-DB work out of the connection scope unless the logic requires transactional consistency.
- For repeated target resolution, build one device snapshot and pass it to downstream helpers instead of refetching inventory.
- For repeated integration lookups, add a small in-memory TTL cache rather than doing the lookup on every request.
- Re-run the route, verify the behavior, and check
pg_stat_activityagain. - If the route is still heavy, then consider query-count reduction, bulk loading, or schema/index tuning. Do not jump to pool-size changes before the connection lifecycle is clean.