initial: split from gov-agreg — vreau.digital standalone platform
Moved from gov-agreg/src/pages/achizitii/* to root (drop prefix). - 22 pages migrated, 127 files total - All internal links: /achizitii/X → /X (176 occurrences fixed) - AchizitiiLayout subnav rewritten: /X paths, top-right link to vreaudigital.ro hub - BaseLayout new (vreau.digital branding, OG tags, site URL) - astro.config.mjs: site https://vreau.digital, server output (was static) - docker-compose: port 5096 (vreaudigital is 5095), container vreau-digital - deploy.sh: paths /opt/vreau-digital, log /var/log/vreau-digital-deploy.log Backend shared with gov-agreg: - PostgreSQL satra (same schemas: seap, firms, anaf, anre, ...) - Photon, Martin tiles - Infisical /vreaudigital path (DATABASE_URL etc. shared) build: PASS (npx astro check 0 errors, npm run build 5s vite + 10s server)
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
-- 034_asf.sql
|
||||
-- ASF — Autoritatea de Supraveghere Financiară.
|
||||
-- Public registries of authorized financial entities (insurers, brokers, pension
|
||||
-- funds, asset managers, intermediaries) scraped from data.asfromania.ro.
|
||||
--
|
||||
-- Sources (all return JSON{raspuns:HTML, status:100} via POST cautare):
|
||||
-- 1. /scr/ra/cautare?l=ro (Registrul asigurătorilor + intermediarilor)
|
||||
-- sectiune=1 tipCompanie=0 → Societăți de asigurare - companii active
|
||||
-- sectiune=2 tipCompanie=0 → Societăți de asigurare - companii radiate
|
||||
-- sectiune=1 tipCompanie=1 → Intermediari principali - companii active
|
||||
-- sectiune=2 tipCompanie=1 → Intermediari principali - companii radiate
|
||||
-- Fields per panel: register_no (RA-XXX/RBK-XXX), LEI, CUI, RC code,
|
||||
-- authorization no/date, registration date, radiation date, type, legal form,
|
||||
-- address, phone, fax, observations, authorized classes (general/life),
|
||||
-- executives. Total: ~768 insurers + ~801 brokers ≈ 1.5K entities.
|
||||
--
|
||||
-- 2. /scr/ra/cautare endpoint accepts free-text 'termen' (≥4 chars). Search
|
||||
-- hits denumire, CUI, adresă, județ, classes. NO captcha required when
|
||||
-- 'g-recaptcha-response' field is OMITTED from the POST body. (When sent
|
||||
-- with any non-empty value the server tries to verify and returns
|
||||
-- "Verificare captcha eșuată".)
|
||||
--
|
||||
-- 3. Pension funds + AIFM/UCITS register pages exist on asfromania.ro/ro/a/...
|
||||
-- but most are F5-WAF-protected from non-browser clients. We start with the
|
||||
-- ra portal which has cleanest data; document handoff for additional
|
||||
-- registers in ASF-PLAN.md.
|
||||
--
|
||||
-- Cross-source value: asf.entitati.cui (extracted directly from response, no
|
||||
-- fuzzy match needed) × seap.announcements.supplier_cui = "ASF-licensed firms
|
||||
-- with state contracts". Red-flag: insurance firm wins SEAP contract for state
|
||||
-- insurance services but has been radiated by ASF; broker active in SEAP but
|
||||
-- with suspended/withdrawn ASF authorization.
|
||||
|
||||
CREATE SCHEMA IF NOT EXISTS asf;
|
||||
|
||||
-- ── 1. Authorized entities (insurers, brokers, pension funds, AIFM, UCITS) ──
|
||||
-- One row per distinct ASF register entry. Every entity has a register_no
|
||||
-- (RA-NNN for insurers, RBK-NNN for brokers, etc.) which is globally unique
|
||||
-- per register_type.
|
||||
CREATE TABLE IF NOT EXISTS asf.entitati (
|
||||
id bigserial PRIMARY KEY,
|
||||
register_type text NOT NULL, -- 'asigurator' | 'broker' | 'fond_pensii' | 'aifm' | 'ucits' | 'intermediar_secundar'
|
||||
section_status text NOT NULL, -- 'activ' | 'radiat' (mirrors source sectiune=1/2 split)
|
||||
register_no text NOT NULL, -- e.g. "RA-057", "RBK-123" (unique within register_type)
|
||||
name text NOT NULL, -- raw "Denumire"
|
||||
name_normalized text, -- firms.normalize_company_name(name) — for trigram fallback
|
||||
cui text, -- "Cod unic de identificare (CUI)"
|
||||
cod_rc text, -- "Cod unic RC" (e.g. J40/2226/2006)
|
||||
cod_lei text, -- LEI 20-char
|
||||
nr_autorizatie text, -- "Număr autorizație" (e.g. 114.146)
|
||||
data_autorizare date, -- "Dată autorizare"
|
||||
data_inmatriculare date, -- "Dată înmatriculare"
|
||||
data_radiere date, -- "Dată radiere" (NULL when active)
|
||||
tip_companie text, -- "Tip companie" (Societate de asigurare / Intermediar principal / etc.)
|
||||
forma_juridica text, -- "Formă juridică"
|
||||
adresa text, -- "Adresă"
|
||||
telefon text,
|
||||
fax text,
|
||||
email text,
|
||||
web text,
|
||||
observatii text, -- free-text remarks
|
||||
clase_autorizate jsonb, -- {"asigurari_generale":[...], "asigurari_viata":[...]}
|
||||
conducere jsonb, -- [{"nume":"X","functie":"Y","din":"DD.MM.YYYY"}]
|
||||
raw_html text, -- raw panel HTML for traceability
|
||||
fetched_at timestamptz NOT NULL DEFAULT now(),
|
||||
UNIQUE (register_type, register_no)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_asf_entitati_cui ON asf.entitati(cui) WHERE cui IS NOT NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_asf_entitati_name_norm_trgm ON asf.entitati USING gin (name_normalized gin_trgm_ops);
|
||||
CREATE INDEX IF NOT EXISTS idx_asf_entitati_type_status ON asf.entitati(register_type, section_status);
|
||||
CREATE INDEX IF NOT EXISTS idx_asf_entitati_radiere ON asf.entitati(data_radiere) WHERE data_radiere IS NOT NULL;
|
||||
|
||||
COMMENT ON TABLE asf.entitati IS
|
||||
'ASF authorized entities — insurers, brokers, pension funds, AIFM/UCITS, intermediaries. Source: data.asfromania.ro/scr/ra (and other registers).';
|
||||
COMMENT ON COLUMN asf.entitati.register_type IS
|
||||
'asigurator (RA-NNN) / broker (RBK-NNN) / fond_pensii / aifm / ucits / intermediar_secundar';
|
||||
COMMENT ON COLUMN asf.entitati.section_status IS
|
||||
'activ / radiat — mirrors source sectiune=1/sectiune=2 split. Active record has data_radiere=NULL.';
|
||||
|
||||
-- ── 2. Scrape log (mirrors anre.scrape_log convention) ──────────────────────
|
||||
CREATE TABLE IF NOT EXISTS asf.scrape_log (
|
||||
id bigserial PRIMARY KEY,
|
||||
scraper text NOT NULL, -- 'asigurator_activ' / 'asigurator_radiat' / 'broker_activ' / ...
|
||||
source_url text NOT NULL,
|
||||
rows_seen integer NOT NULL DEFAULT 0,
|
||||
rows_inserted integer NOT NULL DEFAULT 0,
|
||||
rows_updated integer NOT NULL DEFAULT 0,
|
||||
rows_skipped integer NOT NULL DEFAULT 0,
|
||||
duration_ms integer NOT NULL DEFAULT 0,
|
||||
started_at timestamptz NOT NULL,
|
||||
finished_at timestamptz NOT NULL DEFAULT now(),
|
||||
error text
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_asf_scrape_log_started ON asf.scrape_log(started_at DESC);
|
||||
|
||||
-- ── 3. Materialized view: per-CUI ASF rollup ────────────────────────────────
|
||||
-- Joinable with seap.announcements.supplier_cui to detect financial firms
|
||||
-- holding state contracts.
|
||||
CREATE MATERIALIZED VIEW IF NOT EXISTS asf.mv_entitati_per_cui AS
|
||||
SELECT
|
||||
cui,
|
||||
COUNT(*) AS nr_total,
|
||||
COUNT(*) FILTER (WHERE register_type = 'asigurator') AS nr_asigurator,
|
||||
COUNT(*) FILTER (WHERE register_type = 'broker') AS nr_broker,
|
||||
COUNT(*) FILTER (WHERE register_type = 'fond_pensii') AS nr_fond_pensii,
|
||||
COUNT(*) FILTER (WHERE register_type = 'aifm') AS nr_aifm,
|
||||
COUNT(*) FILTER (WHERE register_type = 'ucits') AS nr_ucits,
|
||||
COUNT(*) FILTER (WHERE section_status = 'activ') AS nr_active,
|
||||
COUNT(*) FILTER (WHERE section_status = 'radiat') AS nr_radiate,
|
||||
array_agg(DISTINCT register_type) AS register_types,
|
||||
array_agg(DISTINCT register_no ORDER BY register_no) AS register_numbers,
|
||||
MIN(data_autorizare) AS prima_autorizare,
|
||||
MAX(data_radiere) AS ultima_radiere
|
||||
FROM asf.entitati
|
||||
WHERE cui IS NOT NULL
|
||||
GROUP BY cui;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_asf_mv_entitati_per_cui ON asf.mv_entitati_per_cui(cui);
|
||||
|
||||
COMMENT ON MATERIALIZED VIEW asf.mv_entitati_per_cui IS
|
||||
'Rollup of ASF entities per CUI. Refresh: REFRESH MATERIALIZED VIEW CONCURRENTLY asf.mv_entitati_per_cui';
|
||||
Reference in New Issue
Block a user