SAD.peviitor.ro

Software Architecture Design — Documentație Arhitecturală

v1.0 — Iunie 2026

Motor de căutare a locurilor de muncă din România

Platforma agregează joburi din peste 100 de surse (site-uri de carieră, ANAFM, companii direct) și le pune la dispoziție printr-un search engine full-text alimentat de Apache SOLR, cu un API BFF în PHP și o interfață web în React.

⁠▼️ Prezentare Generală

Scop

Acest document descrie arhitectura software a platformei peviitor.ro — un motor de căutare a locurilor de muncă din România.

Domeniu

Sistemul acoperă: colectarea automată a datelor (scraping), validarea, indexarea full-text în Apache SOLR, expunerea printr-un API BFF și interfața web React.

Componente principale

ComponentăURL
Platforma livepeviitor.ro
API (BFF)api.peviitor.ro
SOLR (search)solr.peviitor.ro
Admin/Validatoradmin.peviitor.ro
Testtest.peviitor.ro

⁠🏗️ Context View (C4 Level 1)

Diagrama de context arată interacțiunile dintre utilizatori, frontend, API, SOLR și scrapere:

                     +-------------------+
                     |   Cautator de     |
                     |   munca (Browser) |
                     +--------+----------+
                              |
                         HTTPS (peviitor.ro)
                              |
                     +--------v----------+
                     |   search-engine   |
                     |  (React + Vite)   |
                     +--------+----------+
                              |
                      HTTPS (api.peviitor.ro)
                              |
                      +--------v----------+
                      |   API (BFF) v1    |
                      |  PHP 8.x, RPi 5   |
                      |    (4GB RAM)      |
                      +--------+----------+
                               |
                     HTTP (192.168.1.x:8983)
                     Basic Auth (LAN)
                               |
                      +--------v----------+
                      |  Apache SOLR 10.x |
                      |  RPi 5 (16GB RAM) |
                      +--------+----------+
                              ^
                              |
               +--------------+--------------+
               |              |              |
      +--------v------+ +----v------+ +-----v--------+ +------------------+
      | Scrapers (Py) | | JMeter    | | ANOFM         | | Scrapers (Node)  |
      | GitHub Action | | Scraper   | | Scraper       | | JS / TypeScript  |
      +---------------+ +-----------+ +---------------+ +------------------+

Stakeholders

Căutători de locuri de muncă

Interfață rapidă, căutare relevantă, date corecte

Contributori open-source

Scrapers, bug fixes, features

QA Team

Validare date, testare automată

Administrator platformă

Monitorizare, mentenanță, securitate

⁠🖥️ Deployment View

Infrastructură hardware

+-------------------------------------------------------------+
|                        Acasa / RCS&RDS                       |
|                                                              |
  |  +------------------+    +-----------------------+          |
  |  | Router TP-Link   |    | RPi 5 (4GB) — API     |          |
  |  | 192.168.1.1      |    | 192.168.1.135         |          |
  |  | Ethernet 1 Gbps  +----+ Nginx Proxy :80/443   |          |
  |  | DDNS:            |    | Nginx UI :81          |          |
  |  | zimbor.go.ro     |    | PHP BFF :8080         |          |
  |  |                  |    +-----------------------+          |
|  |                  |    +------------------------+          |
|  |                  +----+ RPi 5 (16GB) — SOLR    |          |
|  |                       | 192.168.1.134          |          |
|  |                       | Docker solr:10-slim    |          |
|  |                       | SOLR :8983             |          |
|  +--------+---------+    +------------------------+          |
|           |                                                   |
+-----------|---------------------------------------------------+
            | Internet (NAT)
            |
    +-------v--------+
    |  IP Public      |
     |  86.122.35.88   |
    +-----------------+
            |
    +-------v--------+
    |  Frontend       |
    |  (GitHub Pages) |
    +-----------------+

API Server — RPi 5 (4GB)

ModelRaspberry Pi 5 Model B Rev 1.0
SoCBroadcom BCM2712 (Cortex-A76, 4 cores)
RAM4 GB LPDDR4X
StocaremicroSD 59.4 GB (31 GB liberi)
OSDebian 12 (Bookworm), kernel 6.12.87
Rețeaeth0: 192.168.1.135/24
Dockerphp:8.3-apache (API), orase-api, nginx-proxy-manager
MonitoringNetdata v2.10.0, solr-monitor (Discord)

SOLR Server — RPi 5 (16GB)

