jevstrudel.git / worker / migrations / 0005_pitch_votes.sql

Pitches: listeners' votes on them, and the listener songs that answer them. Owner: src/content-store.ts reads and writes both, for src/content.ts (the routes); src/data.ts reads them for the data tab.

What is identifying here, and why (migrations/CLAUDE.md): a vote names the account that cast it, so each account votes once per pitch and can take its vote back. Like every row, it is public: the data tab shows who voted for what (worker/README.md, What is public). Times are milliseconds since the epoch, UTC.

One account's vote for one pitch; taking it back deletes the row. Only a public pitch can be voted on (content.ts checks; a held pitch's votes, if it were ever held after, stay as they were).

14CREATE TABLE pitch_votes (
15  pitch TEXT NOT NULL REFERENCES pitches (id) ON DELETE CASCADE,
16  user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE,
17  created_at INTEGER NOT NULL CHECK (created_at > 0),
18  PRIMARY KEY (pitch, user_id)
19) STRICT;
20CREATE INDEX pitch_votes_by_user ON pitch_votes (user_id);

The pitch a listener song answers, set by the song's author (a site song says so in its SPEC.md, pitch:, which the build reads): the maker of a song is the one who can say what it answers. NULL when it answers none, and again if the pitch is deleted.

26ALTER TABLE listener_songs ADD COLUMN pitch TEXT REFERENCES pitches (id) ON DELETE SET NULL
27  CHECK (pitch IS NULL OR (length(pitch) = 22 AND pitch NOT GLOB '*[^A-Za-z0-9_-]*'));
28CREATE INDEX listener_songs_by_pitch ON listener_songs (pitch);