Files
Aissa 5d60d33db1 Platform bundle: marketing publish, IT ops, packaging, agents mesh.
Volledige Foodlinkk Command Center uitbreiding met social automatisering,
reclamefolder filters, Proxmox monitoring en documentatie.
2026-06-09 00:41:27 +00:00

114 lines
4.2 KiB
SQL

-- Retail 360: notes, media, milestones, ownership, RSS, city demographics
CREATE TABLE IF NOT EXISTS entity_notes (
id SERIAL PRIMARY KEY,
entity_type VARCHAR(32) NOT NULL,
entity_id INTEGER NOT NULL,
title VARCHAR(255),
body TEXT NOT NULL,
note_type VARCHAR(32) DEFAULT 'general',
created_by VARCHAR(64) DEFAULT 'team',
pinned BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_entity_notes_entity ON entity_notes(entity_type, entity_id);
CREATE TABLE IF NOT EXISTS entity_media (
id SERIAL PRIMARY KEY,
entity_type VARCHAR(32) NOT NULL,
entity_id INTEGER NOT NULL,
filename VARCHAR(255) NOT NULL,
content_type VARCHAR(64) DEFAULT 'image/jpeg',
storage_path TEXT NOT NULL,
caption TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_entity_media_entity ON entity_media(entity_type, entity_id);
CREATE TABLE IF NOT EXISTS sales_milestones (
id SERIAL PRIMARY KEY,
supermarket_id INTEGER REFERENCES supermarkets(id) ON DELETE CASCADE,
client_id INTEGER REFERENCES clients(id) ON DELETE SET NULL,
deal_id INTEGER REFERENCES deals(id) ON DELETE SET NULL,
milestone_type VARCHAR(64) NOT NULL DEFAULT 'custom',
title VARCHAR(255) NOT NULL,
status VARCHAR(32) DEFAULT 'pending',
target_date DATE,
completed_at TIMESTAMPTZ,
value_eur NUMERIC(12,2),
notes TEXT,
sort_order INTEGER DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_milestones_store ON sales_milestones(supermarket_id);
CREATE TABLE IF NOT EXISTS ownership_changes (
id SERIAL PRIMARY KEY,
entity_type VARCHAR(32) DEFAULT 'supermarket',
entity_id INTEGER,
chain VARCHAR(100),
previous_owner VARCHAR(255),
new_owner VARCHAR(255) NOT NULL,
change_type VARCHAR(64) DEFAULT 'acquisition',
effective_date DATE,
source VARCHAR(255),
notes TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_ownership_chain ON ownership_changes(chain);
CREATE TABLE IF NOT EXISTS city_demographics (
id SERIAL PRIMARY KEY,
city VARCHAR(100) NOT NULL,
province VARCHAR(50),
gemeente_code VARCHAR(16),
population INTEGER,
households INTEGER,
avg_income NUMERIC(12,2),
muslim_proxy_pct NUMERIC(5,2),
data_source VARCHAR(100) DEFAULT 'cbs',
last_updated TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(city, province)
);
CREATE INDEX IF NOT EXISTS idx_city_demo_city ON city_demographics(city);
CREATE TABLE IF NOT EXISTS rss_feeds (
id SERIAL PRIMARY KEY,
name VARCHAR(128) NOT NULL UNIQUE,
url TEXT NOT NULL,
category VARCHAR(64) DEFAULT 'general',
is_active BOOLEAN DEFAULT TRUE,
last_fetch_at TIMESTAMPTZ,
last_status VARCHAR(32)
);
CREATE TABLE IF NOT EXISTS rss_items (
id SERIAL PRIMARY KEY,
feed_id INTEGER NOT NULL REFERENCES rss_feeds(id) ON DELETE CASCADE,
title TEXT NOT NULL,
link TEXT,
summary TEXT,
published_at TIMESTAMPTZ,
fetched_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(feed_id, link)
);
CREATE INDEX IF NOT EXISTS idx_rss_items_published ON rss_items(published_at DESC);
ALTER TABLE calendar_events ADD COLUMN IF NOT EXISTS supermarket_id INTEGER REFERENCES supermarkets(id) ON DELETE SET NULL;
ALTER TABLE wholesalers ADD COLUMN IF NOT EXISTS external_id VARCHAR(64);
CREATE UNIQUE INDEX IF NOT EXISTS idx_wholesalers_external ON wholesalers(external_id) WHERE external_id IS NOT NULL;
INSERT INTO rss_feeds (name, url, category) VALUES
('Foodlog NL', 'https://www.foodlog.nl/feed/', 'kant-en-klaar'),
('RetailDetail', 'https://www.retaildetail.nl/feed/', 'retail'),
('VMT Food', 'https://www.vmt.nl/feed/', 'food-industry'),
('Nu.nl Economie', 'https://www.nu.nl/rss/Economie', 'economie'),
('Google Halal Food NL', 'https://news.google.com/rss/search?q=halal+food+supermarkt+nederland&hl=nl&gl=NL&ceid=NL:nl', 'halal')
ON CONFLICT (name) DO NOTHING;
INSERT INTO data_providers (name, provider_type, config, is_active) VALUES
('rss_feeds', 'api', '{"type": "rss"}', true),
('wholesale_osm', 'scrape', '{"chains": ["Sligro", "Hanos", "Makro", "Bidfood"]}', true)
ON CONFLICT (name) DO UPDATE SET is_active = true;