This needs much more work.
Each diagram node needs to be less techy, and link to text below that explains the node.
Bootstrap dependency map
The diagram below illustrates the prerequisites for each step to be successful. Work from top to bottom; each node is blocked until its predecessors are completed.
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.