Privacy
Study Match — privacy policy
This is a hackathon demo server. It runs on a teammate's laptop, it stores data for a class project, and it is not run
by a company. It has no age verification and no identity verification: signing up means you ticked a box saying you are
18 or older, and nothing checks that. Treat everything here as a demo, not as a production social product.
WHAT WE COLLECT
Only these things, and only because matching does not work without them:
- Your account: email address, password (we store a hash, never the password itself), display name, and a preset avatar
id you pick from a fixed list.
- Availability: your free windows as start and end times in UTC, plus the time zone they were given in so we can print
them back in your own local time.
- Interests: at most eight short tags (32 characters each), in your own words — "matcha", "sourdough", "bouldering".
These are the only free-text field in the system, and they are tightly bounded: no line breaks, no control
characters, no paragraph. The server translates each one onto its matching vocabulary ("matcha" counts as coffee).
Your raw words stay attached to your own account and are shown back to you; **only the canonical tag ever appears
on a card**, so your phrasing is never shown to another student. An interest nothing matches is kept for you and
never scored.
- Wants: zero to two words from `hangout` and `event` — whether you would rather meet up or go to an
event. Nothing else fits the field, so nothing else can be written into it.
- Consent log: one row per grant or withdrawal, recording the action, its scope and when it happened.
- Inbox messages: the notifications we compose for you (a new card, a counter-offer, a confirmation, a revocation).
- A pairing record for each device your Cubbie agent runs on, so the agent can authenticate. The token is stored hashed.
WHAT WE NEVER ACCEPT
The server rejects these outright, with HTTP 422 `payload_forbidden`. They are not "not stored" by policy — there is no
field for them and the validator refuses unknown fields at every level of the payload:
- calendar event titles, attendees, or locations;
- course codes, course names, professor names, or assignment names;
- grades, of any kind, anywhere;
- free text of any description — with one bounded exception: interests (the tags above), which are capped at 32
characters each and at most eight of them, and are canonicalised before they are used for anything.
That is the point of the design: your Cubbie agent reads your calendar on your phone, turns it into time ranges plus
tags, and deletes the rest. What reaches this server is a handful of intervals and a few words from a closed list.
HOW LONG WE KEEP IT
There is one rule per kind of data, and the server enforces each one:
- Availability expires 7 days after it was observed. Expired availability is never read, even before it is deleted.
- Closed matches, swipes and match reasons are kept 30 days.
- The consent log is kept while your account exists. When you delete your account it is stripped down to a pseudonymous
id (a salted hash, not your account id or email), the action, its scope, and the timestamp — the detail payload is
blanked to `{}` — and it is purged after 90 days.
- Blocks are pseudonymous from the moment they are created: they store salted hashes, never your account id, and they
expire after 12 months.
- Deleted rows persist in encrypted backups until they expire, within 14 days.
We do not use sub-processors. This is a self-hosted demo: one FastAPI process and one SQLite file. There is no
analytics vendor, no email vendor, no cloud queue.
YOUR RIGHTS, AS BUTTONS
- Every grant has a toggle in settings. Turning one off withdraws the live grant, and the withdrawal is recorded.
- "Leave matching" withdraws your matching grant, deletes your live availability, and voids every in-flight plan you are
part of — the other side is told the plan is voided, without being told why.
- "Delete my account" runs the whole cascade in one transaction. Your account row is stripped (email, display name and
password hash blanked, `deleted_at` set, so the session dies). Your availability and its windows, your wants, your hobby tags,
your swipes, your inbox items and the confirmations on your proposals are deleted. Your grants are withdrawn, your
pairing records are revoked, and your candidates and live proposals are voided — so the other side's card or plan
stops being served, without being told why. What survives is deliberately narrow: your block hashes (salted, so a
block keeps working), the report rows (a report is not erased by deleting the reporter), and the stripped consent rows
described above on their 90-day clock.
- Block and report: one report hides the pair immediately, both directions. A block does the same and additionally
prevents any future card between the two of you, both directions.
To ask a question about any of this, ask whoever handed you the invite code — there is no support desk.