Bootstrap dependency map
The diagram below captures what must exist before each step can succeed. Work top-to-bottom; each node is blocked until its predecessors are complete.
flowchart TD SA["prodLab SA has read access to the Lab vault (1Password service account settings)"] HOST["provision-host.sh writes prodLab SA token → ~/.op_env"] SA --> HOST DEPLOY["provision-service.sh docker compose up"] HOST --> DEPLOY RACE{"postgres healthy before n8n connects?"} DEPLOY --> RACE WIPE["wipe /opt/n8n/postgres/* restart stack"] RACE -- "race condition (ECONNREFUSED during migrations)" --> WIPE WIPE --> MIGRATE MIGRATE["DB migrations run to completion (all tables created)"] RACE -- "healthy" --> MIGRATE UI["n8n UI accessible at :5678"] MIGRATE --> UI USER["Create initial user (first-run wizard)"] UI --> USER LICENSE["Activate license (Settings → License)"] USER --> LICENSE APIKEY["Create API key (Settings → API → Create API key)"] USER --> APIKEY STORE["Store key in 1Password service.n8n → env.N8N_API_KEY (prodLab vault)"] APIKEY --> STORE REPROVISION["Re-run provision-service.sh (regenerates .env, runs post-deploy hook)"] STORE --> REPROVISION SA --> REPROVISION CREDS["Credentials imported from Lab vault into n8n"] REPROVISION --> CREDS READY["N8N ready for business"] LICENSE --> READY CREDS --> READY
Notes
Race condition (the postgres blip): On a fresh host, docker compose up respects the postgres healthcheck but a brief connection loss mid-migration can leave the schema partially initialized. Symptoms: n8n starts but returns “Error connecting to n8n” in the browser; logs show relation "public.execution_entity" does not exist. Fix: stop the stack, wipe /opt/n8n/postgres/*, restart.
prodLab SA vault access: The prodLab 1Password service account must have read access to the Lab vault (not just prodLab). Without it, import-credentials.sh silently finds no credentials — the op error was previously suppressed by 2>/dev/null and is now visible in the provision log.
API key lifecycle: The API key is stored in the postgres database. If postgres is wiped, the key is gone and a new one must be created, stored in 1Password, and provision-service.sh re-run.