Maintenance Operations
This page describes the supported procedure for applying schema migrations and restarting Pkgly in a production environment.
Applying database migrations
Pkgly uses SQL files under crates/core/migrations. To apply them manually:
- Back up the database using your standard tooling.
- Connect to Postgres with the same user Pkgly runs under. Example using
psql:bashpsql "$DATABASE_URL" - Run the pending migration scripts in chronological order. Each migration consists of an
*.up.sqlfile. For example:bashRepeat for each newer migration. Keep the session open so you can roll back with the matching\i crates/core/migrations/20251115103000_repository_indexes.up.sql*.down.sqlif needed. - Verify with
SELECTor\dthat the new indexes/tables exist.
Tip: If you manage Postgres with a migration runner (e.g.,
sqlx-cliorjust migrate), use that wrapper instead of applying SQL manually.
Restarting Pkgly services
After migrations, rebuild and restart the services:
- Stop the running stack:bash
docker compose down - Rebuild (if code changed):bashor run
./dev.shnpm --prefix site run build && cargo build --features frontend - Start:bash
docker compose up -d - Check logs for migration output:bash
docker compose logs pkgly
Keep maintenance windows short: apply migrations first, then restart services once the schema is in place so requests hitting old binaries do not fail mid-migration.
Audit logging
Pkgly now emits a dedicated audit stream at info level under the pkgly::audit target.
What is logged:
- Successful user actions on the management API (
/api/**) such as user, storage, repository, security, and token operations. - Successful and denied package operations routed through repository protocol endpoints (
/v2/**,/repositories/**, direct/{storage}/{repository}/...paths). - Successful and denied search, package listing, browse, and websocket browse actions.
What is not logged in the first pass:
- Static/frontend asset requests.
/api/infoand similar low-value informational routes.- Validation, conflict, not-found, or internal-error outcomes unless the result is an authorization failure (
401or403).
Important fields:
actionoutcomeactor_usernameactor_idrepository_idstorage_idpathtrace_id
The existing access log target, pkgly::access, is still emitted separately. Use:
docker compose logs pkgly | grep 'pkgly::audit'If you run JSON logs, filter on "target":"pkgly::audit" and join on trace_id when you need to correlate an audit event with lower-level request or tracing data.