Files
Claude VM a6c03a091e 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)
2026-05-13 00:10:32 +03:00

6.4 KiB

ANCOM — Registrul Furnizorilor de Comunicatii Electronice

Status: ingest implementat și aplicat (2026-05-10). Sursă: ANCOM (Autoritatea Națională pentru Administrare și Reglementare în Comunicații) Lege: Legea 159/2010 (registru public, transparență)

Surse

URL listă autorizați (server-rendered HTML, paginat 10/pag, ~57 pag → ~570 furnizori):

https://www.ancom.ro/reglementare-ro/comunicatii-electronice/
  furnizori-comunicatii-electronice/
  lista-furnizorilor-de-retele-si-servicii-de-comunicatii-autorizati/

Pagination: POST paged=N (form id="ms_form").

URL detaliu (per furnizor, ancom_id din lista):

https://www.ancom.ro/sablon/furnizorinew_23/?id={ancom_id}&pid=4186

Pagina de detaliu conține: Denumire, Adresa/Oras/Judet, CUI direct (Cod unic de înregistrare), EUID (Registrul Comerțului), tipuri de retele R1..R11 + servicii S1..S12 cu data nasterii dreptului.

Schema SQL

Fișier: services/seap-scraper/sql/029_ancom.sql

3 tabele + 1 MV:

  • ancom.operatori — flat, PK ancom_id (din URL ?id=N); CUI direct (no fuzzy)
  • ancom.drepturi — long table: 1 rând per (operator, R/S code) cu data_nasterii
  • ancom.scrape_log — mirror la convenția anre.scrape_log
  • ancom.mv_operatori_per_cui — rollup join cu seap.announcements.supplier_cui

Fișiere

Fișier Linii Rol
sql/029_ancom.sql 113 Schema (3 tabele + MV)
src/scrape-ancom.ts ~410 Scraper TS (list paginate + detail HTML parser)
cron/scrape-ancom.sh 73 Wrapper docker + Infisical Machine Identity
cron/match-cui-ancom.sh 175 Stage A+B+C fallback pentru CUI lipsă

Pattern

Identic cu scrape-anre.ts:

  1. Infisical Machine Identity → env-file → docker run --env-file (NEVER -e $VAR)
  2. Idempotent (UPSERT pe ancom_id)
  3. CUI extras direct din pagina de detaliu (<p><strong>Cod unic de înregistrare:</strong> N</p>)
  4. match-cui-ancom.sh rulat după scrape pentru rândurile eventual rămase fără CUI

Knobs

# Smoke (1 pagină = 10 operatori)
sudo MAX_PAGES=1 /opt/vreaudigital/services/seap-scraper/cron/scrape-ancom.sh

# Subset (limit primele N după dedup)
sudo LIMIT=50 /opt/vreaudigital/services/seap-scraper/cron/scrape-ancom.sh

# Full
sudo /opt/vreaudigital/services/seap-scraper/cron/scrape-ancom.sh

# CUI matcher (idempotent, doar NULL-urile)
sudo /opt/vreaudigital/services/seap-scraper/cron/match-cui-ancom.sh

Cross-source recipes — DRAFT

R1: Furnizori telco SEAP fără autorizație ANCOM (red flag)

Furnizori care au câștigat contracte SEAP cu CPV-uri telco (32xx — telecomm equipment, 64xx — postal & telecom services) dar NU sunt în registrul ANCOM de furnizori autorizați. Caz potențial: subcontractare, revânzare, sau activitate care necesită licență dar n-a fost solicitată.

