Operations

Administrative Tasks

Common how-to runbooks: granting admin access, the development & deployment workflow, and refreshing the dev database.

Making a user an admin

There is no UI button for this — an admin is created by adding fields to the user's MongoDB document after the account exists.

  1. In the admin panel, create the user as you normally would.
  2. Use Manage Users to search for the new user by email address.
  3. Open the user's edit pane and copy the user's ID from the URL, e.g. https://admin.macaronikid.com/#/admin/user/5d0f…
  4. In MongoDB, find that user document (query by _id).
  5. Add the following fields to the document:
    FieldValueType
    adminTypefullString
    isAdmintrueBoolean
    isTestertrueBoolean
Direct database edit
This writes straight to the production database. Double-check you're editing the correct user document, and prefer a connection with the app credentials over the cluster admin. Removing admin access is the reverse — set isAdmin to false (or remove the fields).

Development & deployment workflow

Branch model

Deploying the API to production

The production API runs on three PM2 nodes — api-1, api-2, api-4 — behind a NodeBalancer. Deploy is a per-node pull + restart (no auto-build, to keep downtime controlled across the cluster):

  1. Confirm the intended code is merged into master.
  2. SSH into each production node one at a time. A "pull" script pulls the latest master and restarts PM2; if a new dependency was added, rebuild (npm install) before restart.
  3. Watch the console for a steady stream of activity without errors. A burst of Mongo connection errors right after restart is normal as long as it settles into a steady green stream.
  4. Repeat for the remaining nodes once each is confirmed healthy.

PM2 deploy is defined in ecosystem.config.js (note: the committed deploy host there is stale — see Environments & Deployment). api-3 is the Coolify-managed worker and is not deployed this way.

Carryover warning from the prior runbook — verify before relying on it
The 2021 runbook warned never to run these steps on "legacy API nodes" that delivered publisher emails/newsletters. Today, newsletter/cron work runs in the worker (api-3 / Coolify), so this warning may be obsolete — but confirm no legacy node is still in the path before deploying.

Deploying the front end (web2)

Committing to master auto-deploys to both production front ends (web-front-1, web-front-2) via the git-deploy.php webhook ("Git Deployment Hamster"). Confirm success at each server's deploy-status URL; if it fails, SSH into the affected box and pull manually.

Refreshing the development database

There's no streamlined prod→dev sync. The dev database is rebuilt by restoring a backup into a new instance — cloning a backup is safer than touching a live, running production node.

  1. Use mongo-1 as the clone source (IP 66.228.44.13) — it usually isn't the primary, so cloning it is lowest-risk. Verify the IP before proceeding.
  2. On the mongo-1 Linode, open the Backups tab and pick the most recent backup.
  3. Restore that backup into a new Linode instance (don't overwrite a production node). After it boots, open the Mongo port and restart Mongo, then connect at the new instance's IP.
  4. Optional — point mongo.dev.macaronikid.com at the new instance: in the CloudFlare DNS dashboard, update the mongo.dev A record to the new server's IP. CloudFlare access requires 2FA — contact bien@macaronikid.com for access.
Protect production
Follow the restore-into-a-new-instance path exactly. Never restore over or re-IP a live production member. This gap (no automated refresh) is tracked in Gaps & Open Questions.