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:
Claude VM
2026-05-13 00:10:32 +03:00
commit a6c03a091e
352 changed files with 75295 additions and 0 deletions
+189
View File
@@ -0,0 +1,189 @@
-- SEAP Data Schema for Harta Banilor Publici
-- Runs inside architools_db, isolated in schema "seap"
-- ZERO modifications to existing public.* tables
BEGIN;
-- Enable extensions needed for fuzzy matching
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS unaccent;
CREATE SCHEMA IF NOT EXISTS seap;
-- ── Entități SEAP (autorități contractante + furnizori) ──
CREATE TABLE seap.entities (
entity_id INTEGER PRIMARY KEY,
entity_type TEXT NOT NULL CHECK (entity_type IN ('authority', 'supplier')),
fiscal_number TEXT,
name TEXT NOT NULL,
city TEXT,
county TEXT,
address TEXT,
postal_code TEXT,
is_utility BOOLEAN,
siruta TEXT REFERENCES public."GisUat"(siruta),
match_score REAL,
fetched_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_entities_fiscal ON seap.entities(fiscal_number);
CREATE INDEX idx_entities_siruta ON seap.entities(siruta);
CREATE INDEX idx_entities_type ON seap.entities(entity_type);
CREATE INDEX idx_entities_county ON seap.entities(county);
-- ── Achiziții directe ──
CREATE TABLE seap.direct_acquisitions (
id INTEGER PRIMARY KEY,
unique_code TEXT UNIQUE,
name TEXT,
cpv_code TEXT,
cpv_name TEXT,
publication_date TIMESTAMPTZ,
finalization_date TIMESTAMPTZ,
estimated_value NUMERIC(15,2),
closing_value NUMERIC(15,2),
currency TEXT DEFAULT 'RON',
state_id INTEGER,
state_text TEXT,
contract_type_id INTEGER,
contract_type_text TEXT,
eu_fund_id INTEGER,
eu_fund_text TEXT,
authority_id INTEGER REFERENCES seap.entities(entity_id),
supplier_id INTEGER REFERENCES seap.entities(entity_id),
fetched_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_da_authority ON seap.direct_acquisitions(authority_id);
CREATE INDEX idx_da_supplier ON seap.direct_acquisitions(supplier_id);
CREATE INDEX idx_da_finalization ON seap.direct_acquisitions(finalization_date);
CREATE INDEX idx_da_publication ON seap.direct_acquisitions(publication_date);
CREATE INDEX idx_da_cpv ON seap.direct_acquisitions(cpv_code);
CREATE INDEX idx_da_value ON seap.direct_acquisitions(closing_value);
-- ── Licitații publice (contract award notices) ──
CREATE TABLE seap.public_notices (
id INTEGER PRIMARY KEY,
notice_no TEXT,
contract_title TEXT,
cpv_code TEXT,
cpv_name TEXT,
estimated_value NUMERIC(15,2),
contract_value NUMERIC(15,2),
currency TEXT DEFAULT 'RON',
publication_date TIMESTAMPTZ,
state_date TIMESTAMPTZ,
procedure_type_id INTEGER,
procedure_type_text TEXT,
contract_type_id INTEGER,
contract_type_text TEXT,
notice_type_id INTEGER,
state_id INTEGER,
state_text TEXT,
authority_id INTEGER REFERENCES seap.entities(entity_id),
authority_city TEXT,
authority_county TEXT,
authority_siruta TEXT REFERENCES public."GisUat"(siruta),
has_lots BOOLEAN DEFAULT false,
fetched_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_pn_authority ON seap.public_notices(authority_id);
CREATE INDEX idx_pn_date ON seap.public_notices(publication_date);
CREATE INDEX idx_pn_siruta ON seap.public_notices(authority_siruta);
CREATE INDEX idx_pn_cpv ON seap.public_notices(cpv_code);
-- ── Contracte câștigate (din section 5 a licitațiilor) ──
CREATE TABLE seap.notice_contracts (
id SERIAL PRIMARY KEY,
notice_id INTEGER REFERENCES seap.public_notices(id),
lot_number INTEGER,
lot_title TEXT,
contract_value NUMERIC(15,2),
currency TEXT DEFAULT 'RON',
contract_date DATE,
winner_id INTEGER REFERENCES seap.entities(entity_id),
winner_name TEXT,
winner_fiscal TEXT,
winner_city TEXT,
winner_county TEXT,
winner_siruta TEXT REFERENCES public."GisUat"(siruta),
num_offers INTEGER
);
CREATE INDEX idx_nc_notice ON seap.notice_contracts(notice_id);
CREATE INDEX idx_nc_winner ON seap.notice_contracts(winner_id);
CREATE INDEX idx_nc_winner_siruta ON seap.notice_contracts(winner_siruta);
-- ── Matching localități SEAP → SIRUTA ──
CREATE TABLE seap.locality_map (
seap_city TEXT NOT NULL,
seap_county TEXT NOT NULL,
siruta TEXT REFERENCES public."GisUat"(siruta),
match_type TEXT,
confidence REAL,
PRIMARY KEY (seap_city, seap_county)
);
-- ── Stare sync scraper ──
CREATE TABLE seap.sync_state (
source TEXT PRIMARY KEY,
last_date TIMESTAMPTZ,
last_id INTEGER,
status TEXT,
updated_at TIMESTAMPTZ DEFAULT now()
);
INSERT INTO seap.sync_state (source, status) VALUES
('da', 'pending'),
('notices', 'pending');
-- ── Helper: normalize locality names ──
CREATE OR REPLACE FUNCTION seap.normalize_locality(input TEXT)
RETURNS TEXT LANGUAGE sql IMMUTABLE AS $$
SELECT lower(trim(unaccent(
regexp_replace(input, '\s+', ' ', 'g')
)));
$$;
-- ── Materialized view: procurement stats per UAT ──
CREATE MATERIALIZED VIEW seap.uat_procurement_stats AS
SELECT
u.siruta,
u.name AS uat_name,
u.county,
COALESCE(da_stats.da_count, 0) AS da_count,
COALESCE(da_stats.da_total_value, 0) AS da_total_value,
COALESCE(pn_stats.notice_count, 0) AS notice_count,
COALESCE(pn_stats.notice_total_value, 0) AS notice_total_value,
COALESCE(da_stats.da_count, 0) + COALESCE(pn_stats.notice_count, 0) AS total_contracts,
COALESCE(da_stats.da_total_value, 0) + COALESCE(pn_stats.notice_total_value, 0) AS total_value
FROM public."GisUat" u
LEFT JOIN LATERAL (
SELECT
COUNT(*) AS da_count,
SUM(da.closing_value) AS da_total_value
FROM seap.direct_acquisitions da
JOIN seap.entities e ON e.entity_id = da.authority_id
WHERE e.siruta = u.siruta
) da_stats ON true
LEFT JOIN LATERAL (
SELECT
COUNT(*) AS notice_count,
SUM(pn.contract_value) AS notice_total_value
FROM seap.public_notices pn
WHERE pn.authority_siruta = u.siruta
) pn_stats ON true;
CREATE UNIQUE INDEX idx_ups_siruta ON seap.uat_procurement_stats(siruta);
COMMIT;