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