Files
MijnBesluit/db/13_adverteren.sql
T
2026-09-27 14:21:31 +00:00

124 lines
6.1 KiB
SQL

-- ============================================================================
-- Adverteren op MijnBesluit: adverteerders, campagnes en tellers.
--
-- Lees docs/Adverteren.md voordat je hier iets aan verandert. Daar staat waarom de balk laag
-- is, hoe er wordt gekozen wie er getoond wordt, en waarom goedkeuring vooraf gaat.
--
-- Draaien met:
-- mysql -u root -p mijnbesluit < db\13_adverteren.sql
--
-- Opnieuw draaien mag: er gebeurt dan niets.
-- ============================================================================
USE `mijnbesluit`;
-- ------------------------------------------------------------ adverteerders ---
-- Een bedrijf dat adverteert. Bewust een eigen tabel en géén regel in `users`:
--
-- * Een adverteerder is een bedrijf, geen persoon met een kluis, familie of nalatenschap.
-- Hem in `users` zetten zou betekenen dat elke query over gebruikers hem moet uitzonderen,
-- en één vergeten uitzondering is er één te veel in een applicatie die over nalatenschappen
-- gaat.
-- * Het scheidt de twee werelden ook fysiek: wie in het adverteerdersdeel inbreekt, staat nog
-- steeds nergens bij de kluizen in de buurt.
--
-- Inloggen gaat net als bij gebruikers met een code per e-mail; die codes staan in dezelfde
-- tabel `login_codes`, met een eigen doel-nummer.
CREATE TABLE IF NOT EXISTS `adverteerders` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`company_name` VARCHAR(160) NOT NULL,
`contact_name` VARCHAR(160) NOT NULL DEFAULT '',
`email` VARCHAR(255) NOT NULL,
`phone` VARCHAR(50) NULL,
`address` VARCHAR(160) NULL,
`postal_code` VARCHAR(20) NULL,
`city` VARCHAR(120) NULL,
`country` VARCHAR(80) NULL,
`coc_number` VARCHAR(40) NULL, -- KvK
`vat_number` VARCHAR(40) NULL, -- btw
`created_at` DATETIME(6) NOT NULL,
`last_seen_at` DATETIME(6) NULL,
`blocked_at` DATETIME(6) NULL, -- geen nieuwe campagnes meer; bestaande blijven staan
PRIMARY KEY (`id`),
UNIQUE KEY `ux_adverteerders_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------- campagnes ---
-- Eén geboekte advertentie: wat er staat, wanneer hij mag draaien, hoe vaak per uur, wat hij
-- kost en hoe ver hij is.
--
-- De afbeelding staat hier als blob en niet in `vault_files`. Die tabel is voor spullen van
-- gebruikers en is versleuteld met sleutels per gebruiker; een advertentielogo is juist
-- openbaar en hoort daar niet tussen te staan. Hij wordt bij het opslaan verkleind, dus groot
-- kan hij niet worden.
--
-- `amount_cents` wordt bij het boeken berekend en dan vastgelegd. Verandert het tarief later,
-- dan verandert een al geboekte campagne niet mee - je hebt afgesproken wat je afsprak.
CREATE TABLE IF NOT EXISTS `campagnes` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`advertiser_id` BIGINT NOT NULL,
`text` VARCHAR(300) NOT NULL,
`link` VARCHAR(500) NOT NULL,
`image` LONGBLOB NULL,
`image_type` VARCHAR(100) NULL,
`starts_on` DATE NOT NULL,
`ends_on` DATE NOT NULL,
`per_hour` INT NOT NULL,
`amount_cents` INT NOT NULL,
`rate_cents` INT NOT NULL, -- het tarief waarmee gerekend is, voor de verantwoording
`payment_reference` VARCHAR(40) NULL, -- wat de adverteerder bij zijn bunq-betaling zet
`paid_at` DATETIME(6) NULL,
`paid_by_user_id` BIGINT NULL, -- welke beheerder het afvinkte
`state` TINYINT NOT NULL DEFAULT 0,
`approved_at` DATETIME(6) NULL,
`approved_by_user_id` BIGINT NULL,
`rejection_reason` VARCHAR(500) NULL,
`created_at` DATETIME(6) NOT NULL,
`updated_at` DATETIME(6) NULL,
PRIMARY KEY (`id`),
KEY `ix_campagnes_adverteerder` (`advertiser_id`),
-- De vraag "welke campagnes mogen nu draaien" komt bij élke keer dat iemand het overzicht
-- opent. Die moet op een index kunnen landen en niet op de hele tabel.
KEY `ix_campagnes_lopend` (`state`, `starts_on`, `ends_on`),
CONSTRAINT `fk_campagnes_adverteerder` FOREIGN KEY (`advertiser_id`)
REFERENCES `adverteerders` (`id`) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- --------------------------------------------------------------- vertoningen ---
-- Eén regel per campagne per klokuur, met tellers erin. Níét één regel per vertoning: bij een
-- paar honderd bezoekers per uur loopt zo'n tabel eindeloos vol, en voor het kiezen én voor de
-- verantwoording is een teller per uur genoeg.
--
-- Het uur staat in UTC, op het hele uur afgerond. De unieke sleutel is wat het optellen veilig
-- maakt: twee bezoekers tegelijk leveren een INSERT ... ON DUPLICATE KEY UPDATE op en geen
-- tweede regel.
CREATE TABLE IF NOT EXISTS `campagne_uren` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`campaign_id` BIGINT NOT NULL,
`hour_utc` DATETIME(6) NOT NULL,
`shown` INT NOT NULL DEFAULT 0,
`clicks` INT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_campagne_uren` (`campaign_id`, `hour_utc`),
CONSTRAINT `fk_campagne_uren_campagne` FOREIGN KEY (`campaign_id`)
REFERENCES `campagnes` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- De rechten voor de applicatiegebruiker staan NIET hier maar in 02_applicatiegebruiker.sql.
--
-- Waarom: de scripts vanaf 03 worden ook door de uitrolagent gedraaid, met een beperkt
-- databaseaccount dat geen rechten mág uitdelen. Een GRANT hier laat die hele uitrol struikelen,
-- en dat account meer macht geven is de verkeerde kant op. Rechten uitdelen is inrichten; dat
-- doet een mens één keer als root. Een zelfcontrole legt elke CREATE TABLE in deze map naast de
-- lijst in 02, dus vergeten kan niet ongemerkt.
SELECT 'Klaar. Adverteerders, campagnes en tellers staan klaar.' AS melding;