-- 187_gisogd_permits.sql
-- Forgejo #2367 PR-1 (Schema) — реестр разрешений на строительство (РНС) и ввод
-- в эксплуатацию (РВЭ) Свердловской области из ОТКРЫТОГО API ГИСОГД-СО.
--
-- Одна таблица gisogd_permits: карточки документов раздела 13 («Сведения о
-- документах в деле о земельном участке») региональной ГИС органов гос. власти
-- Свердловской области (gisogd66.midural.ru). Открытый JSON-API без авторизации.
--
-- Источник (карточки/списки) отдаёт данные без гео-блокировки (bare curl 200), но
-- код лоадера всё равно держим устойчивым к отсутствию полей (spatialUnit / geometry
-- у части документов отсутствуют — hasGeometry=false).
--
-- Две схемы источника:
--   agate_ekbgo         — ЕКБ, самая свежая выгрузка;
--   agate_sverdregion   — регион-агрегат, отстаёт ~неделю.
-- Один документ может встретиться в ОБЕИХ схемах → бизнес-ключ = (doc_group, doc_num);
-- при конфликте предпочитаем запись с более поздним date_reg (лоадер, PR-2).
--
-- doc_group:
--   'RS' — Разрешение на строительство (группа источника DocRS);
--   'RV' — Разрешение на ввод в эксплуатацию (группа источника DocRV).
--
-- cad_nums — распарсенный spatialUnit (может быть НЕСКОЛЬКО кадастровых номеров
-- через запятую, может отсутствовать → пустой массив). geom — из infosetGeoJson
-- (GeoJSON Polygon WGS84 lon/lat, лоадер приводит к MultiPolygon), NULL когда
-- hasGeometry=false. source_schema/source_key фиксируют, откуда прилетела запись
-- (для инкрементальной сверки по (source_schema, source_key, date_reg)).
--
-- Порядок применения: миграция ПЕРЕД деплоем кода (schema-first, sql.md).
-- Таблица НОВАЯ → deploy.yml гоняет всё в одной транзакции; CREATE INDEX
-- CONCURRENTLY здесь не нужен (и запрещён внутри транзакции).

BEGIN;

-- ── gisogd_permits ────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS gisogd_permits (
    id                    BIGSERIAL PRIMARY KEY,
    doc_group             TEXT        NOT NULL,   -- 'RS' (РНС) | 'RV' (РВЭ) — см. CHECK
    doc_num               TEXT        NOT NULL,   -- № документа, напр. «66-45-08-2026» (strip'нут)
    doc_name              TEXT,                   -- name карточки, напр. «Разрешение на строительство № … от …»
    date_doc              DATE,                   -- dateDoc — дата выдачи документа
    date_reg              DATE,                   -- dateReg — дата регистрации в реестре (для conflict-резолва)
    approved_organization TEXT,                   -- approvedOrganization — выдавший орган
    source_schema         TEXT        NOT NULL,   -- 'agate_ekbgo' | 'agate_sverdregion'
    source_key            TEXT        NOT NULL,   -- key карточки в схеме источника (для инкрементальной сверки)
    cad_nums              TEXT[]      NOT NULL DEFAULT '{}',  -- распарсенный spatialUnit ('{}' если нет)
    geom                  GEOMETRY(MultiPolygon, 4326),      -- из infosetGeoJson; NULL если hasGeometry=false
    fetched_at            TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at            TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    -- Только 'RS'/'RV' допустимы (защита от опечаток в лоадере).
    CONSTRAINT chk_gisogd_permits_doc_group CHECK (doc_group IN ('RS', 'RV')),

    -- Бизнес-ключ: один документ (группа + номер) хранится ОДНОЙ строкой, даже если
    -- прилетел из обеих схем. Лоадер UPSERT-ит по нему, предпочитая поздний date_reg.
    UNIQUE (doc_group, doc_num)
);

-- Пространственный индекс — §-запросы «РНС/РВЭ рядом с участком».
CREATE INDEX IF NOT EXISTS gist_gisogd_permits_geom
    ON gisogd_permits USING GIST (geom);

-- GIN по массиву кадастровых номеров — матч «разрешение на этом участке».
CREATE INDEX IF NOT EXISTS gin_gisogd_permits_cad_nums
    ON gisogd_permits USING GIN (cad_nums);

-- Дата документа — фильтры/сортировки по свежести разрешений.
CREATE INDEX IF NOT EXISTS idx_gisogd_permits_date_doc
    ON gisogd_permits (date_doc DESC);

COMMENT ON TABLE gisogd_permits IS
    'Реестр разрешений на строительство (РНС) и ввод в эксплуатацию (РВЭ) '
    'Свердловской области из открытого API ГИСОГД-СО (gisogd66.midural.ru, раздел 13). '
    'Бизнес-ключ (doc_group, doc_num); при конфликте двух схем источника '
    '(agate_ekbgo / agate_sverdregion) предпочитается поздний date_reg. Refresh: weekly '
    '/ on-demand. Forgejo #2367.';

COMMENT ON COLUMN gisogd_permits.doc_group IS
    '''RS'' = разрешение на строительство (группа источника DocRS), '
    '''RV'' = разрешение на ввод в эксплуатацию (группа источника DocRV).';

COMMENT ON COLUMN gisogd_permits.cad_nums IS
    'Распарсенный spatialUnit карточки: список кадастровых номеров (несколько через '
    'запятую в источнике). Пустой массив ''{}'' когда spatialUnit отсутствует или все '
    'значения не прошли валидацию формата кадастрового номера.';

COMMENT ON COLUMN gisogd_permits.geom IS
    'MultiPolygon (WGS84) из infosetGeoJson карточки (Polygon приведён к MultiPolygon '
    'лоадером). NULL когда hasGeometry=false / infosetGeoJson отсутствует.';

COMMENT ON COLUMN gisogd_permits.source_schema IS
    'Схема источника, из которой прилетела запись: ''agate_ekbgo'' (ЕКБ, свежая) или '
    '''agate_sverdregion'' (регион-агрегат, отстаёт ~неделю).';

COMMENT ON COLUMN gisogd_permits.source_key IS
    'key карточки в схеме источника. Вместе с (source_schema, date_reg) используется '
    'лоадером для инкрементальной сверки: карточки тянутся только для новых/изменённых.';

COMMIT;