ModelRaspberry Pi 5 Model B Rev 1.1
CPUARM Cortex-A76, 4 cores @ 2.4 GHz
RAM16 GB LPDDR4X + 16 GB swap + 2 GB zram
StocaremicroSD 64 GB (33 GB folosiți)
OSDebian 13 (Trixie), kernel 6.18.29
Rețeaeth0: 192.168.1.134/24
Dockersolr:10-slim (port 8983)
RuntimePython 3.13.5, Node.js v24.16.0, GCC 14.2.0

⁠🚀 API BFF — api.peviitor.ro

API-ul BFF (Backend for Frontend) este scris în PHP 8.3 și rulează într-un container Docker php:8.3-apache pe portul 8080, expus public prin Nginx Proxy Manager.

Endpoint-uri v1

EndpointMetodăDescriere
/v1/searchGETCăutare full-text
/v1/jobsGETListare joburi
/v1/companiesGETListare companii
/v1/companyGETDetalii companie
/v1/totalGETNumăr total joburi
/v1/suggestGETAutocomplete sugestii
/v1/randomGETJoburi aleatoare
/v1/healthGETStatus sănătate
EndpointMetodăDescriere
/v1/firmeGETFirme
/v1/addPOSTAdăugare documente
/v1/updatePUTActualizare documente
/v1/cleanjobsDELETECurățare joburi expirate
/v1/emptyDELETEGolire core

Flux căutare

  1. Normalizare query (diacritice → ASCII)
  2. Construire SOLR query (edismax, fq, bq, sort)
  3. Fetch de la http://192.168.1.134:8983/solr/job/select
  4. Mapare câmpuri SOLR → API response
  5. Return JSON

Monitorizare

Conexiunea la SOLR se face prin Basic Auth pe LAN. CORS este restricționat la domenii cunoscute. API-ul are integrare Sentry pentru error monitoring.

Linkuri utile:

⁠🔍 Apache SOLR Index — solr.peviitor.ro

Apache SOLR 10.x rulează în container Docker solr:10-slim pe RPi 5 (16GB), cu autentificare Basic Auth configurată prin security.json.

Core: job (locuri de muncă)

FieldTipStocatIndexatMultiValuedRequired
urlstringDA (uniqueKey)
titletext_general
companystring
cifstring
locationtext_general
workmodestring
statusstring
salarytext_general
datepdate
vdatepdate
expirationdatepdate
tagstext_general

Status Flow (Job)

scraped -> tested -> published
scraped -> verified -> published
  • scraped — abia colectat, nevalidat
  • tested — URL funcțional, dar date incomplete
  • verified — complet, toate câmpurile extrase
  • published — importat în indexul principal

Validare URL & Expirare

Joburile cu expirationdate < NOW() sunt șterse automat (cron zilnic 02:00). Validarea URL se face prin HEAD requests paralele (max 1000 concurrent) — 404 → DELETE, conținut invalid → tested.

⁠🎨 Frontend — search-engine (React)

Tech Stack

FrameworkReact 18
State ManagementRedux Toolkit + redux-thunk
Routingreact-router-dom v6
StylingTailwind CSS 3 + shadcn/ui (Radix)
BuildVite 5
MonitoringSentry
AnalyticsMicrosoft Clarity
DeployGitHub Pages

Structură src/

src/
  components/   -> UI (shadcn/ui + custom)
  context/      -> React context providers
  pages/        -> Search, JobDetail, etc.
  reducers/     -> Redux slices
  lib/          -> Utility library
  utils/        -> Helpers
  assets/       -> Statics (SVG, images)
  store.js      -> Redux store config
  App.jsx       -> Root component + routes
  index.jsx     -> Entry point

⁠📈 Scrapers & Data Pipeline

Sursa (site companie)
    | (Python/Scrapy/JMeter)
    v
GitHub Actions (cron zilnic)
    |
    v
Script de upload (upload_to_solr.sh)
    |
    v
SOLR index (job core)
    |
    v (cron daily 06:00)
Validare URL-uri (HEAD requests)
    |
    v (cron daily 02:00)
Stergere joburi expirate (expirationdate < NOW())

Scrapers

Scriși în Python/Scrapy, NodeJS/JS, sau Apache JMeter. Rulează prin GitHub Actions în repo-uri separate (inclusiv pe conturi externe) pentru paralelism maxim.

scraper.peviitor.ro

Validare Automată

HEAD requests paralele verifică zilnic URL-urile. 404 → DELETE, conținut invalid → retestat.

Cron: 06:00

Curățare Expirate

Joburile cu expirationdate < NOW() sunt șterse automat. Expirare: vdate + max 30 zile.

Cron: 02:00

⁠📝 Architectural Decision Records (ADR)

