Pods
What a pod stores, who can read it, and how join links and guest players work.
A pod is a group of people who play together. Four tables hold one: pods for
the group, pod_members for who is in it, pod_invites for the link that lets
someone join, and pod_guests for a player with no account.
Every one of the four is readable only by the pod's own members.
The pod
| Column | What it holds |
|---|---|
name | The pod name. Between 1 and 60 characters after trimming. |
created_by | Who created it. Provenance only, since who administers a pod is the role on pod_members. Clears to null with the account, and the pod stays. |
created_at | When it was created. |
Membership
| Column | What it holds |
|---|---|
pod_id, user_id | The pair is the primary key, so a second join writes nothing rather than a duplicate. |
role | owner or member. Owners rename the pod, set roles, and remove people. |
joined_at | When the person joined. |
A pod always has at least one owner. Removing the last one raises an error in the database rather than being prevented by a screen, so it holds however the row is deleted.
Join links
| Column | What it holds |
|---|---|
token | 32 hex characters, generated when the row is created. This is the secret in a join URL. |
status | active or revoked. |
expires_at | Seven days after the link was created, unless set otherwise. |
invited_by | Who created the link. Clears to null with the account. |
created_at | When the link was created. |
One link admits several people, so an invite has no accepted state. A link works until it is revoked or it expires.
What a link shows before you sign in
Opening a join link names the pod and whoever created the link, to anyone holding it, signed in or not. That is deliberate: deciding whether to join a pod is deciding what to share, and nobody can decide that against a token that says nothing.
Those two fields are the whole of it. A link reveals no member list, no decks and no pod id, and it grants nothing until somebody signs in and accepts.
Revoking a link takes the pod name back with it. A revoked or expired link stops naming anything.
Guest players
| Column | What it holds |
|---|---|
display_name | The name shown for that player. Between 1 and 40 characters, and unique within the pod, ignoring case, among guests that are not archived. |
claimed_by_user_id | Set when the person behind the guest signs up and the record is claimed. Null otherwise. |
archived_at | Set when a guest is retired. An archived guest stays readable, and its name becomes free for reuse. |
created_by | Who added the guest. Clears to null with the account. |
created_at | When the guest was added. |
A guest belongs to the pod rather than to a single game, so a pod collects a handful of them and the same name is reused week to week.
Who can read and write what
A person outside a pod reads zero rows from all four tables. The anon role
holds no privilege on any of them, so a request without a session is refused
rather than answered with an empty list.
Inside a pod, any member can read everything, add a guest, and create or revoke a join link. Owners additionally rename the pod, change roles, and remove people. Anyone can remove their own membership.
Two writes are refused for everybody, a pod's own owner included:
- Nothing writes a row into
pod_membersdirectly. Being in a pod has to mean that the person agreed to be in it, and an owner who could insert a user id could put anyone in a pod without asking. - Nothing writes a row into
podsdirectly. Creating a pod has to create its first owner in the same transaction, or a failure between the two writes leaves a pod that nobody can administer.
Both rules are enforced by the absence of a policy and by the absence of a grant, so neither depends on the other being right.
What sharing a pod shares
Two views answer this, and they are the only way one account reads another's data here. Both list their columns rather than selecting everything, so what follows is the whole of it.
Your pod-mates see, for you: your username, and your display name and avatar.
Your pod-mates see, for each of your decks: the deck name, the format, the colors, the commander's name and the commander's card image.
Your pod-mates do not see: the card list, the deck overview, your deck
notes, the budget, the meta notes, or your email. Joining a pod grants no access
at all to deck_cards, and a pod-mate asking for the cards in a deck they can
name still reads zero rows.
The deck name is the label and the commander is secondary, because one person can have two decks with the same commander and a commander alone cannot tell them apart.
Three things worth knowing
Marking a deck private does not hide its name from your pod. Private governs the deck itself, which stays unreadable: the card list, the overview and the notes are closed to a pod-mate whatever the setting. What a pod shares is the name and the commander, so that somebody can put your deck in a seat. A deck you delete leaves the list straight away.
Your display name, avatar and bio are already public, to anyone, signed in or not. That is how profiles work throughout the app and it is not something a pod changes. Your username is the part a pod makes visible.
Leaving a pod ends it. Remove yourself, or get removed, and the decks and names stop resolving on the next read. Nothing is cached on anyone else's account.