Changelog
Every change to this belfry: the code it runs and what was changed on the server, with who started each change. Settings are named, never their values.
4 November 2026
server Homepage published from site
website Website published from the server by Xavier via the Belfry website agent.
code Merge branch 'belfry-console' into belfry-sh
e84996b
code belfry apply on little disk: rebuild an image only when its sources changed
9a3a61a
code Blossom accepts web files (HTML, CSS, JS, JSON, fonts, …) for nsites, kept 5 years
3cbe3f6
server Settings changed: COMMUNITY_NAME, COMPANY_NAME, MAIL_FROM, ADMIN_NETS, CUSTODY_SEED_DIR, HOMEPAGE
code belfry apply: with little disk, build one image at a time and empty the build cache after each
2e9d822
code install.sh: new belfries show their own website (HOMEPAGE=nsite), a placeholder until published
8833685
code belfry.<domain>: overview, status, members by e-mail, website approvals; placeholder homepage
b894e6a
code DEPLOY: the git server is prebuilt too
9415cc7
code Prebuilt images: the git server (ngit-grasp) too
6e988ab
code belfry: record changes in the changelog, belfry homepage publish|status
9817181
code Community pages every belfry serves: /proposals, /monitor, /changelog
97cd8ac
code Community homepage on the apex: start page, a proxy to the website, or an nsite (NIP-5A)
c3302ba
code NEXT_STEPS §3zu: git server deployed on belfry.tofauti.net, smoke green
4f1e29c
code Prebuilt images on GHCR: the signer, proxy, groups relay and onboarding service
a09a85c
code Git server for agents: ngit-grasp at git.<domain>, members are the active passes
af98fe8
code install.sh: say where it stopped, quieter apt and Docker install; disk sizes from a real run
c8aafd4
code install.sh: Caddy on 80/443 by default, nginx only with --nginx
c4fdee2
code One-command install: curl -fsSL https://belfry.sh/install.sh | sudo bash
51a6aa9
1 November 2026
code Fewer onboarding screens for outside apps: Keycast 0021, Village Notes signs in by itself
f0c1642
code Merge github/main: PR #1 (belfry-event allows any kind)
e7fd146
code Merge PR #1: Keycast policy belfry-event: allow any kind
ea4a407
code Signed in on the way back to the app: the welcome page signs in and ends at return_url
cb934c4
code test_nip46check: ruff format (the padding table one tuple per line)
f1fb532
code Pass order API: payment_url straight to Mollie's checkout, return_url back to the app
528de41
code Keycast policy belfry-event: allow any kind
2001790
code Invite codes from an app: /api/invites without an e-mail, Village Notes "Invite someone"
eb3743d
code Sign-out back to the app, no "Stay signed in?" step, branded Keycast pages for outside apps
ef04e28
31 October 2026
code feat: add signin with email
48e10ba
code Internal invoices numbered as orders (ORD/) when another organisation invoices the tickets
8c6dca9
code Plan snapshot note: rev 90, tickets invoiced by XL Collective (§3zq)
da41674
code Tickets booked at the seller's Odoo: invoice, payment and credit note over JSON-2
925fc47
code Village notes: an example app on a Belfry (invite, bunker sign-in, tokens, notes)
59d71c0
30 October 2026
code Agent command: one action per call through the holder's bunker (me, invite, invites, status, revoke)
d8c981b
code COMMUNITY_NAME quoted in .env.example: bootstrap sources .env, and the unquoted space broke it
88c73b6
code E-mail code for an app's own key: /api/email-code binds the key to the address in Odoo
9231001
code Bootstrap accepts Stripe restricted keys (rk_test_, rk_live_); DEPLOY.md lists their permissions
1a04fd5
code Apps connect to a Belfry: /.well-known/belfry.json, /api/me, CORS, steward skill
87865ce
code NEXT_STEPS §3zn: deployed to both servers, smoke 220 ok on each
041d100
code Blossom gate keeps the public proxy's X-Forwarded-Proto: blob URLs are https again
a540371
code Smoke 6w: the smoke steward leaves the stewards group again
3737762
code Agents act for a pass holder through a bunker; stewards get a free pass
847e0a0
28 October 2026
code Fresh install on a server: bootstrap waits for Issuer2's own metadata; ADMIN_NETS before bootstrap
85b5051
code Short names for the participant apps: <domain>/chat and others redirect to their hosts
ba5a58f
code Pass API and agent skill: an agent orders a pass from an invite on a visitor's behalf
e2a0ce6
27 October 2026
code Encrypted OpenID4VP responses (direct_post.jwt) for the door and pass sign-in: Talao presents the pass
4c90785
code Sign-in code next to the magic link: a 6-digit code in the same mail, for devices without the mailbox
68ee49e
code CLAUDE.md: refer to NEXT_STEPS, the slice contract and the plan snapshot by path, not as imports
fbac39c
code NEXT_STEPS: Belfry registered at the EUDI Launchpad registrar
5c72549
code NEXT_STEPS: EUDI registrar section is §3zk (§3zj is the sign-in code)
aa221e0
code EUDI reference wallet: signed issuer metadata, registrar certificates for issuer and verifier
f34c57c
26 October 2026
code Programme: a Shifts tab for volunteers and stewards
851868f
code Groups: Flotilla on a NIP-29 relay (zooid); every participant can open a group
36e89e1
code Volunteers: a two-week pass earned with three shifts; shifts in Odoo, a personal shift page, steward pages
eb36064
code Applications: <domain>/apply, answered with an invite or a friendly no on the steward pages
a7155b2
code Sign-up journey from the user test: invites wait for payment, VAT, real invoices, welcome page, mail to apps
028aec9
code Photos: no more black uploads
f96efbd
code Sign-in: the account page's button goes straight to the e-mail sign-in; no avatars
755ff5e
code Programme review follow-ups: calendar filters under the relay's cap, retries
36ae07b
code Programme: page past the relay's cap, word search, titles only for bookings
9f7ad55
code NEXT_STEPS: polls on Nostr deployed
52733d9
code Polls on Nostr: public relay hint, smoke checks, docs
ee55af5
code Polls on Nostr: an announcement when a poll opens, the result when it closes
a0f91af
code NEXT_STEPS: programme app complete and deployed
d2f26a5
code Programme app: phone navigation, search, reminders, offline, polls per session
58085bd
code NEXT_STEPS: programme app deployed on the test VM
4eebd3e
code Programme app: announce, edit and cancel your own session
f390a2f
25 October 2026
code Programme app: what is on now, RSVPs, comments and photos per session
38c531b
code Calendar on phones: square mark, date on one line, day view first
ec88ae9
code Wallet: send to someone from the directory, receive by QR, clearer history
36349e3
code Wallet: the pass's tokens arrive on sign-in; no Lightning address settings
07b0587
code Programme and room bookings as public calendar events
6a4a1fa
code Invoice page: no salesperson for participants (the onboarding service's user)
82ff200
code Invoice and payment pages link to Belfry, not to Odoo
571d088
code Branded error pages: proxy, onboarding service, Odoo
68262dd
code Share preview: Open Source Village instead of "Odoo" for invite links
056d6da
code zerotier.sh dns: no forwarded AAAA for the domain (the public IPv6 would bypass ZeroTier)
dce21e8
code Admin network DNS: dnsmasq on the VM's ZeroTier address
9eb35ea
code Wallet: the participant's own signer, seed and nutzap key in an encrypted backup on the relay
f039d2a
code Join with an own Nostr key: proof on the invite page, keyless signer account at activation
28ce1a7
code NEXT_STEPS: iDEAL and Bancontact are enabled in the Mollie account
cdeeb9f
code NEXT_STEPS: the verifier kept a stale status list beyond its TTL
2d707da
code Status list: indexes above the highest in use stay valid
6c1f8af
code Smoke: follow the start page's forward; the test-run notice on Odoo's invite page; tester notes: the November test window
16cd2fc
code Start page at the apex, invites from participants, feedback page, test-run notice
0082ac4
code NEXT_STEPS: the user's open to-dos (Mollie methods and key, old backups, venue IPv4)
1cbd867
code NEXT_STEPS: the test VM's fresh install (Belgium, EUR, new keys)
3305775
code bootstrap: offer only the Mollie payment methods the Mollie account has enabled
5a7343f
code Fresh Odoo database in the company's country (BE, EUR); status list valid only for active passes
97047cd
code Blueprints: no placeholder fallback for client secrets
4ba88f2
code Secrets as files instead of environment variables; Docker hardening
9f4fc10
code Mollie: a pending refund revokes the pass; rate limits for the venue WiFi
eb5f277
code odoo.conf carries a PBKDF2 hash of the master password, not the password
2a046d4
code Default avatars from the key; Mollie next to Stripe with refunds and chargebacks
4a1849d
code Stripe from bootstrap: Odoo's provider from STRIPE_PUBLISHABLE_KEY and secrets/stripe_secret_key, both webhooks
24d6afe
code Reports and moderation: a Report link in the directory, market and photos, steward handling
3fe4edb
code Privacy notice, terms, refund policy, community rules, help on pass.<domain>; event-day runbook
028abc6
24 October 2026
code Sync workflow: actions/checkout@v5 (runs on Node.js 24; v4's Node.js 20 is deprecated)
0b73a07
code DEPLOY: reload the proxy after a Caddyfile change (the directory is mounted)
ea4a914
code Docs for readers new to the project: current state only, a docs index, the pass sign-in bridge
22dab0d
code Wallet: Geist from the image instead of Inter from Google Fonts (patch 0006)
da39c7f
code NEXT_STEPS 3x: hardening and the admin network; plan snapshot notes rev 75
3e7f13f
code zerotier.sh: ADMIN_NETS includes the VM's own public addresses
6092480
code chore: add github workflow
bb7391e
code Hardening: rate limits, per-account magic-link limit, CSP, non-root containers, split networks, no Mailpit in production, admin pages over ZeroTier only
bd9c9ec
code The pass on the phone without a wallet: /me shows a renewing QR, /check at the door
32f17f8
code Mobile, second pass: dashboard, header, wallet buttons, button rows (Keycast 0016, wallet 0005)
dcf13eb
code Mail sender: prod-env.sh keeps an existing MAIL_FROM; DEPLOY.md says it needs SPF
8805a6f
code What's new: recent activity across the apps in the directory (people.<domain>/#/activity)
2a56654
code Mobile: buttons fit phones with large text (Keycast patch 0015, Authentik brand CSS)
2c6d7fc
code Photos at photos.<domain> (services/village), tips in village tokens through the wallet
9071b7d
code Directory and marketplace (services/village), paid in village tokens through the wallet
ee4d155
code Plan: DIDs dropped (no did:webvh, no id.<domain>); identity is the Nostr key
0b80b8d
code Mocked hardware tokens until the YubiKey ceremony; rewrap keeps seed and backup key
6393159
code Nightly encrypted off-VM backups with a restore drill (infra/scripts/backup.sh)
bd1ecfd
code Recoverable participant keys from a custody seed under the stewards' YubiKeys (Keycast patch 0014)
ac6de5f
code Logout no longer ends on a blank page (Keycast patch 0013, OIDC_LOGOUT_URL)
0bf255c
code Vote: sign in with the participant's own signer (self-custody)
56865b5
code Self-custody: take over the Nostr key or move to one's own (Keycast patch 0012)
0da6010
code Village wallet at wallet.<domain>: keys from the Nostr key, nutzaps (Keycast patch 0011)
b23e218
code prod-env.sh: keep the ODOO_HOST_PREFIX already in .env
48caee5
code Anonymous polls at vote.<domain>: Semaphore, one vote per active pass
154496b
code Village tokens: Cashu mint without monetary value, 50 tokens per pass day at activation
980ae57
code Chat: Log out in the mobile menu (patch 0003)
116d9c3
code Open Source Village app bar in chat and calendar, home-screen icons, calendar logout
e35bcad
code Plan snapshot: logout decision (live doc rev 59)
660df33
code Logout ends the sign-in everywhere; friendly sign-in errors; pass landing page
ae3d63d
code Starter events for new participants: follow list and relay lists, so Coracle finds the profile
7a63689
code Keycast dashboard: Community apps cards linking to chat and calendar (patch 0009)
1c2aa45
23 October 2026
code Single sign-on for the apps: silent prompt=none sign-in, trusted clients, chat button
9d98be8
code Calendar: Sign in with Open Source Village, silent sign-in on load
988350b
code Community chat: Coracle at chat.<domain>, bunker sign-in, policy kinds for both apps
1f37b62
code Community calendar: Calendar by Form* at calendar.<domain>
dabf1b0
code smoke: decode the status list token with padding (base64 -d aborted step 11)
d244436
code NIP-46 for apps outside the network: public bunker relay, client check, clean restarts
9eb8b9b
code DIDroom: sign-in offers on the claim page, Issuer2's login at Authentik
376d0b3
code walt.id web wallet: anonymous pre-authorized codes, draft-13 token and credential requests
22f5e29
code Issuer metadata with authorization_servers for walt.id's wallet
9dfe736
code New setups serve Odoo at shop.<domain> instead of odoo.<domain>
4abf309
code Type metadata also at /.well-known/vct/vct/village-pass/v1 for walt.id's wallet
014658d
code Keycast fork: dark text on the accent, e-mail from the ID token, "Your pass" card
876b5d8
code Proxy: issuer metadata also at the appended well-known paths
67a4c41
code belfry_pass: legible pass rows, navbar logo, no portal chatter; company currency EUR
f77ec10
code Pass info for the community apps: GET /admin/partners/<id>/pass
5124eca
code Activation mail leaves at once; one activation per invoice
bd502df
code Brand files: CORS and cache headers, woff2 media type
bf37ea6
code Branding: Open Source Village, run by Belfry; dark theme, mobile first; shared brand/ folder
b9a96bb
code Steward pages: Belfry's own UI for stewards, Odoo as backend only
6e445e7
code belfry_pass: invite list failed with "Expected singleton" once there were several invites
908da84
code Review follow-ups: activation link while signed in, secrets off argv, template note
927954e
code Real-user test plan for the public deployment (docs/real-user-test.md)
d16f8e4
code Plan snapshot: passwordless magic-link login (live doc rev 49)
b664255
code Participant login by magic link: no passwords, one-time sign-in link at activation
5dc6415
code Notes: public test deployment live (belfry.tofauti.net), smoke green over TLS
e585152
code Deployment: Keycast uses the public HTTPS issuer behind the proxy; smoke admin calls inside the container
53d78b4
code Deployment run on Hetzner: secrets as files, public SANs, bootstrap behind the proxy
2ec7c7c
code Authentik: pin the seed brand as default so the account-setup links work behind a proxy
d25027e
code Proxy denies Keycast's dev inbox; smoke test runs against a public deployment; export check
50c3762
code Policy kinds: calendar (NIP-52), photos (NIP-68), proposals (NIP-88 and NIP-23), NIP-17 chat
f33ae66
code Hetzner: provisioning script, cloud-init and firewall for the Belfry VM
88a7f29
code Keycast fork: Belfry branding and key export for OIDC-only accounts; gated Blossom server
85cbe76
code Deployment preparation: Caddy reverse proxy overlay, public URLs, deployment guide
47dc03c
code Hardening: Odoo mail and privileges, issuer certificate pinning, signed verifier requests
374b7c3
code Phase 3: pass certificates, status list, door check and pass sign-in (local happy path)
96d7ba9
code Phase 2: participants get their Authentik login through a mailed account-setup link
eaea7c8
code Phase 2: Keycast fork with the login through Authentik
6d14e79
code Phase 2 start: community relay (rnostr) with a whitelist derived from Odoo
c658d55
22 October 2026
code onboarding: publish the kind-0 profile at activation
c97125f
code Build slice 1: Compose stack, Odoo belfry_pass module, onboarding service
d94d2bc
code Plan, verification spikes and build contract for slice 1
3501aad