max / makenotwork
- Co-Authored-By
- Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9 files changed,
+10 insertions,
-122 deletions
| @@ -9,34 +9,39 @@ | |||
| 9 | 9 | ||
| 10 | 10 | @font-face { | |
| 11 | 11 | font-family: "Young Serif"; | |
| 12 | - | src: url("/static/fonts/ysrf.ttf"); | |
| 12 | + | src: url("/static/fonts/ysrf.woff2") format("woff2"), | |
| 13 | + | url("/static/fonts/ysrf.ttf") format("truetype"); | |
| 13 | 14 | font-display: swap; | |
| 14 | 15 | } | |
| 15 | 16 | ||
| 16 | 17 | @font-face { | |
| 17 | 18 | font-family: "IBM Plex Mono"; | |
| 18 | - | src: url("/static/fonts/IBMPlexMono-Regular.ttf"); | |
| 19 | + | src: url("/static/fonts/IBMPlexMono-Regular.woff2") format("woff2"), | |
| 20 | + | url("/static/fonts/IBMPlexMono-Regular.ttf") format("truetype"); | |
| 19 | 21 | font-weight: normal; | |
| 20 | 22 | font-display: swap; | |
| 21 | 23 | } | |
| 22 | 24 | ||
| 23 | 25 | @font-face { | |
| 24 | 26 | font-family: "IBM Plex Mono"; | |
| 25 | - | src: url("/static/fonts/IBMPlexMono-Bold.ttf"); | |
| 27 | + | src: url("/static/fonts/IBMPlexMono-Bold.woff2") format("woff2"), | |
| 28 | + | url("/static/fonts/IBMPlexMono-Bold.ttf") format("truetype"); | |
| 26 | 29 | font-weight: bold; | |
| 27 | 30 | font-display: swap; | |
| 28 | 31 | } | |
| 29 | 32 | ||
| 30 | 33 | @font-face { | |
| 31 | 34 | font-family: "Lato"; | |
| 32 | - | src: url("/static/fonts/Lato-Regular.ttf"); | |
| 35 | + | src: url("/static/fonts/Lato-Regular.woff2") format("woff2"), | |
| 36 | + | url("/static/fonts/Lato-Regular.ttf") format("truetype"); | |
| 33 | 37 | font-weight: normal; | |
| 34 | 38 | font-display: swap; | |
| 35 | 39 | } | |
| 36 | 40 | ||
| 37 | 41 | @font-face { | |
| 38 | 42 | font-family: "Lato"; | |
| 39 | - | src: url("/static/fonts/Lato-Bold.ttf"); | |
| 43 | + | src: url("/static/fonts/Lato-Bold.woff2") format("woff2"), | |
| 44 | + | url("/static/fonts/Lato-Bold.ttf") format("truetype"); | |
| 40 | 45 | font-weight: bold; | |
| 41 | 46 | font-display: swap; | |
| 42 | 47 | } |
Binary file
Binary file
Binary file
Binary file
Binary file
| @@ -1,19 +1,0 @@ | |||
| 1 | - | # One-shot: refresh the testnot.work staging mirror from the latest prod backup. | |
| 2 | - | # Paired with mnw-testnot-refresh.timer for daily execution. | |
| 3 | - | # | |
| 4 | - | # Runs after sandod-backup-fetch so it uses a fresh dump. Needs root on fw13: | |
| 5 | - | # reads /srv/sando/backups (sando-owned) and uses Tailscale SSH (node identity) | |
| 6 | - | # to reach testnot as root. | |
| 7 | - | # | |
| 8 | - | # Place at /etc/systemd/system/mnw-testnot-refresh.service on the Sando host. | |
| 9 | - | ||
| 10 | - | [Unit] | |
| 11 | - | Description=MNW: refresh testnot staging mirror from prod backup | |
| 12 | - | After=sandod-backup-fetch.service network-online.target | |
| 13 | - | Wants=network-online.target | |
| 14 | - | ||
| 15 | - | [Service] | |
| 16 | - | Type=oneshot | |
| 17 | - | ExecStart=/usr/local/bin/mnw-testnot-refresh.sh | |
| 18 | - | # A failed refresh leaves testnot on its previous data + the app restarted; | |
| 19 | - | # the next daily cycle retries. Don't hammer. |
| @@ -1,81 +1,0 @@ | |||
| 1 | - | #!/usr/bin/env bash | |
| 2 | - | # Refresh the testnot.work staging mirror from the latest production backup. | |
| 3 | - | # | |
| 4 | - | # testnot is a read-only mirror of prod, gated app-side to Fan+/creator accounts | |
| 5 | - | # (ACCESS_GATE). This job reloads its database from the prod backup that | |
| 6 | - | # sandod-backup-fetch already pulls to fw13, so the mirror tracks live ~daily. | |
| 7 | - | # | |
| 8 | - | # Runs on fw13 (the Sando host, where the backup lives and which has tailnet | |
| 9 | - | # root on testnot via Tailscale SSH). The restore runs as the postgres | |
| 10 | - | # superuser on testnot — streamed over Tailscale SSH — so extension/owner lines | |
| 11 | - | # in the dump apply cleanly without granting the app role superuser. The app | |
| 12 | - | # applies any newer migrations on the next boot (MNW migrates on startup), so a | |
| 13 | - | # prod dump a few migrations behind the deployed binary self-heals on restart. | |
| 14 | - | # | |
| 15 | - | # Idempotent and safe to re-run: it stops the app, resets the schema, restores, | |
| 16 | - | # and starts the app. testnot holds no durable state of its own (it's a mirror), | |
| 17 | - | # so a wiped/refreshed DB each run is the intended behavior. | |
| 18 | - | set -euo pipefail | |
| 19 | - | ||
| 20 | - | BACKUP="${TESTNOT_BACKUP:-/srv/sando/backups/latest.sql.gz}" | |
| 21 | - | SSH_TARGET="${TESTNOT_SSH:-root@testnot}" | |
| 22 | - | DB="${TESTNOT_DB:-makenotwork}" | |
| 23 | - | SERVICE="makenotwork.service" | |
| 24 | - | # Soak-pause: while this flag file exists, the refresh is a no-op so a | |
| 25 | - | # multi-day soak's data + feature state stay stable. Pause/resume: | |
| 26 | - | # touch /srv/sando/testnot-refresh.paused # pause | |
| 27 | - | # rm /srv/sando/testnot-refresh.paused # resume | |
| 28 | - | PAUSE_FLAG="${TESTNOT_REFRESH_PAUSE:-/srv/sando/testnot-refresh.paused}" | |
| 29 | - | ||
| 30 | - | log() { echo "[$(date -u +%H:%M:%S)] $*"; } | |
| 31 | - | ts_ssh() { tailscale ssh "$SSH_TARGET" "$@"; } | |
| 32 | - | ||
| 33 | - | if [ -e "$PAUSE_FLAG" ]; then | |
| 34 | - | log "refresh paused ($PAUSE_FLAG present) — skipping to keep the soak stable" | |
| 35 | - | exit 0 | |
| 36 | - | fi | |
| 37 | - | ||
| 38 | - | [ -r "$BACKUP" ] || { echo "backup not readable: $BACKUP" >&2; exit 1; } | |
| 39 | - | # Verify gzip integrity before we drop the staging schema — a backup truncated | |
| 40 | - | # after sandod fetched it (disk-fill, partial copy) would otherwise feed a corrupt | |
| 41 | - | # stream into the restore. Matches the daemon's backup.rs verify_backup gzip -t. | |
| 42 | - | gzip -t "$BACKUP" || { echo "backup failed gzip integrity check: $BACKUP" >&2; exit 1; } | |
| 43 | - | log "backup: $BACKUP ($(stat -c %s "$BACKUP") bytes, gzip ok)" | |
| 44 | - | ||
| 45 | - | log "stopping $SERVICE on testnot" | |
| 46 | - | ts_ssh "systemctl stop $SERVICE" | |
| 47 | - | ||
| 48 | - | # Drop every non-system schema (mirrors sandod reset_scratch — migrations create | |
| 49 | - | # custom schemas like tower_sessions that survive DROP SCHEMA public CASCADE). | |
| 50 | - | # Recreate public OWNED BY the app role: on PG15+ a postgres-owned public grants | |
| 51 | - | # no CREATE to other roles, so boot migrations would fail with "no schema has | |
| 52 | - | # been selected to create in" (same gotcha as the sando scratch DB). | |
| 53 | - | log "resetting schema" | |
| 54 | - | ts_ssh "sudo -u postgres psql -v ON_ERROR_STOP=1 -d $DB" <<SQL | |
| 55 | - | DO \$\$ | |
| 56 | - | DECLARE s text; | |
| 57 | - | BEGIN | |
| 58 | - | FOR s IN | |
| 59 | - | SELECT nspname FROM pg_namespace | |
| 60 | - | WHERE nspname NOT LIKE 'pg_%' AND nspname <> 'information_schema' | |
| 61 | - | LOOP | |
| 62 | - | EXECUTE format('DROP SCHEMA IF EXISTS %I CASCADE', s); | |
| 63 | - | END LOOP; | |
| 64 | - | EXECUTE 'CREATE SCHEMA public AUTHORIZATION $DB'; | |
| 65 | - | END \$\$; | |
| 66 | - | SQL | |
| 67 | - | ||
| 68 | - | log "restoring prod dump" | |
| 69 | - | gunzip -c "$BACKUP" | ts_ssh "sudo -u postgres psql -q -v ON_ERROR_STOP=1 -d $DB" >/dev/null | |
| 70 | - | ||
| 71 | - | log "starting $SERVICE (applies any newer migrations on boot)" | |
| 72 | - | ts_ssh "systemctl start $SERVICE" | |
| 73 | - | ||
| 74 | - | # Boot smoke: the app must come back healthy after migrating. | |
| 75 | - | for i in $(seq 1 20); do | |
| 76 | - | code=$(ts_ssh "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/health" || echo 000) | |
| 77 | - | [ "$code" = "200" ] && { log "health OK"; exit 0; } | |
| 78 | - | sleep 3 | |
| 79 | - | done | |
| 80 | - | echo "testnot did not return healthy after refresh" >&2 | |
| 81 | - | exit 1 |
| @@ -1,17 +1,0 @@ | |||
| 1 | - | # Daily trigger for the testnot mirror refresh. sandod-backup-fetch runs at | |
| 2 | - | # 04:00 UTC; we refresh at 05:00 UTC to leave headroom for the fetch to land. | |
| 3 | - | # | |
| 4 | - | # Place at /etc/systemd/system/mnw-testnot-refresh.timer on the Sando host. | |
| 5 | - | # Enable: systemctl enable --now mnw-testnot-refresh.timer | |
| 6 | - | ||
| 7 | - | [Unit] | |
| 8 | - | Description=MNW: daily testnot staging-mirror refresh | |
| 9 | - | ||
| 10 | - | [Timer] | |
| 11 | - | OnCalendar=*-*-* 05:00:00 UTC | |
| 12 | - | # If the box was off when the timer fired, run on next boot. | |
| 13 | - | Persistent=true | |
| 14 | - | Unit=mnw-testnot-refresh.service | |
| 15 | - | ||
| 16 | - | [Install] | |
| 17 | - | WantedBy=timers.target |