Add production Docker compose + on-startup PocketBase bootstrap

Introduce registry-pull production stacks (docker-compose.prod.yml) for
both the multi-container Docker setup and the all-in-one Docker AIO image,
with everything an operator needs (superuser, super-admin, ports, volumes)
driven from .env.

The API Server now bootstraps PocketBase on startup: a new internal/bootstrap
package (Go port of setup-pocketbase.mjs) creates missing collections,
reconciles existing ones, and creates the DriverVault super-admin from
DRIVERVAULT_SUPERADMIN_* when absent. Idempotent and gated by PB_BOOTSTRAP.
The PocketBase superuser is still upserted by the PocketBase container, since
the REST API cannot bootstrap the first superuser.

Move PocketBase to port 8070 (internal + published) and the web app to 8090
across both stacks, with matching CORS defaults.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
tajniak81
2026-07-19 15:35:33 +02:00
co-authored by Claude Opus 4.8
parent 1e76c2b7f9
commit 30c9cdebe9
17 changed files with 1042 additions and 23 deletions
+21
View File
@@ -15,6 +15,7 @@ import (
"time"
"drivervault/apiserver/internal/api"
"drivervault/apiserver/internal/bootstrap"
"drivervault/apiserver/internal/config"
"drivervault/apiserver/internal/pb"
)
@@ -44,6 +45,26 @@ func main() {
log.Println("WARNING: POCKETBASE_ADMIN_EMAIL/PASSWORD unset — management endpoints return 503 until configured")
}
// Bring PocketBase up to the expected schema (create missing collections,
// reconcile existing ones) and ensure the super-admin. Idempotent, so it runs
// on every boot. Non-fatal: a fresh PocketBase that isn't reachable yet, or a
// bad service account, must not stop the panel from coming up so a superadmin
// can log in and fix the connection.
if cfg.Bootstrap && cfg.AdminConfigured() {
bootCtx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
if err := bootstrap.Run(bootCtx, client, bootstrap.Options{
UsersCollection: cfg.UsersCollection,
SuperAdminEmail: cfg.SuperAdminEmail,
SuperAdminPassword: cfg.SuperAdminPassword,
SuperAdminName: cfg.SuperAdminName,
}); err != nil {
log.Printf("WARNING: bootstrap failed: %v", err)
} else {
log.Println("bootstrap: PocketBase schema ready")
}
cancel()
}
srv := api.New(cfg, client)
if err := srv.StartPlugins(); err != nil {