Your band’s business stays in the band.
Set lists, fees, phone numbers and contracts belong to the people who play. Here’s what we promise, how each promise is enforced, and where the limits are.
Four promises.
The database checks every read
Your band’s songs, shows, files and money are readable by its members and no one else. The rule is enforced by the database on every request, not by the app hiding screens.
Nothing else of the band’s
A fill-in player is not a member. They see the show they’re playing, its set and its files, and who booked them. Everything else is refused.
Two days after the show
The links you send venues and crew work without an account, so they don’t stay open: day sheets, advance forms and door lists close two days after the show.
Enforced on the server
Turn on an authenticator app and a password alone can’t read or change anything in your bands, even by going around the app.
How it’s enforced.
Wrangl has no server of its own between the app and the database. The app talks to Postgres (hosted by Supabase) directly, so the database’s own rules are the security model. Open any section for the detail.
Row-level security on every table
The database decides who reads and writes each row.
Postgres row-level security is on for every table. Each policy calls one of a few shared functions (is this person a member of the band, do they hold this permission) so a membership check is written once and used everywhere.
Some writes go through database functions that run with elevated rights. Each of those re-checks the caller’s permission in its own body, and refuses a signed-out caller before comparing anything, so a missing identity can’t slip through a comparison.
A row can’t be moved into another band: a task, piece of gear or merch line keeps the band it was made in, and a file can only be linked from inside its own band’s storage folder.
Roles and permissions
Seven permissions, off until granted, checked by the database.
Each band grants seven permissions per role: songs, events, files, tasks, finances, band settings and the shared-bill chat. They are off until granted, and the owner always holds all of them.
The finances permission gates reading the books, not only changing them: a member without it gets no ledger rows back from the database.
A band whose subscription has lapsed becomes read-only through the same check, so nothing is deleted when a band stops paying.
Members join only through an invitation or a join link. There is no way for a client to add itself to a band directly.
Fill-in players
Refused by default; each thing they see is a named exception.
A sub is booked onto one show and is not a band member, so every rule that admits members refuses them. Each thing a sub may read is a separate, explicit exception: that show, its set, the songs and files shared with it, its field labels, and the profile of whoever booked them.
Signing in
Two-step enforced in Postgres; email links carry a code, not a session.
- Two-step sign-in is enforced in the database. For an account with an authenticator app, every membership and permission check also requires the second step, so a stolen password reads and writes nothing of any band. Every server function that acts for a signed-in person asks the same question first.
- Email links carry a one-time code, never a session. A sign-in, confirmation or reset link takes you to the app with a code it checks. A link for a different account than the one you’re signed in as asks before switching. A session handed over in a link is never accepted.
- Google and Apple sign-in use PKCE, so the code they return can only be spent by the browser that asked for it.
- An invitation is matched on its email address, and only an account that has confirmed that address can see or accept it.
- Passwords are at least 8 characters and are handled by Supabase Auth; we never see them. Sign-up, sign-in and password reset support a Cloudflare Turnstile check, verified by the sign-in server rather than the app.
Signed-out visitors and shared links
An allow-list of what a visitor can call, and links that expire.
Someone who isn’t signed in can call only an allow-list of database functions: the ones behind the public band page and the links bands send out. Every new function is closed to them unless it is added on purpose, and a test fails if the list changes.
For those links, the token in the address is the credential, and each one closes:
- Day sheet, advance form, an act’s bill link and the door list: two days after the show.
- A contract: a month after it’s signed, or a month after the show if it isn’t.
- Join and answer links: their own expiry date.
- A personal calendar feed doesn’t expire, since a calendar app subscribes once, but it stops working when its member leaves the band.
When one of these links is pasted into a chat, its preview shows a label and nothing behind the token.
Files and storage
Private buckets, short-lived links, each band in its own folder.
- Files, receipts, contracts, voice memos and photos are kept in private storage. The only public files are band logos and press-kit photos, which a band publishes on purpose.
- A private file opens through a signed link that expires within an hour.
- Every stored path starts with its band’s id, and the storage rules refuse an upload outside a band’s own folder.
- Profile pictures and logos accept only raster images, not SVG, which a browser can run as a page.
- A deleted file waits in the band’s trash for 30 days, then is removed for good.
What the app can’t write
Billing status, admin role and email address are off limits to clients.
Clients can update only named columns. A band’s owner can edit its name and public page but not its subscription status; only Stripe’s verified webhook marks a band paid. A person can edit their profile but not their admin role or email address, which follows the address they sign in with.
API keys and webhooks
Hashed keys, a read-only API, signed webhooks that can’t reach private networks.
- An API key is shown once. We keep only its SHA-256 hash and a short prefix to tell keys apart.
- The API is read-only and returns a fixed shape per record: no fees, books, contacts, files or email addresses. It sends no CORS headers, so a key can’t be used from a web page.
- A key or webhook acts for the person who made it, and stops when they lose the band-settings permission. Making one tells the band’s other members who hold that permission.
- Webhooks are signed with HMAC-SHA256 (
Wrangl-Signature: t=…,v1=…). A rotated secret keeps signing alongside the new one for 24 hours. - Webhooks go only to
httpsaddresses on public hosts. The sender resolves the address itself, refuses private networks, connects to the address it checked, and follows no redirects.
Third parties and telemetry
Keys stay on the server; error reports are scrubbed.
- Keys for paid services (maps, receipt reading, email, payments) live only on the server. Usage is counted per person, and if the limit can’t be checked the call is refused rather than let through.
- Error reports and their breadcrumbs are scrubbed before they leave the device: email addresses, the token in a link, session and sign-in secrets, and search text are removed.
- Usage analytics never include the content itself, and you can turn them off in Account settings.
- Every service that processes data is named in the Privacy Policy.
On the web
HTTPS everywhere, no framing, strict headers.
Every page is served over HTTPS with HSTS, nosniff, a strict referrer policy and a permissions policy. The app refuses to be framed by other sites, except the embed widget a band places on its own site. Links people type into a profile or event open only if they’re web links.
How we test it
The rules are tested against a real database before every release.
More than 180 end-to-end tests drive the real app against a real local database, with no mocking of sign-in or access rules. Many sign in as the wrong person on purpose: an outsider who shares no band, a sub, a member without a permission, a signed-out visitor. Each change runs the full suite, and nothing ships unless it passes; database changes are rehearsed on a staging project before production.
What we don’t claim.
“Who can see this file” is a display choice, not a lock
A band can show a file or event to some roles only. That tidies each person’s screens, but every member of the band can still read it. Keep anything a bandmate must not see out of the band.
A link is only as private as where you send it
Anyone holding an open day sheet, advance or door-list link can read it until it closes. Send them to the people they’re for.
What you add to a band stays with the band
If you leave, what you contributed stays in the band’s records for its other members. You can delete your account from Account settings once you no longer own a band.
No system is perfect
Data travels over HTTPS and is kept with the providers the Privacy Policy names. Nothing on this page means nothing can ever go wrong; it’s what we do to make it unlikely.
Tell us first.
If you think you’ve found a security problem, email security@wrangl.band with what you saw and how to repeat it. Please test only with accounts and bands of your own.
Bring the band. Keep it yours.
Free for you alone, forever. Invite the band when you’re ready.
Start free