Skip to content

Data and privacy

Verified against v0.21.0 · internal/db/migrations, internal/store/users.go, web/src/lib/notificationAudio.ts, cmd/parley/main.go, internal/auth/oidc.go, internal/standup/webhook.go, internal/plugin/fetch.go, internal/plugin/secrets.go, web/src/lib/meet.ts

Parley stores very little about people, mostly because it never asks. In its default mode there is no account, no email address and no password.

Table Field What it is
users id A generated UUID. Public — it is broadcast to everyone in a room
users name Up to 64 characters. Self-chosen, or derived from an identity-provider claim
users issuer, subject Only for federated sign-in: which provider vouched for you, and your opaque id there. Empty for anonymous users
users avatar_icon The avatar you picked, as one short opaque id (≤32 characters). Empty until you choose one. Public — shown to everyone in a room. Removed with the account: it is a column on the users row, not a separate record
users avatar_accessory Retired in v0.5.1: no longer written or read, and dropped by a later migration
users notification_sounds Whether this user enabled local notification sounds. False by default and never included in rosters or session payloads
users created_at Timestamp
session_tokens token_hash SHA-256 of the bearer token. The token itself is never stored
session_tokens user_id, created_at, last_used_at Which account, and when it was last seen
members space_id, user_id, spectator, last_seen_at Which rooms you have joined
session_presence session_id, user_id, replica_id, seen_at Which session you have a socket open on, and which replica is serving it. Written while you are connected, deleted when you disconnect, and swept once it ages past the presence window (~100s). It is what the space page counts to say “3 here”

No email address is stored, even when signing in through a provider that supplies one — an email is used only to derive a display name, and then discarded. There is no avatar URL and no uploaded image — an avatar is a color derived from your user id plus, optionally, two ids naming a shape you picked from the built-in set — and no IP address column anywhere.

Everything else is what a team types: session titles, story titles and references, notes up to 2000 characters, votes, and standup entries of up to 2000 characters each.

Treat this as the sensitive data. A story note is where somebody writes the customer’s name or the reason a deadline slipped. It is stored as plain text in Postgres, and it is what a database dump mostly contains.

Nothing, unless you configure it. Parley has no telemetry, no analytics, no crash reporting and no update check.

Notification cues are synthesized in the browser with Web Audio. They use no audio files and make no network request. The server stores only the on/off preference.

The server connects to configured Postgres. In open mode with no webhooks or network-capable plugins configured, it needs no external service. With AUTH_MODE=oidc, it also contacts the configured IdP for discovery, signing keys, and sign-in token exchange. Discovery is probed in the background at boot without gating startup or readiness; a failed probe is retried during sign-in.

Configured standup webhooks send event metadata to their approved recipient; plugins with approved fetch grants can send requests to allowed HTTPS hosts. The optional Meet add-on loads Google’s SDK in the browser and uses its activity APIs. Review Integrations and outbound data for the current inventory and operator responsibilities. Self-hosting does not make an external connector or bring-your-own model endpoint local.

CapabilityStatusWhat to do instead
Retention policyNot builtApplication records are not automatically deleted. Session tokens are the exception: they expire on the configured lifetimes and their rows are swept hourly.
Account deletionNot builtThere is no endpoint. DELETE /api/me ends a session, it does not delete the account. Deleting a users row must be done in SQL, and see the caveat below — it is not a clean cascade.
Per-space export or erasureNot builtExport sessions to CSV individually; erase with SQL against the documented schema.
Expired token cleanupBuilt inAn hourly background pass deletes session_tokens rows past either SESSION_IDLE_TTL or SESSION_MAX_TTL, so the table does not grow without bound.
Content encryption at restNot builtMeeting content and room codes are not encrypted by Parley. Use encrypted storage or your database provider's encryption. Plugin secrets and webhook signing secrets use AES-GCM with a configured key. Binding ciphertext to its plugin install/name or webhook space requires a successful parley secrets reseal; key custody remains the operator's responsibility.
TelemetryOut of scopeThere is none, and adding it is not planned.

If you need to answer a data-subject request

Section titled “If you need to answer a data-subject request”

There is no tooling for it. In practice: users gives you the person’s row, members the spaces they joined, and their content is reachable by user_id from votes and standup_entries.

members, session_tokens, session_presence, votes and standup_entries all cascade on delete, so removing the users row takes them with it.

Verify against the schema before running anything destructive, and take a backup first.