Een dating-app op basis van brieven, niet van gezichten!
Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.
-- Promotieteam: de vrienden die vrijwillig mond-tot-mondreclame maken.
--
-- Eigen database, met opzet los van de app. Het schema van de app wordt bij elke wijziging
-- opnieuw aangemaakt en zijn gegevens zijn wegwerpbaar (zie db/setup.js); deze lijst is dat
-- niet. Daarom staat er hier ook nergens een `drop table`: dit bestand mag zo vaak uitgevoerd
-- worden als je wilt en raakt nooit een bestaande rij aan.
--
-- Er is geen quotum en geen controle. Dit schema telt daarom niets: geen aanbrengcodes, geen
-- verwijzing naar de gebruikers van de app, geen score per persoon. Zou zoiets er staan, dan
-- gaat iemand ernaar kijken, en dan is het alsnog een quotum. Het beantwoordt één vraag:
-- wie doet er mee, en hoe bereik ik diegene als het feest er is.
create table if not exists promoters (
id bigint primary key generated always as identity,
name text not null check (length(trim(name)) between 1 and 80),
-- Contact: e-mail, telefoon, of allebei. Minstens één van de twee, want zonder contact kun
-- je iemand niet uitnodigen en is de rij een naam zonder feest.
email text check (email is null or (email = lower(email) and email like '%@%')),
phone text check (phone is null or length(trim(phone)) > 0),
joined_on date not null default current_date,
-- Gestopt. De rij blijft staan: "wie was er vorig jaar bij" blijft zo te beantwoorden, en
-- wie weer meedoet is één klik terug. Echt weg wil hebben kan ook — dan wordt de rij gewist.
left_on date,
note text not null default '',
check (email is not null or phone is not null),
check (left_on is null or left_on >= joined_on)
);
create index if not exists promoters_name on promoters (lower(name));
/*
* Vanaf hier de post. Deze database blijft staan (anders dan die van de app), dus wat er later
* bij komt, komt er met `alter ... if not exists` bij: dit bestand blijft één keer draaien én
* herhaalbaar, zonder een migratiestapel en zonder ooit een naam te wissen.
*/
alter table promoters add column if not exists welcomed_at timestamptz; -- wanneer de welkomstmail eruit ging
/*
* Gezet als het vertrek van de afmeldknop in de mail kwam, en niet van de knop Gestopt hier. Dat
* onderscheid is nodig omdat Postmark op zijn afmeldpagina meteen een "toch weer aanmelden" biedt
* voor wie zich vergist: verdwijnt iemand daardoor weer van hun afmeldlijst, dan hoort hij hier
* ook terug te komen. Wie jij met de hand op Gestopt zet, staat nooit op die lijst en wordt door
* die terugweg dus met rust gelaten.
*/
alter table promoters add column if not exists unsubscribed_at timestamptz;
/*
* Hier stond een `unsub_token` voor een eigen afmeldlink. Die is er niet meer: bij een
* broadcast-stream doet Postmark het afmelden zelf en is dat niet uit te zetten zonder hun
* toestemming voor "custom unsubscribe handling". Wie afmeldt komt op hun onderdrukkingslijst, en
* server/promotie.js haalt die op en zet diezelfde persoon hier op `left_on`. Eén afmeldweg, en
* de kolom hoort dan ook weg te zijn in plaats van ongebruikt te blijven staan.
*/
alter table promoters drop column if exists unsub_token;
/*
* De vaste tekst van de welkomstmail: één rij, te bewerken op /promotieteam. Hier en niet in de
* repository, want de repository is openbaar en dit zijn jouw woorden aan je vrienden — en omdat
* schaven aan een zin geen uitrol hoort te kosten. `{naam}` wordt de aanhef.
*/
create table if not exists welcome (
singleton boolean primary key default true check (singleton),
subject text not null default 'Welkom bij het promotieteam',
body text not null default
'Hoi {naam},
Fijn dat je meedoet. Je hoeft niets bij te houden en er is geen quotum — vertel het gewoon door
aan wie je denkt dat er iets aan heeft.
Als dank geef ik een feestje. Je hoort van me wanneer.
Groet,
Bram'
);
insert into welcome default values on conflict do nothing;
/*
* Wat er naar de groep is gegaan. Geen prestatiemeting van wie dan ook — het is het doorslagvel:
* wat schreef ik, wanneer, aan hoeveel mensen, en bij wie liep het mis.
*/
create table if not exists mailings (
id bigint primary key generated always as identity,
subject text not null,
body text not null,
sent_at timestamptz not null default now(),
aantal int not null default 0, -- hoeveel er daadwerkelijk uitgingen
mislukt text not null default '' -- adressen die Postmark weigerde, met de reden
);