1.3.3 put the dblink job into the SQL but still ran psql against
_supabase, where pg_cron refuses the extension; the psql session now runs
in postgres, the only database pg_cron accepts in this image
version 1.3.4
the supabase image pins cron.database_name to postgres, so pg_cron refuses
jobs scheduled from _supabase, where the log tables live; 1.3.2's upgrade
failed on the first live run with 'can only create extension in database
postgres'. The job now runs in postgres and deletes the _analytics
log_events_* rows in _supabase over a local dblink connection, which needs
no password because the image trusts local connections for supabase_admin.
version 1.3.3
- every instance gets a pg_cron job (set up on create, upgrade and resume)
that deletes _analytics.log_events_* rows older than 2 days and runs the
first cleanup right away; Logflare never deletes stored logs, and instance
3's 2 GB db image died 100% full of them on 2026-10-06, after which
analytics 500'd every delivery and vector was OOM-killed by its
undeliverable backlog every few minutes
- vector's memory limit back to 512 MiB, the ceiling the production
supabase charts carry; the retention job bounds its backlog, so 1024 MiB
is not needed anymore
- version 1.3.2
- vector reads the log files of every pod on the node, so its memory need follows the node's log volume. At
256 MiB it was killed for running out of memory 122 times on instance 1 and used 89% on instance 2.
The limit is now 512 MiB (request unchanged at 128 MiB) for new instances; the total limit per instance
goes from 5.625 GiB to 5.875 GiB, requests stay at 1.875 GiB.
- README memory table and the test for the totals updated
- version 1.1.1 -> 1.1.2
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- install.sh said "Installed supaspin supaspin 1.1.0." because --version now includes the name; it now says
"Installed supaspin 1.1.1."
- CLAUDE.md: tells AI agents to read Igor's global rules first, and states the versioning rule (number in VERSION,
code and README together, semantic versioning, major bumps only with Igor's yes, a git tag vX.Y.Z after every merge)
- version 1.1.0 -> 1.1.1
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- list and tunnel print plain-language tunnel instructions for every instance: keep it open, run it in the
background, close it, with a notice that background/close work on Mac and Linux only, not Windows
- push-env N TARGET puts an instance's .env values into another .env file, on this server or over SSH (Mac, Linux,
Windows): existing keys are replaced, missing keys added, commented-out lines ignored, every other line kept.
A temporary copy of the target is compared after writing and put back on any mismatch. --dry-run shows the
changes without writing. SSH failures are explained with how to set SSH up.
- VERSION file (1.1.0), version line in the README, `--version` prints "supaspin 1.1.0"; a test keeps the file, the
code constant and the README in step
- remove an unused parameter of run() and an unreachable second help branch in main()
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a terminal app that creates, lists, shows and deletes numbered Supabase
instances on a single-node microk8s server, for testing and staging copies of
any app. Nothing in it is specific to one app.
- supaspin: single-file Python app (menu and commands: create, list, show,
env, tunnel, delete, mail, setup). Instance N gets namespace supaspin-N,
hostname slot N, Postgres on <LAN IP>:544N and Studio on <LAN IP>:300N.
Lowest free number is reused; a refused create says why.
- Disk: fixed-size ext4 image files, loop-mounted from /etc/fstab. db 2 GB,
storage 1 GB, functions/snippets/deno/pgsodium 256 MB each. imgproxy mounts
the storage volume (the chart's own imgproxy volume cannot see uploads, so
image resizing failed). Empty mount points are made read-only until mounted
so a pod started early after a reboot cannot initialise a database there.
- Memory: limits 5.625 GiB, requests 1.875 GiB per instance, all 12 services.
Half of a production setup, except analytics (768 MiB) and realtime
(384 MiB), which were killed for running out of memory at half of it.
- Priority class supaspin-low (-100, never preempts) on every instance pod.
- Public HTTPS through the existing nginx ingress with Let's Encrypt. The
Studio and pg-meta routes are cut out of the Kong gateway config by a
post-renderer, which also pins the db and studio pods to fixed host ports.
- Certificates: delete keeps the TLS secret (with its cert-manager issuer
annotations) in namespace supaspin-certs and create restores it, so
create/delete cycles do not hit Let's Encrypt's 5-per-week limit.
- Secrets generated per instance: JWT secret, anon and service keys, Postgres
and Studio passwords, realtime/meta/logflare keys. The rendered values file
is removed after install; secrets are never written through kubectl apply.
- Instance .env (mode 600) with the usual Supabase variable names, plus an SSH
tunnel command and DATABASE_URL help.
- Delete is idempotent and finds the real mounts instead of trusting a list,
so half-created and older instances clean up completely. A failed create
offers to run it.
- Mail settings: saved defaults changeable from the menu; create asks to use
them or enter different ones for that instance.
- install.sh: installs the app; accepts a Gitea token or a local checkout
because git.didgibot.com requires sign-in even for public repositories.
uninstall.sh: removes the app and, after confirmation, every instance.
- tests: 30 unittest cases (numbering, ports, JWT signing, values, .env,
fstab handling, post-renderer, certificate secret handling).
- README: install, first-run setup, menu, tunnel, troubleshooting, uninstall.
Pinned chart: supabase-community/supabase-kubernetes 0.8.0 (Postgres 17.6.1.136).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>