# Multi-tržište: razdvojiti ili nastaviti? — plenum 5 stručnjaka (2026-08-19)

# Bilko multi-tržište — plenum 5 stručnjaka: razdvojiti ili nastaviti? (2026-08-19)

**Pitanje CEO-a:** *"Ovo s multi-tržištima će nas ujesti za guzicu. Pogledaj odluke o tome kako smo
odlučili da dijelimo backend i što nas taj plan sad ubija. Odvajanje ili nastavak?"*

**Presuda: NE RAZDVAJATI. Jednoglasno, 5/5.**

Sjedišta: arhitekt (Petter Graff, autor ADR-015) · HR porez i fiskalizacija · HR računovodstvo ·
podaci i distribuirani sistemi (Martin Kleppmann) · đavolji advokat.
Svi su radili nezavisno, s identičnim briefom, bez međusobnog dogovaranja.
Brief: `~/system/evidence/107158/plenum-brief-multimarket.md` · nalazi: `plenum-1..5-*.md`

---

## 1. Brief je bio pogrešan i svih pet sjedišta ga je oborilo

Tvrdio sam da plugin arhitektura (ADR-015) postoji kao ljuštura koju **niko ne koristi**.

**Netačno.** Mjereno na `azdo/main` @ `0e3dcd04`:

| provjera | rezultat |
|---|---|
| `git grep -l "CountryPlugin"` | **30 fajlova** |
| `git grep -l "PluginRegistry"` | **24 fajla** |
| `InvoiceService.kt` | 8 pogodaka, `pluginRegistry.resolve(country)` na 4 mjesta |
| `ComplianceCalendarService.kt` | 3 pogotka, HR PDV rokovi **isključivo** kroz `PluginHR` |
| `DI.kt` 226–238 | svih 5 jurisdikcija registrovano kroz Koin |

Greška je nastala jer je ispis skraćen na prvih osam redova — vidjeli su se samo pluginovi sami.
**Brojanje umjesto čitanja**, ista klasa greške kao s `boot.sh` dan ranije. Zabilježeno jer je to
obrazac koji se ponavlja, ne jednokratni previd.

## 2. Stvarni kvar je uzak, ne strukturni

`PausalService.kt` je goli Koin singleton izvan registryja. **Napisan 2026-08-13** — tri mjeseca
poslije ADR-015, šest dana prije plenuma. Nije zatečeni legacy nego **nov rad koji je zaobišao
mehanizam koji radi**.

Ruta `/compliance/pausal/*` nema country-gate, a **isti obrazac** (`SUPPORTED_COMPLIANCE_COUNTRIES`)
postoji ~150 linija niže **u istom fajlu** za deadline rute.

**Zašto ga ništa nije zaustavilo:** ADR-015 §3.1 obećava Detekt CI pravilo protiv `when(country)`
grananja u servisima.

> **ISPRAVKA 2026-08-19 (poslije objave).** Prvobitno je ovdje pisalo da
> `grep -i detekt azure-pipelines.yml` daje **0 pogodaka** i da kapija ne postoji. **To je netačno.**
> Mjereno na `azdo/main`: **16 pogodaka za `detekt`**, 30 za `MC #106879`, 10 za `kover`. Detekt je
> ožičen kao **stvaran blokirajući korak** (`Gate: Detekt (MC #106879)`,
> `Detekt static analysis (blocking, detekt-baseline.xml suppresses pre-existing debt)`).
> Isto važi i za `integrationTest known-failures baseline check (MC #106879, blocking)` — **živ je i
> radi**: oborio je build 1180 na PR-u 367 zbog 11 stvarnih regresija.
>
> Greška je nastala jer je grep izveden nad **glavnim checkoutom**, koji je na grani druge sesije i
> zastario. Ista klasa greške koju je ovaj plenum ispravio u §1 — mjerenje nad pogrešnim stablom.
> MC #106879 jeste `paused`, ali status zadatka **ne opisuje stanje pipeline-a**.

**Prava, uža rupa:** Detekt radi s aktivnim skupovima pravila `potential-bugs` i `coroutines`.
Pravilo koje bi uhvatilo baš ovaj slučaj — tržišna logika izvan `PluginRegistry` — **nije napisano
kao Detekt pravilo**. Sam pipeline to i kaže: `CrossTenantNotChecked` iz `detekt.yml` *"is NOT a
real Detekt RuleSetProvider"*. Dakle nedostaje **jedno custom pravilo**, ne cijela kapija.

> Petter Graff: *"Razdvajanje liječi pogrešan organ."*

## 3. Zašto razdvajanje (opcija B) nije odgovor

- **Regulatorno ga ne traži nijedan propis.** HR poreski stručnjak nije našao odredbu (Zakon o
  računovodstvu, EN16931) koja zahtijeva odvajanje **izvornog koda** po jurisdikciji — reguliše se
  revizijski trag transakcija, ne arhitektura softvera. eRačun kod je **već** fajlovski odvojen
  (`country/hr/*` vs `country/rs/*`).
