-- ============================================================================ -- 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;