IDDecizieRațional
ADR-001SOLR pe RPi 5 (16GB)Cost zero, consum mic, suficient pentru ~50k joburi
ADR-002PHP BFF pe RPi 5 separat (4GB)Separarea API de SOLR îmbunătățește securitatea și izolarea
ADR-003PHP BFF (nu API direct SOLR)Izolare, normalizare query/response, Basic Auth ascuns
ADR-004React + Redux + VitePerformanță, ecosistem matur, tooling modern
ADR-005DDNS zimbor.go.roIP dinamic RCS&RDS; DDNS asigură acces extern
ADR-006Scrapers în repo-uri separateParalelism, mentenabilitate, contribuții distribuite
ADR-007edismax + copyField _text_Căutare full-text pe multiple câmpuri simultan
ADR-008Status flow scraped→verified→publishedPipeline de calitate înainte de publicare

⁠🛢 Testare

Strategia de testare este definită integral în documentul separat: Test Strategy — peviitor.ro.

Arii de testare

Frontend

Testare manuală exploratorie + Playwright E2E + testare vizuală

API

Validare endpoint-uri în Swagger UI + Postman/Bruno + PHPUnit

SOLR Index

Conformitate schemă, căutare diacritice, CRUD, facet search

Validare date

Status flow, câmpuri obligatorii, matching companii

Cross-component

Integrare Frontend ↔ API ↔ SOLR ↔ Scrapers

Non-functional

Performanță (P95 < 2s), Securitate (OWASP Top 10), Accesibilitate (WCAG 2.2 AA)

Medii de testare

MediuURLScop
Localhttp://localhost:3000Dezvoltare, unit testing (Docker)
Testtest.peviitor.roIntegrare, UAT, regresie
Producțiepeviitor.roLive

KPI

≥95%
Test Pass Rate
≥80%
Automation Coverage
≤3
Defect Escape Rate / trim.
<2s
Search Response Time (P95)

Bug Lifecycle

[New] → [Assigned] → [In Progress] → [Fixed] → [Verified] → [Closed]

Bug severity: S1 (Blocker) → S4 (Trivial). Triaj zilnic; S1/S2 rezolvate în < 4h.

Tool-uri

Playwright, Postman/Bruno, PHPUnit/Jest/Vitest, Apache JMeter, k6, OWASP ZAP, axe DevTools/WAVE, TestLink, GitHub Issues.

⁠⚠️ Riscuri și Compromisuri

RiscImpactMitigare
Single point of failure (2 RPi-uri)API și/sau SOLR indisponibileBackup config; scripturi de restore rapide
Stocare microSDFiabilitate redusă, uzurăMonitoring health; backup zilnic
IP dinamic RCS&RDSPierdere conexiune externăDDNS cu TTL scăzut; fallback manual
Fără replică SOLRPierdere date la defecțiuneBackup configurabil; rebuild din scrapers
Dependență GitHub ActionsScrapers nu rulează fără GitHubSelf-hosted runner ca alternativă

⁠💻 Tehnologii Utilizate

TehnologieRolVersiune
Apache SOLRSearch & indexare10-slim (Docker)
PHPAPI BFF8.x
ReactFrontend UI18.x
Redux ToolkitState management2.x
ViteBuild tool5.x
Tailwind CSSStyling3.x
shadcn/ui (Radix)Componente UI-
Python / ScrapyWeb scraping3.x
Apache JMeterWeb scraping5.x
SentryError monitoring-
NetdataMonitoring infrastructură2.10.0
Microsoft ClarityUser analytics-
DockerContainerizare-
Debian LinuxOS (RPi)12 / 13
Nginx / ApacheReverse proxy-
PlaywrightTestare E2E-
PHPUnit / Jest / VitestTestare unitară-
k6Testare de performanță-
OWASP ZAPTestare de securitate-
GitHub ActionsCI/CD, scrapers-

⁠📖 Glosar

TermenDefiniție
BFFBackend for Frontend — API care servește specific unui client (frontend)
SOLRPlatformă de căutare full-text open-source (Apache Lucene)
CoreIndex SOLR (echivalentul unui tabel în DB)
edismaxQuery parser SOLR care permite boost și câmpuri multiple
BFF APIAPI-ul PHP (v1) care face proxy între frontend și SOLR
ScraperScript care extrage automat date de pe site-uri externe
DDNSDynamic DNS — serviciu care actualizează DNS-ul pentru IP-uri dinamice
CIF/CUICodul de Identificare Fiscală al companiilor din România
vdateVerified date — data la care un job a fost verificat
ANAFAgenția Națională de Administrare Fiscală