Skip to main content

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 PluginRegistrynije 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-demoSVERACUN_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.