Files
roagest/CLAUDE.md

172 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## What this is
ROAGEST is a **Visual FoxPro 9** desktop application (Romanian-language) for **gestiune de stocuri și mărfuri** — goods/inventory management: purchases (`achiziție`, NIR — *notă intrare recepție*), sales, warehouse transfers, stock (`stoc`), consumption vouchers (`bon consum`), inventory counts (`inventar`), price changes (`schimbare preț`), and cash-register (`casă de marcat`, e500/mp500) integration. It backs onto an **Oracle** database (`gcS` schema, default `CONTAFIN`) reached through the shared `goExecutor`/`goConn` SQL pass-through objects. It is one member of the larger "ROA" suite built by ROA Romfast SRL (ROAACNPRO, ROAIMOB, ROACONT, ROACASA, ROADEF, etc.) and lives alongside its siblings under `D:\ROA`.
The code, comments, menus, and changelog are all in Romanian — match that language when editing user-facing strings, comments, and changelog entries.
**Architecturally, ROAGEST is older-generation than ROAACNPRO/ROAIMOB**: those apps instantiate `oApp` as a subclass of the shared `RoaApp` framework class (`COMUN/programe/roa.prg`) with an ordered `initializeaza*` method pipeline. ROAGEST does **not** use `RoaApp` at all — `COMUN/programe/roa.prg` exists in this repo (vendored, shared with the other apps) but is unreferenced. Instead, `Programe/roagest.prg` is a long, monolithic startup script that manually chains `SET PATH`/`SET CLASSLIB ... ADDITIVE`/`SET PROCEDURE ... ADDITIVE` statements and instantiates `goApp = CREATEOBJECT("wzApplication")` — the classic VFP "Application Wizard" base class (defined in `COMUN/clase/appwiz.vcx`). Don't assume the `RoaApp`/`initializeaza*` conventions documented for ROAACNPRO/ROAIMOB apply here.
## Build, run, version control
- **Build/run requires the Visual FoxPro 9 IDE on Windows.** There is no command-line build. Open `roagest.pjx` in the VFP IDE and use *Project > Build* to produce `roagest.exe`. The startup program is `Programe/roagest.prg`.
- **`.prg` files are source; `.fxp`/`.FXP` are compiled, `.BAK` are backups.** Edit the `.prg`. The `.scx/.sct` (forms), `.vcx/.vct` (class libraries), `.frx/.frt` (reports), and `.mnx/.mnt`/`.mpr` (menus) are VFP binary/generated artifacts — **edit them in the VFP IDE, not by hand.** `.mpr`/`.mpx` are GENMENU-generated from `.mnx`; never hand-edit them.
- **SVN remains the "live" source of truth**, especially for `COMUN/` — use `svn`, not `git`, for the authoritative history. A **git** repo now runs in parallel (see "Version control: git alongside SVN" below).
- **`config.fpw`** sets the runtime environment (`CODEPAGE=1252`, `EXCLUSIVE=OFF`, `SAFETY=OFF`, `MULTILOCKS=ON`, `TALK=OFF`). Don't enable `SAFETY` — the code relies on silent overwrite. `Programe/roagest.prg` re-asserts most of these plus `SET DATE TO DMY`, `SET DECIMALS TO 4`, `SET EXACT ON`.
- `roagest.exe` refuses to start unless its own filename matches `gcNumeProgram = 'ROAGEST'` (`IF !LIKE(gcNumeProgram + '*', ...)` near the top of `roagest.prg`) — a guard against running a renamed/copied executable.
- The compiler error log is `roagest.ERR`; the runtime log is `log.txt`. `roagest.Stats` and `versiune_db.txt` (format `YYYY_MM_DD_NN`, e.g. `2026_01_21_02`) track build/DB-schema stamps checked against the update server on launch (`COMUN/programe/oupdate.prg`, `wwcodeupdate.prg`).
- `Programe/cont2000.prg` is a near-duplicate of `roagest.prg` (same startup pattern, older `CONT2000` naming) still present in the tree — treat it as legacy/reference, not the active entry point, unless you confirm otherwise from `roagest.pjx`'s main-file setting.
## Version control: git alongside SVN
Git rulează în paralel cu SVN-ul legacy, nu îl înlocuiește. SVN rămâne sursa "vie" pentru `COMUN/`, sincronizat manual către git; nu rula comenzi `svn` din git și nu presupune că git-ul e la zi cu ultimele modificări SVN dacă nu a fost sincronizat explicit.
- Repo-ul principal (rădăcina acestui folder) e propriul lui `.git`, cu remote `git@gitea.romfast.ro:romfast/roagest.git`. `.gitignore` exclude `COMUN/` (gestionat separat, vezi mai jos), `.svn/`, artefactele VFP compilate (`*.fxp`, `*.bak`, `*.mpr`, `*.exe`, …) și fișierele Windows uzuale.
- `COMUN/` are propriul `.git` separat, cu remote `git@gitea.romfast.ro:romfast/comun.git`**același repo partajat de toate aplicațiile ROA** (ROAACNPRO, ROAIMOB, etc.). O modificare împinsă acolo afectează toate proiectele. Nu face `push --force` peste `comun.git` fără aprobare explicită — ar șterge istoric comun tuturor proiectelor.
- Căutarea în cod VFP binar (`.vcx`/`.scx`) pentru acest proiect folosește `vcx2txt.ps1` parametrizat pentru ROAGEST (vezi secțiunea de mai jos) — cache separat, `D:\ROA\_vfp_textcache\roagest`, nu-l amesteca cu cache-urile altor proiecte.
## Searching code inside `.vcx`/`.scx` (binary) libraries
Most class/form code lives **inside binaries** (`.vcx`+`.vct`, `.scx`+`.sct`, …), not in `.prg`, so plain grep can't read it cleanly. To search method/procedure bodies, convert the binaries to their TEXT form first and grep the text, using the shared `foxbin2prg` tool already built at `D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE`:
```powershell
& 'D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1' -Project 'D:\ROA\ROAGEST\roagest.pjx' -ProjectRoot 'D:\ROA\ROAGEST' -CacheRoot 'D:\ROA\_vfp_textcache\roagest' -Types vcx,scx,frx,mnx
```
This reads the file list straight from `roagest.pjx`, so it only converts the `.vcx`/`.scx`/`.frx`/`.mnx` this project actually references — not all of `COMUN\` (most of which is unused by any one app). It's incremental and safe to re-run after IDE edits. Output lands in `D:\ROA\_vfp_textcache\roagest\` as `.vc2`/`.sc2`/`.fr2`/`.mn2` text mirrors — `Grep` those.
For `.vcx`/`.scx`, code edits no longer require the VFP IDE — the flow is now:
1. Refresh the cache (`vcx2txt.ps1` above), especially if a VFP IDE session ran since the last refresh (IDE changes make the cache stale).
2. Edit the `.vc2`/`.sc2` text directly (position-sensitive format — don't reflow lines; properties are alphabetized).
3. Review the diff on the text file like any other source change.
4. Write back with `txt2vcx.ps1` (`D:\ROA\UTIL\foxbin2prg\txt2vcx.ps1 -TextFile <path\to\file.vc2> -ProjectRoot 'D:\ROA\ROAGEST' -CacheRoot 'D:\ROA\_vfp_textcache\roagest'`) — it regenerates and recompiles the binary in a staging folder, fidelity-checks it against the edited text, then copies it into the project only if that check passes.
`.mnx`/`.frx` stay **read-only** in this flow (menus still need GENMENU in the IDE; reports are too fragile to round-trip) — edit those in the VFP IDE as before. Targets under `COMUN\` need `-AllowComun` plus explicit approval, since a change there affects every ROA app. See `D:\ROA\UTIL\foxbin2prg\CLAUDE.md` for full details and `COMUN\docs\flux-editare-vfp-text.md` for the shared per-round workflow (baseline backups, review patches, fidelity check) plus the per-project parameters (including ROAGEST's).
## The COMUN shared framework
`COMUN/` is **shared, framework-level code used by every ROA app** — it is not specific to ROAGEST. Treat it as a vendored library:
- A change in `COMUN/` affects all ROA applications. Prefer making app-specific changes in this repo's top-level `Programe/`, `Clase/`, `Ferestre/`, `Meniuri/`, `Rapoarte/` directories. Only touch `COMUN/` when the fix genuinely belongs to the shared framework.
- Unusually for this app, **most of the actual "gestiune" business logic lives in `COMUN/programe/`, not in this repo's own `Programe/`.** ROAGEST's own `Programe/` folder has only ~24 files (`roagest.prg`, `gestiuni.prg`, `cont2000.prg`, `oimportdinxml.prg`, `ofactureaza.prg`, `exportare.prg`, `fisa_ob_inventar.prg`, `update_nomenclator.prg`, `suma_in_vorbe.prg`, `actualizari.prg`, `cumplun-furn.prg`, `inchidere_k.prg`, `ovariabile_globale.prg`, `shutdown.prg`), while the core stock/article/movement procedures — `oproceduri_stocuri.prg`, `oproceduri_articole.prg`, `oproceduri_rulaje.prg`, `oproceduri_casademarcat.prg` (+ `_e500`/`_mp500` cash-register variants), `oproceduri_facturare.prg`, `oproceduri_obinv.prg` (fixed-asset-in-use items), `anaf_efactura.prg` (ANAF e-Factura), `osecurity.prg`, `oproceduri_configurare.prg`, `oproceduri_listari.prg`, `oproceduri_retete.prg`, `orapoarte.prg` — all resolve from `COMUN/programe/` via `SET PATH`. Likewise most class libraries used (`onomenclatoare`, `stocuri.vcx`, `rulaje.vcx`, `ointroduceri*`, `oinventar`, `orapoarte_gestiuni`, `bon_fisc`, `onom_articole`, `onom_retete`, `ferestre_oracle`, `configurare.vcx`, `serii_numere.vcx`, …) live in `COMUN/clase/`, not this repo's `Clase/`.
- ROAGEST's **own** `Clase/` folder is small: `gestiuni.vcx`, `oavize.vcx`, `oimportxml.vcx`, `orapoarte_gestiuni.vcx`, `ovizrul.vcx`, `atentie.vcx`. Its own `Ferestre/` is also small: `fundal.scx` (shell form), `accesindivid.scx`, `frm_conversii.scx`, `frm_schimbare_pret_tva.scx`. The bulk of forms actually used are `COMUN\ferestre\*` (e.g. login is `COMUN\ferestre\frm_login.scx`).
- `SET PATH` (see `Programe/roagest.prg` ~line 109) makes `COMUN\CLASE`, `COMUN\FERESTRE`, `COMUN\PROGRAME`, `COMUN\GRAFICE`, `COMUN\RAPOARTE`, `COMUN\MENIURI`, and the `COMUN\UTILE\*` helper libraries (GridExtras, ctl32, hpdf/ReportOutput, web, Excel) resolvable by bare filename, plus a sibling `..\COMUNROA\` directory (built from `gcAppPath`'s grandparent). So `SET PROCEDURE TO email.prg` resolves to `COMUN\PROGRAME\email.prg`.
## Application architecture
Startup flow (`Programe/roagest.prg`, procedural — no `oApp`/`RoaApp` object wraps it):
1. Verifies the running exe is actually named `ROAGEST*`; sets `SET CENTURY/DELETED/DATE/EXACT/...` environment options.
2. Computes `gcAppPath` (own folder) and `gcDirMare`/`dirgen` (suite root, one level up — e.g. `D:\ROA\`), builds the long `SET PATH TO` string across its own folders + `COMUN\*` + `..\COMUNROA\`, then issues **dozens of ordered** `SET CLASSLIB ... ADDITIVE` and `SET PROCEDURE ... ADDITIVE` statements (order matters: later `ADDITIVE` registrations can shadow earlier same-named procedures/classes).
3. Parses the launch parameter string (`tparam`, semicolon-delimited: `host;user;password;idutil;idprogram;...;an;luna;schema;idfirma`) when launched by the central ROA launcher; otherwise falls back to hardcoded dev defaults (`JCSSERVER`/`CONTAFIN_ORACLE`).
4. Sets up cross-cutting globals: `goLog`/`poLog` (`Log_Mesaje.prg`), `goLocale` (Romanian by default, `glTraducere = .F.` — translation path largely dormant), `goExecutor`/`goConn` (Oracle SQL pass-through), `goExport`, `goMyXMLHTTP` (remote error reporting), and an optional `goKeepAlive` timer (avoids ODBC idle timeouts).
5. `NUMEPROGRAM = 'ROA - Gestiuni'`, `_program = 'gest'`; reads the actual version string from the built `.exe`'s file version resource.
6. Registers `ON SHUTDOWN ShutDown()` / `ON ERROR ErrorHandler(...)`, instantiates `goApp = CREATEOBJECT("wzApplication")`, sets `goApp.cStartupMenu` to `Meniuri\roagest.mpr` and `goApp.cStartupForm` to `COMUN\ferestre\frm_login.scx`, then `goApp.SHOW` — this is the VFP event loop entry (AppWizard's `Show`/`Run` machinery), analogous to `READ EVENTS` in the newer apps.
7. `ErrorHandler` posts errors to a remote endpoint via `goMyXMLHTTP.postError(...)` (host read from `settings.ini`'s `[errors] host` key) in addition to showing `AMESSAGEBOX`. `Cleanup()`/`ShutDown()` release class libs, procedures, and the menu stack on exit.
### Globals convention
Same `g`/`gc`/`gn`/`gl` Hungarian-ish prefixing as the rest of the suite (`g` = global, `gc`/`gn`/`gl` = char/numeric/logical, `m.` = memory-variable scoping), declared `PUBLIC`/`PRIVATE` directly in `roagest.prg` rather than promoted by a framework object:
- `goApp` (AppWizard app object), `goConn`/`goExecutor` (Oracle connection + SQL executor), `goLog`/`poLog` (logger), `goLocale`, `goExport`, `goCalendar`, `goFirma`.
- `gcS` = Oracle schema (default `CONTAFIN`), `gnIdFirma`, `gnAn`/`gnLuna` (working year/month), `gcAppPath` (this app's folder), `gcDirMare`/`dirgen` (suite root, e.g. `D:\ROA\`), `gcSecurityPath`/`gcSecurityFile` (`DIRGEN + 'Security\ROA_SECURITY.TXT'`), `gcGeneralIniFile`/`gcSettingsFile` (`DIRGEN + 'settings.ini'`).
- Legacy holdovers from the pre-Oracle (`CONT2000`) codebase are still declared even though mostly unused now: `nror[65000]`, `RTVA[22,2]`, `SER_PERM`/`SER_PERI`/`VERSIUNE` (commented out), old disk-serial license-check functions (`decodare1`, `HEXDEC`, `DECTOBIN`, the commented-out `PORNIRE`/`verif_ser_perm`) — dead code kept for reference, not active.
### Data layer
- Backend is **Oracle**, reached via `goConn`/`goExecutor` (created from the `DECABAZA` classlib, same pattern as the sibling apps) — run queries with `SQLEXEC()`/the executor wrapper; results come back as VFP cursors.
- Domain tables/views follow Romanian/domain naming: `stoc`, `rulaje`/`rull` (stock movements), `act` (documents/NIR), `articole`/nomenclator, `gestiuni` (warehouses/locations), `casa de marcat` bon fiscal tables. Look in `COMUN/programe/oproceduri_stocuri.prg`, `oproceduri_articole.prg`, and `oproceduri_rulaje.prg` for the canonical query/view names (e.g. `viz_stocuri` filters on `an`, `luna`, `id_sucursala`, `id_gestiune`).
- `Initializari/` holds XML templates for cash-register integrations (`roagest_bon.xml(.tmpl)`, `roagest_mp500.xml(.tmpl)`, `euro500t.txt(.tmpl)`, `euro500t_erori.xml(.tmpl)`).
- `Locale/` is a full VFP database (`locale.dbc` + `.dbf`/`.cdx`) for the (largely dormant) translation feature, not just an .ini.
## Domain quick reference
- **No app-specific `.h` include** defines domain constants the way `roaacnpro.h` does for ROAACNPRO — `Include/CONT2000.H` is just a historical comment (a class-tree diagram from the old `CONT2000` codebase), and `Include/foxpro.h` is the stock VFP header. Domain behavior (document types, movement signs, VAT handling) is expressed directly in procedure logic in `COMUN/programe/oproceduri_*.prg`, not centralized constants — expect to trace behavior through those procedures rather than a single defines file.
- **`Rapoarte/*.frx`** (24 report layouts in this repo, more resolved from `COMUN\RAPOARTE`) name the real workflows: `rap_nirtransfer_achi` (NIR/transfer receiving), `rap_centralizator_intrari`/`_intrari2`, `rap_centralizator_iesiri`/`_iesiri2` (in/out summaries), `rap_fisa_magazie_fifo` (FIFO stock card), `rap_gest_val_subgrupe`/`_gestc` (valued stock by subgroup), `rap_vechime_stocuri` (stock aging), `rap_marfuri_lista_centr`/`_desf`/`_valoric` (goods lists), `rap_vanzari_comp_cant`/`_val`/`_web` (sales comparisons), `rap_instiintaripret` (price-change notices), `rap_inchidere_k`, `rap_stoc_obinv` (inventory-use objects), `rap_rul_consum_lucrari_articole`/`_centralizator_consum_lucrari` (consumption vouchers).
- **`Meniuri/`** menu names map to the app's top-level operations: `achi*` (achiziții/purchases), `vanz*` (vânzări/sales), `consum*` (bon consum), `transfer*` (stock transfers), `config*` (configurare), `casademarcat`/`casamarcat` (fiscal cash registers), `obinvent` (obiecte de inventar), `stoc`, `rulaje`, `list*`/`rapoarte` (reports), `roagest.mnx`/`.mpr` (the root startup menu, referenced by `goApp.cStartupMenu`).
- **`todo.txt`** is an informal running work list (Romanian, `ok`/`OK`-prefixed = done, otherwise pending) — recent items concern store inventory (`inventar magazin`), FIFO stock cards, and VAT-rate handling during the 19%→21% transition; useful as a quick pulse on active/recent pain points but not authoritative documentation.
- **VAT/TVA** is time-sensitive here too: recent changelog entries (v2.11.02.11.2) explicitly prepare the app for the 21%/11% rates effective 2025-08-01 while still supporting 19%/9%/5% for prior periods — the same "rate by document period, not 'current' rate" caution as the other ROA apps applies.
- **Cash register / fiscal integration**: `oproceduri_casademarcat.prg`, `oproceduri_casa_marcat_e500.prg`, `oproceduri_casa_marcat_mp500.prg` (in `COMUN/programe/`) integrate specific fiscal printer/cash-register protocols (E500, MP500); `Initializari/roagest_bon.xml`/`roagest_mp500.xml` are their config templates.
- **ANAF e-Factura / SAFT**: `COMUN/programe/anaf_efactura.prg` provides e-invoicing against ANAF, shared with sibling apps.
## Changelog & release convention
`changelog_roagest.txt` is the user-facing release log (188KB, going back to v1.0.x). **Newest entry goes at the top**, in this exact HTML-comment block format (Romanian, `DD/MM/YYYY`):
```
<!--
21/01/2026
ROAGEST - 2.11.5
:nou:
<what changed>
:modificare:
<what changed>
-->
```
Tags in use: `:nou:` (new feature), `:modificare:` (change), `:eroare:` (bug fix), and occasionally `:adaugare:` (addition) — match this exact tag vocabulary (a lone historical `:modfiicare:` typo exists; don't repeat it). Bump the `MAJOR.MINOR.PATCH` version (currently `2.11.5`) when you add an entry. The app checks for updates on startup (`COMUN/programe/oupdate.prg`, `wwcodeupdate.prg`) against `versiune_db.txt`'s schema stamp; the runtime reads its own version from the built `.exe`'s file version resource.
**Intrările sunt simple și compacte — doar strictul necesar pentru utilizatori.** O singură intrare
consolidată per livrare (versiunea o dă Marius), fără pași intermediari, fără runde, fără mecanisme
interne și fără erori apărute și corectate în interiorul aceleiași lucrări nelivrate.
## Mod de lucru: delegare către subagenți + review înainte de commit
Preferințele lui Marius pentru sesiunile pe acest proiect:
- **Orchestrare pe misiuni lungi**: niciodată un singur subagent care acumulează context pe multe sarcini înlănțuite — sesiunea principală orchestrează subagenți proaspeți per sarcină (prag: max ~200250k tokens per subagent, apoi handoff + agent nou), cu handoff compact pe disc; regula comună tuturor proiectelor ROA: `COMUN\docs\orchestrare-subagenti.md`.
- **Delegare**: modificările de cod de volum/rutină (aplicarea unei propuneri din `docs/propuneri_*.md`, editări pe cache-ul text + write-back, actualizări de documentație, rulări de teste) se deleagă către **subagenți Sonnet care lucrează în background** (team agents — Agent tool cu `model: sonnet`, lane-uri paralele unde e posibil), iar sesiunea principală doar orchestrează și monitorizează: împarte planul pe lane-uri, transmite constatările între agenți, verifică rezultatele (diff, teste, fidelity) și intervine direct doar la deblocări (procese agățate), decizii și verificări.
- **Fără commit fără review**: nu da commit din proprie inițiativă pe modificări de cod — Marius vrea întâi să **vadă diff-ul**. Pentru binarele VFP (`.vcx`/`.scx`), diff-ul lizibil se face pe forma text: regenerează textul din binarul vechi (HEAD din git) cu `vcx2txt.ps1 -Source` și compară-l cu textul editat din cache (`git diff --no-index`). Commit doar după ce Marius confirmă pe diff.
- **Curățenie înainte de commit**: la finalul unei lucrări se șterg patch-urile de review (`docs/diff_runda*.patch`), handoff-urile, planurile de rundă, logurile brute de regresie/repro, backup-urile `*.pre_runda*.bak` (proiect, `COMUN`, cache text) **și artefactele rulărilor de test** — folderele `screenshots*/` și `uisync*/`, `*_log.txt`/`*.log`, `.fxp`-urile de test. Faptul că sunt în `.gitignore` nu le scutește: se șterg de pe disc. Abia apoi commit.
## Stil de raspuns: scurt si concret
Marius vrea raspunsuri **clare, concise, fara vorbarie**. Regula, nu preferinta.
- **Starea si ce urmeaza, nu povestea.** Ce e gata, ce e stricat, ce trebuie decis, ce urmeaza —
in liste scurte, cu fisier si linie. Fara reconstituirea drumului pana la rezultat.
- **Fara naratiune de proces**: ce a raportat fiecare agent, cine ce a corectat, cum au fost
coordonate benzile. Intra in `docs/`, nu in raspuns.
- **Fara laude si fara reluari.** Nu repeta ce s-a spus deja in conversatie.
- Detaliile tehnice lungi (dovezi, iesiri de test, metodologie) se scriu in fisier si se
**trimite la el**, nu se copiaza in raspuns.
- Cand e ceva de decis: enunta decizia si optiunile in cateva randuri, cu recomandarea ta.
## Reguli de lucru si testare
**Inainte de orice modificare de cod sau testare, citeste `COMUN\docs\reguli_lucru.md`.**
Nu e optional si nu e doar context: contine regulile de livrare (diff ca fisier + aprobare
inainte de write-back), comentariile (max o linie), modificarile minime, harnessul de testare
headless si — la punctul 7 — lista de conventii obligatorii per zona atinsa (encoding cp1252 la
editarea `.vc2`/`.sc2`, UX formulare/griduri, `GO` pe `Recno()`, `goExecutor` + `ALTER TABLE`,
testare UI, export Oracle). Fisierul e index: urmeaza linkurile relevante pentru sarcina curenta.
Depanare detaliata: `COMUN\docs\depanare_testare_vfp.md`.
## Skill routing
When the user's request matches an available skill, invoke it via the Skill tool. When in doubt, invoke the skill.
Key routing rules:
- Product ideas/brainstorming → invoke /office-hours
- Strategy/scope → invoke /plan-ceo-review
- Architecture → invoke /plan-eng-review
- Design system/plan review → invoke /design-consultation or /plan-design-review
- Full review pipeline → invoke /autoplan
- Bugs/errors → invoke /investigate
- QA/testing site behavior → invoke /qa or /qa-only
- Code review/diff check → invoke /review
- Visual polish → invoke /design-review
- Ship/deploy/PR → invoke /ship or /land-and-deploy
- Save progress → invoke /context-save
- Resume context → invoke /context-restore
## Project insights (docs/)
`docs/` holds short, concrete notes discovered while working on real tasks — hidden flows, gotchas, key procedures/packages, relevant tables — that go beyond what this file covers. See `docs/README.md` for the index. **Proactively offer to update `docs/` whenever you uncover a non-obvious project insight while fixing a bug or investigating a flow** (don't wait to be asked), so future sessions can reuse it instead of re-investigating from scratch. Keep entries concise and factual — no restating what's obvious from reading the code.