customer-presentation/OPERATIONS.md
Arlind Ukshini d5f578a581 update docs
2026-04-23 15:00:53 +02:00

4.4 KiB

Operations

Day-to-day commands for running project-bifrost.

Managing invites

All commands run on the VPS as the fenja user.

# Add someone
sudo -u fenja node /opt/fenja/bin/invite.js add someone@example.com

# Remove someone (doesn't kill their active session — see below)
sudo -u fenja node /opt/fenja/bin/invite.js remove someone@example.com

# List everyone
sudo -u fenja node /opt/fenja/bin/invite.js list

Removing an invite stops a user from requesting new codes, but doesn't invalidate their existing session cookie (valid 30 days). To kick them out immediately, also run:

sudo sqlite3 /opt/fenja/data/fenja.sqlite \
  "DELETE FROM sessions WHERE email = 'someone@example.com';"

Reading Join-CTA clicks

Every press of the final "Join Project Bifrost" CTA is logged to the bifrost_joins table. Use bin/joins.js to read it:

# Every click, newest first (id, email, session)
sudo -u fenja node /opt/fenja/bin/joins.js list

# One row per user, with click count + first/last timestamps
sudo -u fenja node /opt/fenja/bin/joins.js summary

# Full click history for a single user
sudo -u fenja node /opt/fenja/bin/joins.js for someone@example.com

# Totals — clicks + unique users
sudo -u fenja node /opt/fenja/bin/joins.js stats

One row is written per click (the schema uses auto-increment id, not email-as-PK), so re-clicks are preserved. For ad-hoc SQL:

sudo -u fenja sqlite3 /opt/fenja/data/fenja.sqlite \
  "SELECT email, datetime(clicked_at/1000,'unixepoch') FROM bifrost_joins ORDER BY clicked_at DESC;"

Service control

sudo systemctl status fenja          # is it running?
sudo systemctl restart fenja         # restart (after config/code changes)
sudo journalctl -u fenja -f          # live log tail
sudo journalctl -u fenja -n 100      # last 100 lines

Deploying code changes

From your laptop, in WSL, inside the project folder:

# Push to staging on VPS
rsync -avz --delete \
  --exclude node_modules --exclude data --exclude .env --exclude .git \
  ./ user@project-bifrost.fenja.ai:/tmp/fenja-upload/

# Then on the VPS:
ssh user@project-bifrost.fenja.ai
sudo rsync -a --delete /tmp/fenja-upload/ /opt/fenja/
sudo chown -R fenja:fenja /opt/fenja
rm -rf /tmp/fenja-upload

# If package.json changed:
cd /opt/fenja
sudo -u fenja npm ci --omit=dev

# Restart
sudo systemctl restart fenja
sudo journalctl -u fenja -n 20

Confirm [mail] SMTP relay reachable and [bifrost] listening appear in the logs.

Editing secrets (SMTP, pepper)

Secrets live in /etc/fenja/env, not in the repo.

sudo nano /etc/fenja/env
sudo systemctl restart fenja

Never change CODE_PEPPER after go-live — it invalidates every pending code. Not catastrophic (users re-request within 10 min), but avoid unless rotating for security.

Backups

Nightly cron at /etc/cron.d/fenja-backup snapshots the SQLite file to /opt/fenja/data/backup-YYYY-MM-DD.sqlite, keeping 14 days.

Manual snapshot:

sudo -u fenja sqlite3 /opt/fenja/data/fenja.sqlite \
  ".backup /opt/fenja/data/backup-manual-$(date +%F).sqlite"

Pull a backup to your laptop:

scp user@project-bifrost.fenja.ai:/opt/fenja/data/backup-YYYY-MM-DD.sqlite .

Quick health checks

# From your laptop
curl.exe -I https://project-bifrost.fenja.ai/              # expect 200
curl.exe -I https://project-bifrost.fenja.ai/timeline.js   # expect 302 → /

If either fails, check Nginx (sudo systemctl status nginx) and Node (sudo systemctl status fenja).

Troubleshooting

Symptom First thing to check
Users don't get codes journalctl -u fenja -n 50 for SMTP errors
Codes arrive in spam SPF/DKIM/DMARC records on the sending domain
502 Bad Gateway Node crashed — systemctl status fenja then journalctl
504 Gateway Timeout Node running but hung — systemctl restart fenja
Nginx config change broke something sudo nginx -t will tell you exactly what
Can't log in with the right code Clock drift between your machine and the VPS, or pepper mismatch

File locations

/opt/fenja/                 code (owned by fenja:fenja)
/opt/fenja/data/            SQLite + nightly backups
/etc/fenja/env              secrets (root:fenja, 640)
/etc/systemd/system/fenja.service
/etc/nginx/sites-available/project-bifrost
/etc/nginx/sites-enabled/project-bifrost  (symlink)
/etc/letsencrypt/live/project-bifrost.fenja.ai/  TLS certs
/etc/cron.d/fenja-backup