Changelog¶
This page is generated from CHANGELOG.md in the repository. Pre-releases look like 0.3.0-beta.1; development builds are 0.3.0-dev.N. For how to move between versions, see Upgrading.
All notable changes to Ribbon are recorded here. The format follows Keep a Changelog and the project uses Semantic Versioning (pre-releases look like 0.2.0-beta.1).
[Unreleased]¶
Added¶
- Documentation site at https://ribbon.thepizza.tech (MkDocs Material, built from
docs/and published to GitHub Pages by the new Docs workflow): getting started, a full configuration reference, a guide to securing your install, features, backups and restore, upgrading, troubleshooting and contributing. The existing docs pages are part of it.
Changed¶
- The README is rewritten with screenshots (light and dark, desktop and phone), a quick start for the
devimage tag and a short configuration table; the detail now lives on the docs site.
[0.3.0-dev.2] - 2026-10-25¶
Development build. Adds the Welcome setup and the result of a full security review (docs/SECURITY-AUDIT.md).
Changed¶
- Onboarding is split in two. The first visit only creates the owner account. Right after the first sign-in a full-page Welcome setup asks for the family name and family members (name and role), then opens the empty Overview and the guided tour. Progress is saved on the server so it resumes if abandoned, and the server holds the rest of the API closed (
409 welcome_setup_required) until it is done. Existing installs with data count as complete, members never see it, and sample-data development mode skips it.POST /api/setupstill acceptsfamilyNameandpeoplefor scripts. - Password hashing is stronger (scrypt N=2^16, r=8, p=2). Existing hashes keep working and are upgraded on the owner's next sign-in.
- Sign-in lockout counts misses per account and address, per account from anywhere, and per address across accounts, so rotating or forging
X-Forwarded-Forno longer dodges it. Passkey sign-in has its own counters and no longer shares one global lockout. - Passkeys now require user verification (PIN, fingerprint or face).
docker-compose.ymldrops all Linux capabilities and setsno-new-privileges. GitHub Actions use read-only tokens by default, job-level write permissions and SHA-pinned actions; Dependabot is enabled.- A Secret Santa organiser can no longer switch peeking on after the names are drawn (turn it on before drawing).
Added¶
ALLOW_PUBLIC_SETUP. Heads-up: with noSETUP_CODE, the first owner can now only be created from your home network (the setup page says so). If your server is reachable from the internet and you have not created the owner yet, setSETUP_CODEfirst.- Setup-code guesses are rate limited and compared in constant time.
.env.exampleis now actually tracked in git.
Fixed (security)¶
- A request path with broken percent-encoding (such as
/%E0%A4%A) left the connection hanging forever; it now answers 400. - Chunked uploads without
Content-Lengthare cut off at the 5 MB (256 MB for restore) cap while reading instead of after buffering. - A restore file with no owner login is refused (it would have locked everyone out and re-opened first-run setup). Uploaded databases are opened with
trusted_schema=OFF, and backup files and folder are owner-only on disk. - The person who set up Ribbon can no longer be demoted or removed by another owner.
- Wishlist links imported from CSV follow the same http(s)-only rule as the form; the client also checks before rendering a link.
- A person's name with a bare carriage return or control character can no longer inject lines into the calendar feed.
- Removing yourself from the ledger no longer reveals whether a surprise is planned for you.
- Single sign-on: the provider's endpoints must be https (or private-network http), redirects are refused when talking to the provider, and starting SSO is rate limited.
- Ask: per-person rate limit, Origin and Welcome-setup checks, and the ledger is passed to the model as delimited untrusted data.
- Passkey ids with broken percent-encoding no longer cause a 500; the open passkey-challenge table is capped and its options endpoint is rate limited.
Cross-Origin-Resource-Policy: same-originon every response andCache-Control: no-cacheon the HTML shell.- Dependencies updated (
npm audit: 0 known vulnerabilities).
[0.3.0-dev.1] - 2026-10-25¶
Development build. Not released: main stays the development branch. Details of each feature: docs/FEATURES.md.
Added¶
- Wishlists per person with surprise-safe reserve and purchased marks (hidden from the list's owner by the server), and "convert to gift".
- Budgets per person or occasion, upcoming dates (birthdays, anniversaries, recurring occasions) and a secret-link calendar feed (.ics) with reminders.
- Scheduled SQLite backups (
BACKUP_CRON,BACKUP_KEEP) with download, back-up-now and restore. - CSV import and export with a template, column mapping and a preview.
- Households as separate ledgers, with sharing between households (invite, choose shared people, unlink) and server-side visibility checks.
- Secret Santa across linked households, with exclusions and a derangement draw.
- Single sign-on (OIDC with PKCE) and passkeys.
- Settings page (general, account, data, sharing, help).
- PWA: manifest, icons, service worker, offline page.
- Guided tour (driver.js, seven skippable steps), replayable from Settings → Help. State is saved per login via
POST /api/me/tour. Off by default in sample-data development mode;TOUR_ALWAYS=trueforces it. - A
ghcr.io/thepizzatech/ribbon:devimage is published from every push tomain.
Changed¶
- Version bumped to 0.3.0-dev.1.
- A production image never contains sample data; first run asks for the family name, members and roles.
Breaking¶
- The bundled Caddy proxy is gone.
docker-compose.prod.yml,deploy/caddy-entrypoint.shand theSITE_ADDRESS,HTTP_PORT,HTTPS_PORTandTLS_MODEsettings no longer exist, and Ribbon no longer redirects HTTP to HTTPS itself. Ribbon listens on plain HTTP, port 8080, anddocker-compose.ymlpublishes${PORT:-8080}:8080. Put your own HTTPS proxy in front (seedocs/REVERSE-PROXY.md), or use the optionaldocker-compose.caddy.ymloverlay. - The default
docker-compose.ymlnow pullsghcr.io/thepizzatech/ribboninstead of building. Build from source withdocker-compose.build.yml; the old development compose isdocker-compose.dev.yml. Theribbon_datavolume name is unchanged, so data carries over. ENFORCE_HTTPSis deprecated (logs a warning). It now means "refuse password sign-in over plain HTTP from everywhere".- If you ran the old production compose, update your reverse-proxy/bookmarks to the new address, and remove any override that published the app port next to Caddy.
Added (HTTPS and proxies)¶
PUBLIC_URLandTRUSTED_PROXIES.X-Forwarded-Proto,-Hostand-Forare honoured only from trusted peers (default: loopback and private ranges, including Tailscale's100.64/10); previously any client could set them.- The
Securecookie flag, the__Host-prefix and HSTS follow the effective scheme. HSTS is six months withoutincludeSubDomains;HSTS=offdisables it. Plain-HTTP LAN sign-in works. - Password sign-in over plain HTTP from public addresses is refused unless
ALLOW_INSECURE_LOGIN=true. A "Connection not secure" notice appears on the sign-in page and in Settings. docs/REVERSE-PROXY.mdwith recipes for Nginx Proxy Manager, Caddy, Traefik, Tailscale and Cloudflare Tunnel.
[0.2.0-dev.1] - 2026-10-24¶
First development build of 0.2. Not released yet: main is the development branch (see docs/RELEASING.md).
Breaking¶
APP_PASSCODEis removed, along with the shared-passcode screen. Ribbon now has real accounts. After upgrading, the first visit asks you to create the owner login (your existing ledger is kept). The variable is ignored and can be deleted from.env.docker-compose.prod.ymlnow runs Caddy in front of the app and the app no longer publishes port 8080. Openhttps://<SITE_ADDRESS>instead ofhttp://<server>:8080. If your own override file publishes the app's port, remove that.- Production sets
ENFORCE_HTTPS=true: plain HTTP is redirected and cookies areSecure.
Added¶
- New look: a "Margin"-style dashboard. Overview with a "Gifts this year" hero, a Needs-you list, a 12-month chart, a breakdown by occasion or person, and an insight card tied to Ask. Sortable Ledger table with status dots, People grid with a person detail view, Ask restyled. Full-screen on phones with a bottom nav.
- Dark theme: follows your device first; the toggle is remembered.
- First-run setup instead of sample data: family name, family members (name, relationship, in your household or not), then the owner login. Lands on an empty Overview with "Add your first gift".
SEED_SAMPLE_DATA(default on in development, off in production and in the image).- Accounts: username or email plus password (scrypt), server-side sessions, CSRF protection, Origin checks, login lockout, sign out, change password. Owners add and remove family logins (owner or member) in Settings.
- HTTPS:
ENFORCE_HTTPSredirect, HSTS, Secure cookies, CSP and other security headers. A Caddy proxy in the production compose, with Let's Encrypt for real domains and a local CA for LAN addresses.HTTP_PORTandHTTPS_PORTfor hosts where 80 and 443 are taken. - People have a relationship (wife, son, aunt, ...). Existing people are migrated by guessing from their old role text, defaulting to "other".
- Version shown in Settings → About, the sidebar footer and
/api/health(with the short commit when built withGIT_COMMIT). - Optional
SETUP_CODEto protect creation of the first owner login. LICENSE(MIT),SECURITY.md,CONTRIBUTING.md, issue templates and the release workflow.
Fixed¶
- Caddy: set
default_sniso HTTPS works when the site is opened by IP address behind Docker port mapping.
Changed¶
- A ledger saved by an older browser-only version is now offered for import once after sign-in, instead of being copied automatically. It is only offered when the server has no gifts of its own yet (or only the sample household).
- Database migration 2 (additive):
usersandsessionstables andpeople.relationship. Existing data is untouched.
[0.1.0] - 2026-10-23¶
Added¶
- SQLite storage on a Docker volume with a JSON API, import and export, and
/api/health. - Docker image (non-root, health check), compose files, README and CI.
- Optional shared passcode (
APP_PASSCODE).