-- 008_band_locations.sql -- Table relationnelle N steps × M villes par band pour le géocodage multi-périodes. -- Remplace la logique mono-entrée de geocode_queue pour les nouveaux traitements. CREATE TABLE IF NOT EXISTS band_locations ( id BIGSERIAL PRIMARY KEY, ma_id BIGINT NOT NULL REFERENCES bands(ma_id) ON DELETE CASCADE, step_order SMALLINT NOT NULL DEFAULT 0, step_label TEXT, location_raw TEXT NOT NULL, is_country_only BOOLEAN NOT NULL DEFAULT FALSE, lat DOUBLE PRECISION, lon DOUBLE PRECISION, geocode_status TEXT NOT NULL DEFAULT 'queued', geocode_query TEXT, geocode_provider TEXT, geocode_confidence REAL, geocode_error TEXT, geocode_tries_geo SMALLINT NOT NULL DEFAULT 0, geocode_tries_llm SMALLINT NOT NULL DEFAULT 0, geocode_next_at TIMESTAMPTZ NOT NULL DEFAULT now(), created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE (ma_id, step_order, location_raw) ); -- Index pour la boucle de travail du geocoder CREATE INDEX IF NOT EXISTS idx_bl_geo_work ON band_locations (geocode_next_at ASC, id ASC) WHERE geocode_status = 'queued'; -- Index pour la boucle du groq-worker CREATE INDEX IF NOT EXISTS idx_bl_llm_work ON band_locations (geocode_tries_llm ASC, id ASC) WHERE geocode_status = 'llm_needed'; -- Index de navigation par band CREATE INDEX IF NOT EXISTS idx_bl_ma_id ON band_locations (ma_id); -- Cache pour éviter de rappeler le LLM pour la même entrée CREATE TABLE IF NOT EXISTS llm_cache ( id BIGSERIAL PRIMARY KEY, input_hash TEXT NOT NULL UNIQUE, model TEXT NOT NULL, prompt TEXT NOT NULL, response TEXT NOT NULL, parsed_city TEXT, parsed_country TEXT, is_null BOOLEAN NOT NULL DEFAULT FALSE, tokens_in INTEGER, tokens_out INTEGER, cost_usd NUMERIC(10, 8), created_at TIMESTAMPTZ NOT NULL DEFAULT now() );