# Jurnal de audit

Ce urme lasă platforma la fiecare schimbare importantă, în ce tabel, cu ce câmpuri, cine le poate citi și cât timp rămân.

## Pe scurt

Platforma nu are un singur „jurnal de audit”. Are mai multe tabele, fiecare pentru un fel de schimbare. Toate au același principiu: urma se scrie **în aceeași tranzacție** cu schimbarea, iar aplicația poate doar să adauge rânduri, nu să le modifice sau să le șteargă.

| Tabel | Ce înregistrează | Cine scrie | Se citește din aplicație |
| --- | --- | --- | --- |
| `acces_audit` | drepturi, roluri, oameni noi, parole resetate de administrator | modulul `acces` și funcțiile SQL ale contului | nu: nicio rută nu îl citește |
| `events` | orice schimbare la produse, categorii, starea zilei, firme | triggere pe tabele și modulul `meniu` | da, `GET /v1/evenimente` |
| `jurnal_parole` | orice schimbare a parolei unui cont | trigger pe `conturi` | nu: aplicația nu are drept de citire |
| `seif_jurnal` | cine a deschis o intrare din seif și când | modulul seifului | nu: aplicația are doar `select, insert` |
| `zi_jurnal` | acțiunile zilei (oprire de produs, export) | modulul `meniu` | prin exportul zilei |
| `urme_client` | ce face omul în pagină (clic, filtru, export, erori de formular) | `POST /v1/prezenta/urme` | nu: nicio rută nu îl citește |
| `alerte_istoric` | alertele trimise firmei | importul din platforma veche | da, `GET /v1/eu/notificari/istoric` |
| `agenti_istoric` | rapoartele agenților automați | `POST /v1/agenti/lucru` | da, ultimele 20 pe agent |
| `jurnal_live` | ce au făcut verificările, colectorii și executorii | executorii, prin `POST /v1/jurnal-live` | da, doar `admin`, ultimele 400 |

## Drepturi și conturi: `acces_audit`

Fiecare schimbare de acces lasă un rând. Nu există schimbare fără urmă: scrierea rândului și schimbarea sunt în aceeași tranzacție.

| Câmp | Ce conține |
| --- | --- |
| `firma_id` | firma în care s-a făcut schimbarea |
| `cine` | contul care a făcut schimbarea |
| `actiune` | una din lista de mai jos |
| `tinta` | contul sau rolul atins (cel mult 100 de caractere) |
| `inainte`, `dupa` | valoarea veche și cea nouă, ca text |
| `creat_la` | momentul scrierii |

Acțiunile permise de constrângerea din baza de date:

| Acțiune | Când apare |
| --- | --- |
| `acces.setat` | accesul unui om pe firmă a fost oprit sau redat |
| `rol.setat` | rolul unui om s-a schimbat |
| `drepturi_rol.setate` | setul de drepturi al unui rol s-a schimbat |
| `om.creat` | un om nou a fost adăugat în firmă (direct sau prin invitație acceptată) |
| `rol_personalizat.creat` | un rol nou al firmei |
| `rol_personalizat.setat` | paginile unui rol personalizat s-au schimbat |
| `drepturi_cont.setate` | drepturile proprii ale unui om s-au schimbat |
| `parola.resetata` | administratorul a pus o parolă temporară |

> [!WARNING]
> Două acțiuni nu lasă rând în `acces_audit`: **ștergerea unui rol personalizat** (lista de acțiuni nu are o acțiune de ștergere) și **resetarea parolei prin email**, făcută de om singur. Resetarea prin email ajunge doar în jurnalul aplicației, ca rând `audit: parola resetata`. Schimbarea parolei rămâne oricum în `jurnal_parole`.

Politicile RLS lasă doar citirea și adăugarea pe firma din sesiune. Aplicația nu are drept de ștergere sau de modificare pe acest tabel.

## Schimbările de date: `events`

Fiecare `INSERT`, `UPDATE` sau `DELETE` pe produse, categorii și starea zilei scrie automat în `events`, printr-un trigger. La o modificare se scrie **un rând pe câmp schimbat**, cu valoarea veche și cea nouă. Colecția `firme` a fost adăugată ulterior.

