Skip to content

Operations

Do not forget the three secrets from Configuration. A database and bucket restored without QNOP_AUTH_ENCRYPTION_KEY and QNOP_AUTH_ENCRYPTION_SALT will come up, but everything encrypted at rest — stored OIDC client secrets among them — is unreadable.

  1. Read the release notes for the version you are moving to.
  2. Take a backup of both stores.
  3. Pin the new image version and restart.

Liquibase runs the schema migration on startup. The first boot on a new version therefore takes longer than usual; the health check’s start period accounts for this.

Migrations are forward-only. There is no downgrade path — going back to an older image after a migration means restoring from the backup you took in step two. This is the reason step two is not optional.

GET /actuator/health is anonymous; point your load balancer or orchestrator at it, or at the liveness and readiness groups underneath it.

Everything else on /actuator/** — health details, metrics, the Prometheus endpoint — requires an authenticated ADMIN. Scraping metrics means giving the scraper admin credentials, which is a deliberate default: the operational surface is not public.

Beyond the actuator, Administration → Scheduler shows the maintenance jobs and their last runs, and Administration → Storage consistency reports mismatches between the database and the bucket.

qnop schedules several maintenance jobs. In a multi-instance deployment they are coordinated so exactly one instance runs each sweep.

JobDefault scheduleWhat it does
Staged-object reaper0 30 3 * * *removes uploads that were staged but never referenced, after a grace period
Orphan reaper0 15 4 * * *removes bucket objects nothing points at any more
Review archive0 50 3 * * *archives reviews older than the configured window
Review purge0 55 3 * * *purges archived reviews after their retention window

The archive and purge windows are set in Administration → Settings, not in the environment. Both archiving and purging are recorded in the audit trail.

Long-running work triggered by users — text extraction, re-anchoring annotations onto a new version — runs through a durable job queue held in PostgreSQL rather than in memory. A crash or restart mid-extraction resumes rather than losing the work.

Every relevant action is appended to the audit trail: annotation lifecycle (created, classified, resolved, reopened, dismissed, auto-closed), placement changes, workflow transitions, review archive/unarchive/purge, due-date changes, extraction outcomes, orphan deletions and scheduler runs.

It is exposed at GET /api/v1/audit/events, filterable, and readable by the AUDITOR role or an ADMIN — that is the only surface the auditor role unlocks. Actor identity is deliberately resolved there even where the UI pseudonymises it elsewhere, because the point of the trail is accountability.