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.