| Câmp | Ce conține |
| --- | --- |
| `seq` | numărul crescător al evenimentului |
| `colectie` | `produse`, `categorii`, `stari_zi` sau `firme` |
| `id`, `camp` | obiectul și câmpul schimbat |
| `inainte`, `dupa` | valorile, în JSON |
| `cine` | cine a făcut schimbarea (`necunoscut` dacă lipsește din conexiune) |
| `sursa` | `platforma`, `dls`, `poller`, `import` sau `executor` |
| `la` | momentul schimbării |

Fluxul se citește în timp real, cu reluare de unde ai rămas: vezi [Fluxul de evenimente](#evenimente). Aplicația nu poate modifica, șterge sau goli tabelul.

## Parolele: `jurnal_parole`

Un trigger pe `conturi` scrie un rând de fiecare dată când se schimbă hash-ul parolei, oricare ar fi calea:

- `cont_id`: contul atins;
- `actor` și `actor_efectiv`: rolul bazei de date care a făcut schimbarea și proprietarul funcției care a rulat-o;
- `cale`: calea declarată de API sau, în lipsa ei, numele aplicației conectate;
- `ip`: adresa trimisă de API sau adresa conexiunii;
- `la`: momentul.

Tabelul nu păstrează niciun hash, nici vechi, nici nou. O eroare la scrierea în jurnal nu blochează niciodată schimbarea parolei. Accesul public la tabel este retras, iar aplicația nu primește drept de citire.

## Celelalte urme

- **`seif_jurnal`**: intrarea din seif, contul care a deschis-o (`cine`) și momentul (`la`). Citirile interne făcute de module pe server nu lasă rând.
- **`zi_jurnal`**: acțiunile zilei, în forma în care le scrie exportul (`intrare` în JSON, cel mult 4096 de octeți), cu produsul, autorul și data. Numai adăugare.
- **`urme_client`**: urmele din pagină sosesc în loturi. Tipurile și cheile sunt pe o listă albă în cod (`clic`, `filtru`, `export`, `formular_eroare`, `perf`, `push_afisat` și altele), deci nu există câmp pentru text liber tastat de om. Numai adăugare și citire pe firmă.
- **`alerte_istoric`**: un rând pe alertă (tip, titlu, text, adresă, momentul). Cine ce alertă vede nu se păstrează aici. Se calculează la citire, după drepturile de acum.
- **`agenti_istoric`**: un rând pe raportul unui agent (agent, etichetă, oră, text). Din 0243 are RLS pe firmă. Rândurile vechi fără firmă rămân în tabel, dar aplicația nu le mai vede.
- **`jurnal_live`**: categoria, nivelul (`info`, `ok`, `avertisment`, `eroare`), mesajul (cel mult 400 de caractere) și procesul. Textul trece printr-un filtru de secrete înainte de scriere.

## Cine le vede

| Cine | Ce vede |
| --- | --- |
| orice om cu sesiune | fluxul `events` al firmei, propriile alerte, istoricul comenzilor de catering și al agenților, după drepturile paginii |
| `admin` | în plus, `jurnal_live` |
| nimeni din aplicație | `acces_audit`, `jurnal_parole`, `seif_jurnal`, `urme_client` |

Toate tabelele de mai sus, cu excepția `jurnal_parole`, sunt izolate pe firmă prin RLS: o firmă nu poate citi urmele alteia (vezi [Securitate](#securitate)).

## Cât se păstrează

Codul platformei nu are nicio ștergere programată și niciun termen de păstrare pentru aceste tabele. Pentru aplicație, `events`, `acces_audit`, `alerte_istoric`, `zi_jurnal` și `urme_client` sunt doar de adăugare. Rândurile rămân până la o intervenție făcută direct pe baza de date.

> [!NOTE]
> Singurele limite sunt cele de citire: 20 de rapoarte pe agent, 400 de rânduri în Jurnal live și un rând pe grup în istoricul alertelor. Rândurile mai vechi rămân în tabel.
