On this page
The key property: one brand’s data can never be seen by another. Here’s how, plus the rest of the v0.1 design.
SignaUnit is in private development. Setup runs on sample data, and real franchisee data comes in only under a signed agreement.
Tenants: one wall per brand
Each franchisor is a tenant. Every piece of tenant data (units, owners, priorities, check-ins, notes, audits, imports) is stored with that tenant’s ID. There is one shared database with one shared structure, and the separation between tenants is enforced by the database itself.
Row-level security, in plain words
Most software keeps customers apart by remembering to add “only this customer’s data” to every query. If a developer forgets once, data can leak.
SignaUnit adds a second, independent lock. The database uses Postgres row-level security (RLS): a rule attached to every tenant table that says, in effect, “only return or change rows whose tenant ID matches the tenant of the current request.”
Here’s how it works on each request:
- You sign in. The API works out which tenant you’re acting in and checks your role and scope.
- At the start of the database transaction, the API tells the database “this request is for tenant X, user Y”.
- Every query in that transaction is filtered by the database to tenant X. Rows from other tenants are invisible. They aren’t returned, and they can’t be updated or deleted.
The application connects to the database as a restricted account that cannot switch these rules off. Database migrations and administrative jobs use a separate account. So even if the application code has a bug, the database still refuses to cross the tenant boundary.
Within a tenant, the API applies your role and scope. A franchise owner sees only their own franchisee’s units, and a region-scoped manager sees only their region. See Roles and permissions.
Cross-tenant leak tests in CI
Isolation is tested continuously, not assumed. Every pull request runs an RLS test suite in continuous integration. It signs in as each role in one test tenant and tries to read and write data belonging to another tenant. Every one of those attempts must fail. If any succeeds, the build fails and the change can’t be merged.
The same pipeline also runs type checks, unit tests, secret scanning, and a check that rejects binary media files in the repository.
Audit log
Every significant action is recorded in a per-tenant audit log: publishes, overrides, waivers, role changes, invites, verifications and support access. Each entry records who acted, what changed and when.
Sign-in and sessions
- Google sign-in only in v0.1. HQ users and owners sign in with Continue with Google, so SignaUnit stores no passwords. Owners are invited by email and sign in with the Google account for that address.
- Web sessions use secure, HTTP-only cookies.
- iPhone sessions use short-lived access tokens, with refresh tokens kept in the iOS Keychain. Push tokens are bound to the session.
- Invite and sign-in endpoints are protected against automated abuse.
- HQ single sign-on (SAML/OIDC) and SCIM deprovisioning are Planned.
- Sign-in isn’t open yet. The current sign-in page is a preview: its Continue with Google button is a placeholder and collects no credentials.
- Other sign-in methods: email sign-in links, passkeys, Face ID unlock and Sign in with Apple are Planned.
- Customization stays inside the wall. Custom fields, templates, webhooks and API clients live inside the tenant boundary and are covered by the same row-level security. See Customization & extensibility.
Files and secrets
- Uploaded files (CSV imports, audit and proof photos) are stored in tenant-scoped object storage, never in a code repository.
- Connector credentials are held in a secrets manager and are never stored in the database in plain text.
- Application secrets live in the hosting environment’s encrypted settings, never in source code. Automated secret scanning runs on every change.
Voice and AI
- Speech is turned into text on the iPhone. No audio is stored or uploaded.
- Text is sent to the server only when the phone can’t interpret a request on its own, and is deleted after 30 days unless your brand sets a different retention period.
- AI requests carry IDs rather than names where possible, and are limited to choosing one of five fixed actions. Every write is confirmed by a person.
- AI providers must offer zero-retention, no-training terms. Your operations content is never used to train a public model.
- Voice can be turned off per person or for the whole brand.
See iOS app and voice.
Privacy defaults that protect owners
Several defaults exist to keep HQ focused on outcomes, and they double as privacy protections for franchisees:
- Owner notes are private unless shared.
- HQ can’t see per-person activity or last-seen times for franchisee-side users.
- Web session recording is off for franchisee-side users.
- KPI imports carry unit-level totals only, never per-employee rows.
Backups and environments
The production database has point-in-time recovery backups. Staging and production are separate environments, and staging sits behind authentication. Development and demos use synthetic data only.
Dedicated database option Planned
For a large franchisor that requires physical separation, SignaUnit is designed to run that tenant on its own dedicated database with the same structure. This option is designed for but not built in v0.1.
Reporting a security concern
If you believe you’ve found a security issue, email hello@signaunit.com with the subject “Security”. Please don’t include sensitive data in the first message.