- **Baza nije rizik nego najbolje uređen dio sistema.** 64 tabele imaju RLS, dvoslojno se provodi
  (app `SET LOCAL app.current_org_id` + RLS). **Nema nijednog cross-jurisdiction stranog ključa** —
  nema šta da se "presiječe". Stvarni diskriminator je `organizations.country`, ne `country_code`.
- **Cijena je nesrazmjerna:** org ima **jedan self-hosted CI slot** — tri backenda znače 3–5×
  serijalizaciju, uz umnoženu repo-nehigijenu.
- **Tržišta pravno ne postoje odvojeno:** nema HR pravnog entiteta (nema OIB), HR plaćanja idu preko
  ALAI Holding AS.

## 4. Šta je plenum iskopao usput — hitnije od arhitekture

**a) Hrvatski eRačun je ISKLJUČEN na produkciji.**
`az containerapp show -n bilko-api-demo -g rg-bilko-demo` → `SVERACUN_HR_LIVE=false`.
Obavezni B2B eRačun u HR važi od **2026-01-01** — sedam i po mjeseci. `PluginHR` kdoc i dalje navodi
provisioning prod tajni kao neriješen blokator.
**Nesklad koji treba razriješiti:** memo iz juna tvrdi da je vrijednost bila `true` i CEO-potvrđena,
uz napomenu "ne gasi je". Danas je `false`. Ko i kad — nepoznato, ne nagađa se.

**b) Registracija ne kreira kontni plan.**
`AuthService.register()` radi `Organizations.insert` i `Users.insert`, ali **nikad `Accounts.insert`**
(provjereno grepom, nula pogodaka). Punjenje postoji u `CountryService` iza `CountryRoutes`, ali nije
dio registracije. Ako ga onboarding ne zove, prvi `sendInvoice()` novog korisnika pada.

**c) Revizija RLS-a je bila djelimična.** 64 tabele imaju RLS; revidirane su **22**. Fail-open rupa
zatvorena jutros (`notifications`, V104→V165, MC #106958) nađena je unutar tih 22 — **42 tabele niko
nije pregledao**. Politike su i dalje PERMISSIVE, nikad prebačene na RESTRICTIVE.

**d) Računovođin portal** (`AccountantContext.kt`, `X-Accountant-Org`) ožičen je na ~10 ruta, a
vlastita dokumentacija kaže da je sigurnosna revizija **obavezna prije produkcije**. To je jedino
mjesto gdje identitet stvarno prelazi granicu organizacije. Curenje tamo nema vidljiv trag i može
otići u nepovratne eRačune prema FINA/SEF.

**e) Dodatni servisi van registryja** (nalaz đavoljeg advokata): `CountryService` (5 metoda s
`when(country)`), `ReportingRoutes` (`when(orgMeta.country)`), `ReportService` (0 pogodaka na
`CountryPlugin`). Dakle `PausalService` nije jedini — ali jeste jedini koji je procurio korisniku.

## 5. Odluka i redoslijed

**Arhitektura se ne dira. Radi se opcija A — dovršiti ADR-015.**

1. **Country-gate na `/compliance/pausal/*`** — obrazac postoji u istom fajlu (sati, ne dani)
   → **URAĐENO isti dan:** PR 367. Kapija `integrationTest` ga je oborila zbog 11 postojećih
   testova pisanih prije gate-a; popravka u toku.
2. ~~**Odblokirati MC #106879** (Detekt CI gate)~~ → **premašeno stvarnošću, vidi ispravku u §2.**
   Detekt i integrationTest kapije su **već žive i blokirajuće**. Preostaje **napisati jedno custom
   Detekt pravilo** koje prijavljuje tržišno-specifičnu logiku izvan `PluginRegistry`.
3. **`HrPausalService` iza `PluginHR`** s podacima iz NN (razredi 1–7, stopa 12%, prag 60.000 EUR —
   potvrđeno iz 5 NN dokumenata, dva nezavisna lanca)
4. **Zamrznuti peto tržište** dok kapija nije zelena u CI-u
5. **Prije svega gore:** razriješiti `SVERACUN_HR_LIVE` i kontni plan pri registraciji

## 6. Metodološka bilješka

Vrijednost plenuma nije bila u odgovoru na postavljeno pitanje — nego u tome što je **pitanje bilo
pogrešno postavljeno**, i što je pet nezavisnih provjera to pokazalo prije nego je iko potrošio
sedmice na razdvajanje.

Đavolji advokat je dobio izričit zadatak da obori brief i orkestratora, i uspio je u oba. Da je
brief prihvaćen na riječ, danas bi počela reorganizacija arhitekture koja bi zaobišla stvarni uzrok:
**nedostajuću kapiju u CI-u, ne dijeljeni backend.**