-- Furnizori SEAP cu contracte telco pe ultimii 24 luni dar absent ANCOM
WITH telco_seap AS (
  SELECT
    a.supplier_cui,
    a.supplier_name,
    COUNT(*)               AS nr_contracte,
    SUM(a.value_ron)       AS valoare_totala_ron,
    array_agg(DISTINCT a.cpv_code) FILTER (WHERE a.cpv_code IS NOT NULL) AS cpv_codes
  FROM seap.announcements a
  WHERE a.supplier_cui IS NOT NULL
    AND a.publication_date >= now() - interval '24 months'
    AND (
      a.cpv_code LIKE '32%' OR  -- echipamente telco
      a.cpv_code LIKE '64%' OR  -- servicii postale & telecom
      a.cpv_code LIKE '72400%'  -- internet services
    )
  GROUP BY a.supplier_cui, a.supplier_name
)
SELECT
  t.supplier_cui,
  t.supplier_name,
  t.nr_contracte,
  t.valoare_totala_ron,
  t.cpv_codes,
  -- profil firmă (caen + judet) pentru context
  e.caen_principal,
  e.adr_judet
FROM telco_seap t
LEFT JOIN ancom.mv_operatori_per_cui m ON m.cui = t.supplier_cui
LEFT JOIN firms.entities e ON e.cui = t.supplier_cui
WHERE m.cui IS NULL                    -- ! NU are autorizatie ANCOM
  AND t.valoare_totala_ron > 100000    -- relevant business volume
ORDER BY t.valoare_totala_ron DESC
LIMIT 100;

R2: Furnizori ANCOM autorizați — câți au câștigat contracte publice?

Inversul lui R1. Câți operatori autorizați ANCOM au cel puțin un contract SEAP? Care e concentrarea pe top 10?

SELECT
  m.cui,
  m.nr_autorizatii,
  m.retele,
  m.servicii,
  o_first.titular_name,
  COUNT(a.id)                            AS nr_contracte_seap,
  SUM(a.value_ron)                       AS valoare_seap_ron,
  MIN(a.publication_date)                AS prima_castiga,
  MAX(a.publication_date)                AS ultima_castiga
FROM ancom.mv_operatori_per_cui m
LEFT JOIN LATERAL (
  SELECT titular_name FROM ancom.operatori WHERE titular_cui = m.cui LIMIT 1
) o_first ON TRUE
LEFT JOIN seap.announcements a ON a.supplier_cui = m.cui
GROUP BY 1,2,3,4,5
ORDER BY valoare_seap_ron DESC NULLS LAST
LIMIT 50;

R3: Concentrare pe județe pentru drept S2 (mobil) sau R3 (fibră)

SELECT
  o.judet,
  COUNT(*) FILTER (WHERE d.cod = 'S2')        AS nr_mobil,
  COUNT(*) FILTER (WHERE d.cod = 'R3')        AS nr_fibra,
  COUNT(*) FILTER (WHERE d.cod = 'S1')        AS nr_internet_fix,
  COUNT(DISTINCT o.titular_cui)               AS nr_furnizori_unici
FROM ancom.operatori o
JOIN ancom.drepturi d ON d.ancom_id = o.ancom_id
WHERE o.status = 'autorizat'
GROUP BY 1
ORDER BY nr_furnizori_unici DESC NULLS LAST
LIMIT 25;

Limitări cunoscute

  • Doar lista autorizați este ingest-ată. ANCOM mai publică:
    • lista furnizorilor radiați
    • lista furnizorilor sancționați (suspendare drepturi)
    • lista celor în libertate de prestare (cross-border) Toate folosesc același pattern ?pid={X} și pot fi adăugate ca surse extra cu status='radiat'/'sanctionat'/'cross-border'.
  • data_nasterii per drept e data inițială — ANCOM nu publică data revocării per-drept, doar pe statusul global al furnizorului.
  • ~570 operatori / scrape ~3 min cu sleep 150ms per detail. Rulare lunară e suficientă; date public oarecum statice.

Next steps

  1. Ingest autorizați ✓ DONE
  2. Adaugă scrape-ancom-radiati.ts (sursa: lista furnizorilor radiați, pid=4318 sau similar)
  3. Crează recipe cross-source furnizori_telco_neautorizati în src/lib/recipes.ts (NU eu — exclusion zone) — pattern listat la R1 mai sus
  4. Pagină profil pe /registru/ancom/[cui] (similar cu beneficiar-privat) — NU eu
  5. CUI matcher cron lunar — adaugă în refresh-mvs.sh sau systemd timer dedicat