Privacy

What we store, and what we don’t

This is a description of what the software does, not a statement of intent. Every claim below names a specific mechanism, so it can be checked rather than believed.

An account is a username and a password

Signing up asks for a username and a password. That is the entire form. The row kept for you holds the username as you typed it, a case-folded copy of it so that two people cannot register names that differ only in capitalisation, a password hash, an optional hash of a single-use recovery code and the date that code was used if it ever was, a role, a flag saying whether the account is banned, and the date it was created.

There is no email column in the database. Not blank — absent. The same goes for a real name, a phone number, a date of birth, a school, a graduation year and a profile photo. Nothing asks for them, so nothing can leak them, and no future change of ownership can quietly start using them.

Passwords

Passwords are hashed with scrypt from Node’s standard library — N = 32768, r = 8, p = 3, a 64-byte key and a fresh 16-byte random salt for every password. The cost parameters are written alongside each hash, so they can be raised later without locking anyone out. The password itself is never stored and cannot be recovered from the hash.

The cost of that is real and worth stating plainly: if you lose both your password and your recovery code, the account is unreachable. We hold nothing that could establish you as its owner, so there is no support route that could hand it back. That is the trade this design makes deliberately.

Sessions and cookies

Signing in sets exactly one cookie, tellyrate_session. It is httpOnly so page scripts cannot read it, SameSite=Lax so another site cannot ride on it, marked Secure in production, and it expires after thirty days — slid forward once a session is more than half spent, so you are not logged out mid-visit.

The value in the cookie is 256 random bits. What the database stores is its SHA-256 digest, so a dump of the sessions table is a list of hashes that cannot be replayed as a login. Signing out deletes the row and the cookie; signing out everywhere deletes every session for the account, which is the remedy if you think your password has leaked.

The only other cookie is the language you picked, tellyrate-locale, holding en or ar. It is read on the server to decide which words a page is written in, and it is not sent anywhere else. There is no analytics cookie, no third-party cookie, and no consent banner, because there is nothing to consent to.

Your browser’s local storage

Two things. tellyrate-theme holds light or dark once you have chosen one; a small inline script reads it before the first paint so a dark-mode visitor never gets a white flash. And while you are writing a review, a draft of it is saved under tellyrate:draft:v1 followed by that hospital’s name — your text and your ratings — so that signing in partway through does not lose what you wrote. The draft is kept for fourteen days, or until you post, and you can clear it at any time by clearing site data for this domain. Both stay in your browser and are never sent to the server.

IP addresses are never stored

Any site that lets strangers write needs a way to stop a flood, and the usual way is to keep a log of who did what from where — exactly what this site promises not to do.

So an address is never written down. To count requests it is passed through HMAC-SHA256, keyed with a server secret plus today’s date in UTC, and only the first 24 characters of the digest are kept, as part of a key like review:a:<digest>. The row holds that key, a count, and the time the window resets. Nothing else: no timestamps of individual actions, no user agent, no path, no record of what was posted.

Because the key includes the date, the same address produces a different digest tomorrow. Yesterday’s counters cannot be joined to today’s, so the table cannot be reassembled into a history of anyone’s activity — by us or by anyone who takes a copy of it. Expired rows are deleted outright.

Two details, for completeness. IPv6 addresses are truncated to their /64 prefix before hashing, because phones rotate the rest of the address routinely and would otherwise get an unlimited supply of fresh counters. And when you are signed in, throttling counts against your account id instead — the address is not hashed at all.

No third parties, enforced by the browser

There is no analytics, no tag manager, no advertising network, no A/B testing service, no session recorder, no error-reporting service, no embedded video, no social buttons and no map tiles. Fonts are served from this domain rather than a font CDN, which would otherwise hand your address to a third party on every page load.

That is not only a policy — the browser enforces it. Every response carries a Content Security Policy of default-src 'self' with connect-src 'self' and frame-ancestors 'none': if a tracker were ever added to this site, your browser would refuse to contact it. The policy does permit inline scripts and styles, which the site needs in order to render a page before its JavaScript arrives — that allows code written into this site's own pages, never a request to anybody else's server. Responses also send Referrer-Policy: no-referrer, so following a link out of here does not tell the destination which facility page you were reading, and a Permissions-Policy that switches off camera, microphone, geolocation and interest-cohort advertising.

What is public

Everything you post is public and indexable — that is the point of the site. Specifically: your username, your reviews with their ratings and text, your comments, the field you trained in, what you were there as, the department if you named one, the year (widened to a five-year band on facilities with fewer than five reviews), and the totals of likes and dislikes.

Who voted is not public. A facility page loads your own vote and no one else’s — the voter list is never sent to a browser.

Where honesty about anonymity stops

A username with no email behind it protects you from being identified by this site. It does not protect you from being identified by what you write, and no software can.

If you were the only pharmacy student in that department that term, or you describe an incident everyone there remembers, or you write the way you talk, a colleague reading it may well know who you are. Only you can judge how much detail is worth that risk. The guidelines give concrete advice on writing something useful without pinning it to one person.

Publishing is also less reversible than people expect. Deleting a review removes it from this site; it does not remove it from a search engine’s cache, someone’s screenshot, or a scraper’s copy taken an hour after you posted it.

The layer we don’t control

The site runs on rented servers and reaches you across a network that belongs to other people. TLS terminates at the host, so the host can see connection metadata — an address, a timestamp, a requested path — exactly as it can for every site it serves, under its own policies rather than this one.

What can be said is that the application never asks for those records, never stores them, and has nothing to join them to. Database backups contain the same rows described on this page and nothing more.

If someone demands the data

If we were ever compelled to hand over what is held about an account, this is the complete list of what exists:

  • the username
  • a password hash that cannot be reversed
  • possibly a hash of a recovery code
  • a role, a banned flag and a creation date
  • the reviews, comments and votes already published for anyone to read

There is no email address, no phone number, no address log and no browsing history, because none of it is ever collected. A demand cannot produce what was never written down.

Changes to this page

This page describes the code, so it changes when the code does. If a future version of the site ever collected something new, this page would have to say so — and if it says nothing about a kind of data, that data is not collected.