Jedna stranica za jedan plugin-par. Sve što ovdje piše kao „gotovo” ima commit i broj testova; sve što piše „čeka tebe” ne može nitko drugi napraviti.
Putanje i gate premjereni 18. rujna 2026. Stranica je pisana 16. rujna, dan prije nego je monorepo razrezan na deset repozitorija, pa je svaka putanja u njoj pokazivala na jedno stablo. Najozbiljniji nalaz: 22 gotova prompta počinjala su rečenicom Radiš u ~/Dev/rasadnik/new-start — repozitoriju koji je od 17. 9. zamrznut i u kojem se po vlastitom PRESELJENO.md više ne razvija. Sada počinju u flora-baseu. Uz to: samples/wp-venture-sync je danas flora-core/wp-venture-sync, samples/sync-nexus je samostalan repozitorij sync-nexus, a gate više nije npm run check nego ./flora check, jedan po repozitoriju. Brojke gatea u promptovima zamijenjene su izmjerenima 18. 9. — stara baza od 3.102 bila je monorepo i danas ne postoji ni pod kojom naredbom.
Dopuna 18. 9. u 22 h — polazna brojka se pomakla drugi put istog dana, i to je sama po sebi poruka. Prompti su ujutro govorili 4.204 u šest gateova; navečer je ./flora check dao 4.377 u sedam (flora-base je dobio vlastiti gate, flora-core narastao za 140 testova). Brojke dolje su osvježene, ali ne vjeruj im na riječ — izmjeri svoju polaznu vrijednost prije nego išta dirneš.
Dopuna 20. 9. u 16 h — treći put. Polazna vrijednost u svih dvadesetak promptova ispod bila je do danas 4.377 (18. 9. u 22 h). ./flora check 20. 9. u 16:09 daje 4.443 testa, flora-core 3.531 u 346 datoteka, izlazni kod 0 — i to je sada upisano u svaki prompt, na 26 mjesta. Sesija koja bi krenula od stare brojke vidjela bi 66 testova viška i pomislila da je nešto pokvarila. Dva puta u tri dana polazna se brojka pomaknula ispod gotovih promptova; to nije razlog da se prompti ne pišu, nego razlog da svaki počne mjerenjem.
I jedna zamka koju prompti ne spominju: ./flora check danas vraća izlazni kod 1, ne 0, ako Vendure nije podignut. Obje trgovine padaju na astro build jer straža requireProductsForBuild odbija build s 0 proizvoda; testovi i type-check im prolaze. Gdje u promptu piše „exit 0", to vrijedi uz podignut Vendure — inače usporedi po repozitoriju, ne po skupnom izlaznom kodu.
Faza 1 je izgrađena na obje strane i spojena u main: WP plugin na masteru s hookovima (Task 6), Vendure plugin sa stranicom „Zalihe: WooCommerce”. Faza 0 je izmjerena. WP plugin je deployan i aktivan na dev-masteru. Faza 2 dokazana uživo. Faza 3 (automatika) izgrađena (plan 03, 8 taskova sa spec i quality reviewom, ~20 commita): izlazni dnevnik iz događaja, pull po kursoru s ref-idempotencijom i bravama, drain s nadjačavanjem, kick, raspored u workeru, dnevna rekoncilijacija, mail za greške, blok „Automatika” na stranici; WP 0.3.0 s ack i kickom iz shutdowna.
Faza 1 dokazana uživo 10. 9.: veza radi, 993 šifre upareno, 5 pa 988 primijenjeno bez greške, sljedeća razlika 0. Hookovi su vidjeli prvi živi pokret (SKU 617). Put child → master i varijabilni proizvodi mjere se tek na produkciji. Faza 2 dokazana uživo 10. 9. navečer: 2 šifre gurnute i primijenjene na masteru s točno jednim retkom dnevnika po pokretu, replay istog ref-a → duplicate, nepoznata šifra i stari paket odbijeni, pregled parkiran pa obrisan pravim pushom, razlika 0. Prvi push je pao na 726 siročadi u lookup tablici mastera (popravak 0.2.1 isti dan). Faza 3 dokazana uživo 11. 9. na SKU 1452 (WP 0.3.0, način „Odmah i po rasporedu”, interval 60 s): izmjena u Vendureu od −15 na masteru za nekoliko sekundi bez odjeka hookova; tri izmjene spojene prigušenjem u jedno slanje, svaki pokret sa svojim ref-om; promjena na masteru u Vendureu za 15 sekundi, pa unsentMovements 0 i lastAcknowledgedId 21 (potvrda radi); istodobno −1 u Vendureu i −2 na masteru → obje strane 72, delte se zbrojile; SALE −1 i CANCELLATION +1 poslani, ALLOCATION ništa; usklađivanje prijavilo razliku upisanu mimo dnevnika (applied 0, skipped 554, jedan unos) i nije ispravilo ništa; pet padova s 401 dalo točno dva maila, jedan po vrsti. Kraj: obje strane 69, ništa dugovano, kursor 27. Neizmjereno ostaje ono što dev ne može pokazati (child → master, varijabilni proizvodi, master koji zašuti usred paketa) i ono što u potprojektu 2 (nexus) još nije napisano: potprojekt 2 (nexus) je napisan do kraja, E1–E8 — devet tablica, potpisani prijem izvještaja, usporedba, pošta, retencija, pet ekrana, skripta za dućane, zadatak u Vendureu i Ansible deploy — i od 14. 9. radi uživo na kontrolnom serveru (sync-probe.rasadnik-milic.hr), gdje ga produkcijski master, oba childa i Vendure stvarno hrane. Sve poslije toga (E9) pisano je po onome što se na pravim podacima vidjelo: podkanali Vendurea kroz jednu tajnu, vrijeme pokreta izvučeno iz same narudžbe umjesto iz razlike snimaka, zanemarene razlike, izvor istine iza druge lozinke i prerađeno sučelje. 500 testova u flora-base/sync-nexus/.
| Dio | Što radi | Dokaz | Stanje |
|---|---|---|---|
| Spec + plan 01 | Model bez šefa: razmjenjuju se pokreti (delte) s porijeklom, ne stanja; SKU je ključ; backorders se samo bilježi; odstupanja kroz nexus. Plan u 15 taskova, svaki s promptom. | 74d20a7 · acfd858 · 6a18330 | gotovo |
| Faza 0, izmjereno | Dev-master: 1.000 proizvoda, 0 varijacija, svi sa SKU-om, bez duplikata, 989 vodi zalihu, backorders posvuda „no”, jedan proizvod na −160 (SKU 617, ručno ispraviti prije primjene). Presjek: svih 1.000 je u Vendureu, 547 Vendure SKU-ova master nema (podskup, očekivano). Hookovi pri spremanju na masteru: updated_post_meta _stock → product_set_stock → updated_props. Put child → master nije mjerljiv na devu (nema licence). | ccc5505 · spec „Faza 0 — izmjereno” | gotovo |
| WP plugin | flora-core/wp-venture-sync/: dnevnik pokreta, HMAC nad metodom+rutom+vremenom+tijelom, REST health / snapshot / movements, wp-cli, admin stranica, README, hookovi (set_stock primarno, updated_post_meta kao mreža koja se dedupira po zahtjevu i ponovno naoruža). 24 PHP testa (Docker, bez composera). | e95df2d … bb160e6 | gotovo |
| Vendure plugin | flora-core/src/plugins/woocommerce-stock-sync/: postavke (tajna write-only), klijent, čista razlika po SKU-u, migracija 1790000087000, servis diff/apply (svaki korak u vlastitoj transakciji, dnevnik preživi rollback), Admin API, stranica Katalog → „Zalihe: WooCommerce” hr/sl/de. 102 vitest testa. | 554243a … 2a00959 | gotovo |
| Živa provjera, negativan put | Klon baze, API na 3010, master nedostupan: stranica se renderira, postavke se spremaju, greške čitljive s URL-om, dnevnik izvršavanja, traka neuspjelih, „Označi viđeno”. Dva Dashboard gotcha-a nađena tek uživo i popravljena. | 520ee43 · 2a00959 | gotovo |
| Deploy | Ansible kao za prijašnje pluginove (inventory-sync, quick-vies-checkout): tar → backup postojeće mape → upload → vlasništvo. Cilja samo mastere, zadano dev. Pravi inventory lokalan i ignoriran. Izvršen na dev-master 10. 9. (failed=0), plugin aktiviran wp-cli-jem. | 54af926 · e1468d6 | obavljeno |
| Živa provjera, pozitivan put | Dev-master ↔ lokalni Vendure (3000), tajna na obje strane: „Veza radi · v0.1.0 · full”. Prva razlika: 993 upareno (7 od 1.000 je neobjavljeno, snapshot nosi samo objavljene), 993 promjene (114 količina/status, 879 samo backorders), 554 samo u Vendureu. Pet šifri primijenjeno i provjereno u bazi (200 = master, INHERIT netaknut, backorders „no”), pa 988 primijenjeno, 0 grešaka, sljedeća razlika 0. Prvi pokušaj pao na svih pet (id kao string → INSERT bez sku) i ništa nije upisao: rollback po koraku dokazan uživo. Dnevnik mastera ima prvi živi pokret (SKU 617, prvo viđenje). | f101102 · spec „Faza 1 — izmjereno” | gotovo |
| Faza 3, kod (plan 03) | Vendure: izlazni dnevnik iz StockMovementEvent (vlastiti upisi se prepoznaju po symbol-oznaci na kontekstu, jer EventBus kopira ctx); pull() po kursoru, delta pod pg_advisory_xact_lock po šifri, primljeni ref u istoj transakciji (replay = duplicate), mutex pg_try_advisory_lock preko procesa, kursor po stranici pa ack; drain() dugovanih redaka s nadjačavanjem (ručni push poravna starije retke istih šifri), parkirani retci; reconcile() koji prijavljuje; kontroleri /stock-sync/kick|health|snapshot|movements s potpisom; job queue za kick (5 s → 60 s backoff); dva ScheduledTaska u workeru; mail za greške (jednom po kodu na sat); blok „Automatika” i tri gumba. WP 0.3.0: POST /movements/ack (pisac za sent_at), kick iz shutdown nakon fastcgi_finish_request (jer blocking=>false nije asinkron), „Check Vendure”. Plan 04: prekidač enabled postaje način off / schedule / immediate — u Dashboardu padajući izbornik „Automatika” („Isključeno”, „Samo po rasporedu”, „Odmah i po rasporedu”) i zasebna kvačica „Dnevno usklađivanje”, uz pločice za oboje. U načinu „odmah” izlazni pretplatnik gurne vlastiti pokret čim nastane, prigušeno na jedno slanje u 5 s po procesu, i to samo slanje (pokret iz Vendurea ne govori ništa o masterovu dnevniku); takav redak nosi okidač event („događaj”). Bez migracije: postavke su JSON (stari enabled: true čita se kao „samo po rasporedu”), a /health WordPressu i dalje vraća enabled = „nije isključeno”. 91 PHP + 504 vitest testa. | 9c313dd … faza 3 | gotovo · dokazano 11. 9. |
| Dokumentacija | README oba plugina, flora-atlas/stanje/plugin-inventory.md (28 plugina, sync zaliha Live-verified), roadmap 57 s brojkama, spec s „Faza 0/1 — izmjereno”, odstupanja koda od plana zapisana u planu. | 5b69fe4 · e51ae36 · faza 1 | gotovo |
| Faza 2, kod (plan 02) | WP 0.2.0: POST /apply (samo full; 400/401/403/422), redak dnevnika s ref-om ide prije upisa zalihe u istoj MySQL transakciji (UNIQUE = idempotencija), wc_update_product_stock pod guardom, hookovi šute; dry run parkira paket koji WP admin potvrđuje (hash, 15 min, confirm); wp vendure-stock apply; ledgerEngine u healthu. Vendure: planPush (obrnuti predznak, prodivost onHand > prag, granice), potpisani POST, push() s provjerom mastera, guardom „jedan upis odjednom”, izlaznim dnevnikom prije slanja, paketima po 500, sentAt na applied/duplicate, stabilnim ref-ovima po planu (pregled i push nose iste). Stranica: dva nova gumba, blok pregleda/rezultata, hr/sl/de. 71 PHP + 179 vitest testova. | 86ffff7 … 86c3f99 | gotovo · dokazano 10. 9. |
| Nexus E1: kostur | flora-base/sync-nexus/: SQLite shema devet tablica, svaka s vlastitom retencijom upisanom u komentar CREATE-a; jedna ruta POST /api/report iza HMAC-SHA256 potpisa (shema prepisana iz potprojekta 1); idempotencija po izvoru i vremenu izrade, pa ponovljeni izvještaj vrati {"duplicate": true} i ne upiše ništa. Bez composera, frameworka i ijedne vanjske biblioteke. 41 test (prije njega 0). | 4b676ff · 1a95f6e | gotovo |
| Nexus E2: usporedba | Pet parova izvora iz postavki, a ne iz koda; tri vrste nalaza po šifri (razlika, samo jedna strana, nema podatka) i prekidač only_one_side po paru; prije usporedbe se traži da su obje strane javile unutar zadnja četiri sata. Šifra se uspoređuje doslovno — bez trimanja, bez velikih/malih slova — jer bi tiho poravnavanje sakrilo baš onu vrstu greške koju nexus traži. 104 testa. | 0b5cb0a · 18b10a2 · 8314313 | gotovo |
| Nexus E3: pošta | SMTP2GO preko njihova HTTP API-ja, namjerno ne Vendureovim putem: nadzor mora moći vikati dok je ono što nadzire pokvareno. Otisak nalaza i tihi prozor od 24 h da se isto neslaganje ne šalje svaka četiri sata; bin/silence-check.php iz crona javlja izvor koji je zašutio (4,5 h). Bez ključa uzbuna se uredno zapiše u alerts, imenuje se varijabla koja fali i ne šalje se ništa — bez pada na mail(). 167 testova, i nijedan ne dira mrežu (fake klijent broji koliko je puta izgrađen: 0). | 79edcd9 | gotovo |
| Nexus E4: retencija | Noćni posao u 3:00: sažmi dan u stock_daily, pa obriši, pa VACUUM — i to tim redom, jer je brisanje prije sažimanja dan povijesti koji nitko drugi ne čuva. Limiti se čitaju iz sqlite_master, ne iz konstante, pa shema i posao ne mogu razići; tablica bez komentara zaustavi posao imenom. Dokazano: s namjerno srušenim INSERT-om na bazi od 97.320 redaka posao je izašao 1 i nijedan redak nije nestao; suhi prolaz imenovao 852.591 redak, pravi obrisao 852.591. Suhi je prolaz usput nađen kako stvara bazu od 102.400 B na putanji koja je nema — popravljeno, i test to drži. 323 testa nakon spoja u main. | 811ad5f · 8ddb428 · f10b55f | gotovo |
| Nexus E5: dashboard i API | Pet ekrana (pločice, tablica neslaganja, 30 dana povijesti, sedmodnevna vremenska crta, narudžbe) i četiri JSON rute. Dvije brave koje se nikad ne sreću: kolačić sesije za ljude, HTTP Basic za strojeve — token na ekranu daje 302 na prijavu, kolačić na API 401. Baza se ne poslužuje ni izravno, ni kao -wal, ni kroz .. (svuda 404). Poveznica na proizvod po izvoru, iz predloška u okolini: dućani idu na pretragu administracije po šifri, Vendure na stranicu varijante, jer se ondje unosi količina. 226 testova. | 0b7a303 · 9ed40be · 6f6f44b | gotovo |
| Nexus E6: skripta za dućane | Jedna samostalna datoteka za wp eval-file, s obje grane u sebi: master čita dnevnik pokreta plugina iz potprojekta 1, child razliku računa prema vlastitom prethodnom snimku. Postavke stoje u wp-config.php, snimak izvan web roota (skripta odbija putanju unutar ABSPATH). Tri prolaza protiv živog lokalnog nexusa: prvi firstRun, drugi točno jedan pokret −15, treći bez promjene i izvještaj se svejedno šalje (šutnja je alarm). Prekinut upis snimka s kill -9 ostavio je sha256 nepromijenjen. 296 testova. | 3818006 · ff72207 | gotovo |
| Nexus E7: zadatak u Vendureu | Treći ScheduledTask woo-stock-report u flora-core/src/plugins/woocommerce-stock-sync/: svaka četiri sata šalje zalihe, pokrete i narudžbe. Nije vezan na način sinkronizacije — trgovina koja prestane javljati čim se sinkronizacija ugasi oslijepi baš kad netko po njoj radi — nego na vlastiti prekidač reportEnabled, a ekran naglas kaže da će nexus tada tu trgovinu prijaviti kao šutljivu. Tajna je zasebna od one prema masteru. productId je id varijante, što je jedino polje koje dashboardu treba za poveznicu. | 83992a3 | gotovo |
| Nexus E8: deploy | Compose (php:8.2-cli bez Dockerfilea — slika već nosi curl, json, pdo_sqlite, sqlite3), host nginx vhost i dva Ansible playbooka: nexus na kontrolni server, skripta na dućane. Dokazano dizanjem stacka: dimni test 400, svih pet ekrana 302 na prijavu, baza 404 i izravno i kroz .., kod montiran read-only, lsof pokazuje samo 127.0.0.1. PHP_CLI_SERVER_WORKERS=4 izmjereno: dva istodobna zahtjeva, dva PID-a, 2 s umjesto 4 s. Playbook: prvi prolaz changed=11, drugi changed=7 (samo mehanika backupa) i redak upisan u bazu između dva prolaza preživio; skripta na djeci 4 pa 0, mode=verify ne mijenja ništa. Nađena i popravljena prava rupa: iza nginxa je ograničenje prijave brojilo svima istu adresu (172.24.0.3), pa je pet krivih pokušaja bila jedna kvota za sve i napadač je mogao zaključati vlasnika — NEXUS_TRUSTED_PROXIES, dokazano stvarnim prijavama. 331 test (323 prije ovog koraka; svih 8 novih drži taj popravak). Pošteno rečeno: healthcheck zaglavljivanje čini vidljivim, ali compose sam ne restarta nezdrav kontejner. | 1cdb423 … 4845389 | gotovo · uživo od 14. 9. |
| Nexus E9: živi rad i dorada | Uživo na kontrolnom serveru od 14. 9., i od tada se mijenja po onome što se na pravim podacima vidjelo. Podkanali: Vendure javlja po kanalu, jednom tajnom — izvještaj nosi channel i popis channels sa statusom, a nexus ime izvora (vendure:plant-garden.hr) izvodi sam, pa se u NEXUS_SOURCES ne upisuje ništa; ugašen kanal razlikuje se od zašutjelog jer popis stiže uz svaki izvještaj. Vrijeme pokreta iz narudžbe: WooCommerce uz svaku stavku zapisuje _reduced_stock, pa pokret nosi minutu same narudžbe umjesto minute kad je razlika snimaka primijećena; razlika snimaka javlja još samo ostatak (ručna izmjena, dostava), a vremenska crta takav pokret crta kao crticu raspona s praznom točkom. Jednokratni prelazak: backfill=7 na dućanu i bin/migracija.php --apply na nexusu. Zanemarene razlike: pravilo po šifri, vrsti nalaza i paru (artikl koji se namjerno prodaje samo u jednoj zemlji) — ne broji se na pregledu ni u e-mailu, ali se i dalje uspoređuje i ostaje u izvozu. Zaglavljeno razilaženje: šifra koja je u neskladu u tri uzastopne usporedbe nije sync u letu nego promjena koja nikad nije stigla — vlasnikov slučaj „jedan store proda nešto a to se ne propagira na master". Podatak je već bio u comparison_items, pa je to upit i oznaka, bez nove tablice: velika kartica „izvor istine je van synca" iznad svega na početnoj (samo kad ima čega, s modalom koji imenuje svaku šifru i obje količine) i ista takva u e-mailu, složena kao tablica da je nacrta svaki klijent, jantarna oznaka u tablici, filtar samo zaglavljena, broj na kartici pregleda i dodatak u naslovu maila (zanemarena razlika se ne broji, inače bi artikl koji se namjerno prodaje u jednoj zemlji zauvijek bio zaglavljen). Čija je strana: zaglavljena razlika prema izvoru istine ne znači sama po sebi da katalog nije dobio promjenu — vlasnikov primjer „izvor istine 10, trgovina 1 osam, trgovina 2 deset" znači da odudara trgovina 1. Nexus sad odlučuje čija je strana (svi ostali se slažu, a izvor istine ne → katalog; jedan odudara → dućan; svatko svoje → ne odlučuje se), pravilo se bira uz izvor istine (konsenzus, vecina, svaka), a pregled i pošta crtaju dvije kartice: crvenu za katalog, jantarnu za dućan. Dijagnostika: tab u postavkama koji ispisuje aritmetiku iza brojki — po paru usporedbe u prozoru, zanemareni, zaglavljeni i najdulji niz, pa svaka zaglavljena šifra s krugovima i početkom — te izvoz cijele snimke u .json bez ijedne tajne, lozinke i adrese. Uz njega je ispravljena i sama brojka: kartica broji nalaze (jedna šifra zaglavljena prema dva dućana su dva nalaza) i uz njih piše na koliko je to šifri. Sučelje: izvor istine kao zaključan izbor iza druge lozinke i obavezno pitanje na svježem nexusu, postavke u četiri taba (uz SMTP2GO račun i probnu poruku), tema svijetla/tamna/automatska, pilule u jednom redu koji se vuče mišem. 500 testova (331 na kraju E8). | 54a3861 … 439621c | u radu · uživo |
| Nexus E10: analiza i dorada | Analiza 15. 9. po pet kategorija (sigurnost, arhitektura, otpornost, nove mogućnosti, poboljšanja) dala je 25 prijedloga s mjerenjem na produkcijskoj snimci: prozor od 12 usporedbi trajao je 4 sata a ne dva dana, 35 od 36 zaglavljenih „od iste minute”, 9 mailova u 8 h za nepromijenjen skup, 99,3 % redaka usporedbi iz skrivenih parova. Vlasnik odabrao 11 (od toga tri veća — A2, A3, N2 — odgođena, S3 odbijen). Izgrađeno, sve na grani nexus-analiza-1: A1 usporedba samo na novom ulazu, S1 CSRF token, S2 display_errors ugašen + handler, S5 granice ulaza + nginx limit_req, P3 izvoz nosi sve retke i filtre, P1 zaglavljeno = 3 kruga + 2 h + obje strane („najmanje od”), P2 mail čeka izvor istine, N3 dnevnik promjena postavki, N5 nečitljivi artikli iz dućana, A5 sirovo tijelo izvještaja 7 dana. Ekran proširen na 96rem. Puni popis u tabu sync-probe. | 17020803 … 4ca51f24 | deployano 16. 9. |
| Nexus E11: prekidač kartice i modal na karticama dućana | Vlasnik je 15. 9. navečer rastavio vlastitu ploču: na snimci od 20:15 stoji 35 zaglavljenih nalaza na 32 šifre — 4 na strani izvora istine, 16 na strani dućana, 15 nejasno. Crvena kartica broji onih 4, kartice dućana ispod nje svih 35 (HR 14, SI 21), obje su brojke točne i nijedna ne objašnjava drugu; k tome kvar iz njegova opisa (HR proda, master ne primi, SI prepiše master — P354: 300/295/300) po konsenzusu pada na stranu dućana i u crvenu karticu ni ne ulazi. Zato: kartica dobiva prekidač (alarm_kartica, uključena dok se ne isključi, u istom obrascu i iza iste brave kao način detekcije; isključena gasi točno taj natpis — oznake, filtar, dijagnostika i pošta ostaju), i svaka kartica dućana otvara svoj :target modal s popisom zaglavljenih te trgovine, stupcem „čija je strana” i podnaslovom koji se zbraja (K + L + O = N). Bez ijednog skripta: sloj-poveznica preko kartice, gumbi iznad njega. Demo baza dobiva treći krug pa se sve to napokon vidi i lokalno. 590 testova (bilo 580). | 774fcb11 … 144633fa | deployano 16. 9. |
| Nexus E12: preglednost dijagnostike | Tab Dijagnostika je narastao na pet tablica i oko 90 redaka bez ičega na vrhu što bi reklo je li to dobro ili loše — vlasnik, 16. 9.: „jako je dugačka i ne znam što je što”. Pitan što na njoj zapravo traži, označio je sva četiri posla (je li sve u redu · odakle ta brojka · gdje je kvar · da ovo nekome pošaljem), a ravan popis ne služi nijednom. Sad: pet pločica sa statusom (izvori, usporedbe, pošta, zaglavljeno, baza), svaka poveznica u svoj odsjek; naslovi su pitanja (Zaglavljeno razilaženje → Zašto pregled kaže 35 — po parovima); odsjeci su sklopivi <details> i onaj čija pločica nije zelena crta se otvoren, pa se kvar ne može kliknuti u stranu. Nijedan prag nije izmišljen — tišina je isti SILENCE_SECONDS koji crveni pilulice, a crveno/jantarno na zaglavljenom dijeli NexusKrivac kao i kartica; baza nema ocjenu jer prag nikad nije izmjeren. Ništa se ne gubi: 25 redaka pa „prikaži sve” na istoj stranici, ?razmotano=1 za Ctrl+F i ispis, i izvoz po odsjeku. Dnevnik pošte sa zadnjih 20 redaka na 7 dana s brojem po statusu i filtrom — odnos poslano/prigušeno je odgovor na „zašto mailovi ne dolaze svaka 4 sata”, jer je tihi prozor 24 h. 598 testova (bilo 590). | ed5d6007 … fd24f899 | deployano 16. 9. |
| Nexus E13: dorada po pregledu | Vlasnik je pogledao E12 i našao šest stvari, dvije od njih kvarovi te iste runde. Pilulice statusa bile su obični linkovi pa je svaki klik dizao stranicu i bacao čitatelja prema dolje — sad nose uzivo, klasu čiji handler od 15. 9. mijenja <main> na mjestu. Kapa od 25 redaka bila je po paru, a parova je 17: oko 300 redaka u odsjeku koji se otvara sam, dakle točno ono zbog čega je tab i prepravljan — sad je 10 na cijeli odsjek, jedna tablica s parom kao stupcem. Uz to četiri stvari kojih nikad nije bilo: zašto je pošta prigušena (stajalo u alerts.note od prvog dana, nitko ga nije čitao); šifra vodi u dućan, par u tablicu neslaganja; tri :target panela koja objašnjavaju stupce, s primjerom retka i izričitim „što brojka nije” (usporedbi u prozoru se čita kao „danas”, krugovi kao sati); i popravak trake postotka, koja je imala tamnu podlogu na tamnocrvenoj kartici pa je nestajala. Hover više ne podiže karticu, a crvena je po izboru vlasnika jedva vidljiva ispuna. 603 testa (bilo 598). | 551e6c60 | deployano 16. 9. |
| Nexus E14: narudžbe po kalendaru, s grafom | Ekran narudžbi imao je jednu kontrolu — broj dana unatrag — a vlasnik je tražio ono što se stvarno kaže: danas, jučer, ovaj tjedan, uz pitanje koje je vrijedilo postaviti: „ne znam kako to voditi kad je sve u UTC-u a ja sad nisam u UTC-u”. Spremanje se ne miče — svaki zapis je i ostaje UTC; u zonu čitatelja seli se samo rub, pa „danas” znači od lokalne ponoći u Zagrebu do sada, izračunato ondje i predano upitu kao dva UTC trenutka. Nova NexusRaspon je ta računica i ništa drugo: čista funkcija ključa, trenutka i zone, bez baze i bez ekrana — jedino tako se teži dio da testirati. Testovi drže oba smjera pomicanja sata (25. 10. 2026. zatvoreni dan ima 25 sati, 29. 3. ima 23) i drže da „danas” i „zadnja 24 h” nisu isto pitanje, pa su i dva gumba a ne sinonimi. Uz to dva grafa iza tabova po vlasnikovoj ispravci — narudžbe složene po dućanu i zbroj količina — jer jedna narudžba od 40 komada i 40 narudžbi od jednog isti su stupac na jednom grafu i nisu ni blizu na drugom; kratki rasponi po satu, dulji po danu, prazna kanta dobiva vlas a ne rupu. Serija se gradi iz redaka koje ekran ionako dohvaća, bez ijednog novog upita. 618 testova (bilo 603). | 1f55c229 … a3aa3b41 | deployano 16. 9. |
| Nexus E15: pošta zove dućan imenom i čita se na telefonu | Vlasnik, 16. 9.: „mail templatovi i dalje koriste ono za master”. Jesu — lib/Alerts.php nije spominjao nikakvo imenovanje (grep dao nulu), pa je ispisivao jedino što je imao: woocommerce-master i woocommerce-master <-> woocommerce-hr, dok ekrani od 14. 9. kažu adresu. Sad ime() i imePara() idu istim redom kao ekrani, a i bilješka usporedbe (only on …) se prevodi. Dvije stvari je otkrio test koji tjera potpisan izvještaj kroz pravi handler: ulazni put nije prosljeđivao postavke, i poziv živi u afterStoredReport() a ne u handle(), pa je varijabla bila izvan dosega. Uz to poruka vodi blokom stanja — četiri pločice 2×2 u fluidnoj tablici i popis zaglavljenih po dućanu — jer mail ne smije pitati @media za pomoć (Outlook ga ignorira, Gmail baca blok u kojem živi). Redak nalaza više nije četiri stupca s nowrap nego dvije linije s presudom „čija strana”; gumb je pune širine; kapa 10 šifri po paru umjesto 50. Mjereno na tijelu poruke: 0 internih ključeva, 0 engleskih bilješki, 0 @media/flex/float, 0 klasa. 623 testa (bilo 618). | 0e4dfefc … d67e5a43 | deployano 16. 9. |
| Nexus E16: rasponi, oblačići, starost problema — i zašto se vlasniku stranica i dalje učitavala | Četiri stvari iz jednog pregleda. Oblačić: grafovi narudžbi i povijesti imali su samo <title>, koji se pojavi tek nakon sekunde mirovanja — sad crtaju isti oblačić koji vremenska crta ima od 14. 9., unutar SVG-a i bez novog skripta. Isti kalendarski rasponi na povijesti i vremenskoj crti, ali ne isti popis na oba: stupac povijesti je cijeli dan (comparison_daily sprema dan, ne trenutak) pa bi „zadnja 24 h” ondje bio jedan stupac, dok crta nudi svih sedam jer svaki njezin redak nosi trenutak. Usput je zatvoren rub koji nikad nije trebao: upit povijesti nije imao gornju granicu jer iznad „danas” nema što izuzeti — izmjereno, „prošli tjedan” sad crta 7.–13. 9. i nijedan stupac iz ovog tjedna. Povijest je dobila drugi tab po vlasnikovu izboru, jer je njegov sud o prvom grafu točan: taj broji nalaze po danu, pa dok se ništa ne popravlja jest i može biti samo niz jednakih stupaca — svojstvo pitanja, ne njegovih podataka. Drugi tab pita koliko dugo problem stoji. Starost se namjerno ne uzima iz NexusStuck: njegov prozor je dvanaest krugova, pa bi sve starije od dva dana zauvijek prijavljivalo ista dva dana i graf bi bio jedan stupac koji se ne miče. Računa se nad svih 30 dana koliko se comparison_items čuva, hodanjem unatrag po krugovima — problem koji je bio riješen pa se vratio mjeri se od povratka, što MIN(created_at) ne bi znao; preko 30 dana zadnja je kanta izrijekom donja granica. Četvrto je odgovor na dvaput prijavljeno „stranica se i dalje učitava kad filtriram poštu”: klik je izmjeren pravim mišem preko DevTools protokola — jedan fetch, nula zahtjeva za dokumentom, scroll nepomaknut — i na grani i u mainu. Kad se pinana skripta ne izvrši, sve tiho degradira i nigdje ne piše da je tako; sad piše. Dijagnostika čita data-skripta s korijena i imenuje uzrok (Cloudflareov Rocket Loader i Auto Minify prepisuju inline skriptu pa joj hash u CSP-u više ne odgovara). Obje su rečenice uvijek u HTML-u, stil bira koju pokazuje — nijedan novi skript da se prijavi da skripte nema. 632 testa (bilo 623). | bcaf54ae … 3796a102 | spojeno 16. 9. |
| Nexus E17: pošta dobiva sekcije po dućanu, i prekidač koji vrijedi na oba mjesta | Vlasnik je pročitao pravu poruku i pitao ono što je trebalo pitati: „zašto nemamo sekcije za HR i SI … u stilu modala gdje je hero dio svakog od njih”. Zaslon je to imao dva dana, pošta je i dalje vodila jednom karticom o masteru i nizala ostalo kao ime para iznad dvostupčanih redaka. Sad svaki dućan ima svoju sekciju: naslov imenuje dućan pa izvor istine (dućan je ono što se ide popraviti), redak s brojkama kao u modalu, i kartica po nalazu sa svih pet stvari koje modal ima — šifra, naziv artikla, vrijednost u svakom dućanu, čija je strana, koliko dugo traje. Nijedan novi upit: podatke je pošta imala cijelo vrijeme i ispisivala dva od pet stupaca. Render je otkrio dva kvara, oba vidljiva i na vlasnikovoj snimci: kartica je pisala „4 ALAZA” jer je rezala strlen(broj) znakova s početka riječi koju plural() vraća bez broja (četveroznamenkasti broj dao bi „ZA”), a „Zaglavljeno po dućanu” brojalo je po paru — sa četiri izvora ima šest parova i dućan je na tri, pa se isti dućan ispisivao tri puta s tri broja (izmjereno: 1538, 35 i 20). Prekidač alarm_kartica sad vrijedi i za poštu. Od 11. 9. namjerno je stao na zaslonu — poruka se čita daleko od ploče i ne smije biti tiho uža od nje — ali to je prestalo vrijediti kad je poruka dobila vlastite pločice i sekcije: kartica je postala treće mjesto koje kaže isto, pa je vlasnik pitao čemu služi i odlučio da je prekidač gasi. Gasi jedan natpis i ništa više. 637 testova (bilo 632), a oba kvara i sama žica prekidača provjereni su tako da su vraćeni — testovi padnu. | 60727674 … (E17) | spojeno 16. 9. |
Podjela od 17. 9. nije zatvorila nijednu stavku na ovom popisu, i nije ni mogla — rez repozitorija premješta kod, ne dokazuje sync. Promijenila je samo gdje se svaka stavka radi: WP strana je u flora-core/wp-venture-sync, Vendure plugin u flora-core/src/plugins/woocommerce-stock-sync, a nadzor je samostalan repozitorij sync-nexus sa svojim gateom. Jedna je stavka time postala teža: promjena koja dira obje strane sada je dva commita u dva repozitorija, a ništa ne provjerava da su otišla zajedno osim sha-lock.json, koji to bilježi ali ne provodi.
Deploy ide s tvog stroja (Ansible, ključ ~/.ssh/rasadnik). Ništa od ovoga ne dira produkciju: playbook zadano cilja samo dev_master, a Vendure je tvoj lokalni na 3000. Koraci označeni ti traže tvoju ruku; ostalo može sesija. Cijeli niz je prošao 10. 9. 2026. (koraci 0–7 i 9; korak 8 nije ponovljen kroz Dashboard); ostaje kao recept za ponavljanje nakon svake promjene plugina. Faza 2 je prošla isti dan navečer (dolje).
Kopiraj flora-samples/stock-checker/scripts/wvss-probe.php na dev-master i pokreni. Datoteku vrati u korijen repoa (ignorirana je u gitu).
wp --path=/var/www/dev-master.rasadnik-milic.hr eval-file wvss-probe.php > probe-master.json
Tracer hookova: kopiraj wvss-hook-trace.php na master, promijeni zalihu jednog proizvoda na HR childu kroz wp-admin, pričekaj da WooMultistore progura, pročitaj log, pa obriši i mu-plugin i log.
mkdir -p /var/www/dev-master.rasadnik-milic.hr/wp-content/mu-plugins && cp wvss-hook-trace.php /var/www/dev-master.rasadnik-milic.hr/wp-content/mu-plugins/ wp --path=/var/www/dev-master.rasadnik-milic.hr eval 'echo file_get_contents(WP_CONTENT_DIR."/wvss-hook-trace.log");' rm /var/www/dev-master.rasadnik-milic.hr/wp-content/mu-plugins/wvss-hook-trace.php /var/www/dev-master.rasadnik-milic.hr/wp-content/wvss-hook-trace.log
Presjek SKU-ova, iz korijena repoa, s dev bazom gore:
docker compose -f compose.dev.yml exec -T postgres psql -U plant_garden -d plant_garden -Atc "select sku from product_variant where \"deletedAt\" is null and sku <> ''" > vendure-skus.txt node flora-samples/stock-checker/scripts/compare-skus.mjs probe-master.json vendure-skus.txt
Plugin je u main; tvoja dev baza još nema tablice. Ugasi :3000, pokreni migraciju, digni ponovno.
cd ecommerce && npx vendure migrate --run && cd .. && npm run dev
Prvo pregled bez kopiranja, pa deploy. Playbook radi backup postojeće mape (ako je ima) u backups/, nikad ne aktivira.
cd flora-core/wp-venture-sync && ansible-playbook ansible/deploy.yml --check --diff
cd flora-core/wp-venture-sync && ansible-playbook ansible/deploy.yml
Aktivacija i prva provjera, na masteru:
wp --path=/var/www/dev-master.rasadnik-milic.hr plugin activate wp-venture-sync wp --path=/var/www/dev-master.rasadnik-milic.hr vendure-stock status
openssl rand -hex 32
Isti niz upiši u WooCommerce → Vendure Stock Sync (Shared secret; Vendure URL može ostati prazan do plana 03) i u Katalog → Zalihe: WooCommerce → Postavke (Adresa WooCommercea = https://dev-master.rasadnik-milic.hr, Zajednička tajna). Spremi.
Da razdvojiš mrežu od logike: potpisani GET na master, iz korijena repoa, s tajnom u varijabli (ne u povijesti shella).
read -s SECRET; ts=$(date +%s); route=/vendure-stock/v1/snapshot sig="sha256=$(printf '%s\n%s\n%s\n%s' GET "$route" "$ts" '' | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')" curl -s -H "X-WVSS-Timestamp: $ts" -H "X-WVSS-Signature: $sig" "https://dev-master.rasadnik-milic.hr/wp-json$route" | head -c 600
Na stranici „Zalihe: WooCommerce” klikni Povuci razliku. Ništa se ne piše; vidiš sažetak i tablicu po šifri.
Odznači sve, označi pet šifri s razlikom u količini, zapiši njihova stanja prije:
docker compose -f compose.dev.yml exec -T postgres psql -U plant_garden -d plant_garden -c "select v.sku, sl.\"stockOnHand\", v.\"trackInventory\", v.\"customFieldsWoobackorders\" from product_variant v join stock_level sl on sl.\"productVariantId\"=v.id where v.sku in ('SKU1','SKU2','SKU3','SKU4','SKU5')"
Klikni Primijeni odabrano, pa isti upit.
„Odaberi sve promjene” → „Primijeni odabrano”. Backfill backordersa ide u paketima po 100.
Promijeni tajnu na jednoj strani, klikni „Provjeri vezu” i „Povuci razliku”, pa vrati tajnu.
Brojke iz koraka 0, 5, 6 i 7 idu u spec pod „Faza 0 — izmjereno” i „Faza 1 — izmjereno”, u flora-atlas/stanje/plugin-inventory.md (Built → Live-verified) i u roadmap 57. Tek onda Task 6 i plan 02.
Razlika je nakon faze 1 na nuli, pa se najprije napravi razlika na Vendure strani. Deploy WP plugina 0.2.0 ide s tvog stroja (Ansible), Vendure je tvoj lokalni na 3000 i traži restart jer API ne gleda promjene koda. Ništa ne dira produkciju.
Ista naredba kao u fazi 1; playbook zadano cilja samo dev_master. Nakon toga provjeri verziju i da nema parkiranog paketa.
cd flora-core/wp-venture-sync && ansible-playbook ansible/deploy.yml
ssh -i ~/.ssh/rasadnik paveljame@178.105.119.208 'wp --path=/var/www/dev-master.rasadnik-milic.hr plugin list --name=wp-venture-sync --fields=name,status,version; wp --path=/var/www/dev-master.rasadnik-milic.hr vendure-stock status'
Kod je u main; nema nove migracije. Ugasi i ponovno digni npm run dev, pa otvori Katalog → „Zalihe: WooCommerce” i klikni „Provjeri vezu”.
U Dashboardu (Katalog → proizvod) postavi zalihu varijante SKU 621 s 200 na 190 i SKU 625 s 200 na 205. Pa „Povuci razliku”.
Odaberi oba retka i klikni „Pregled slanja na WooCommerce”. Onda na masteru pogledaj što je parkirano.
ssh -i ~/.ssh/rasadnik paveljame@178.105.119.208 'wp --path=/var/www/dev-master.rasadnik-milic.hr vendure-stock status'
U WP adminu klikni „Apply this package” (potvrdi dijalog). Pa provjeri zalihu i dnevnik na masteru, i „Povuci razliku” u Vendureu.
ssh -i ~/.ssh/rasadnik paveljame@178.105.119.208 'P=/var/www/dev-master.rasadnik-milic.hr; wp --path=$P eval '"'"'foreach (["621","625"] as $s) { $p = wc_get_product(wc_get_product_id_by_sku($s)); echo "$s -> " . $p->get_stock_quantity() . "\n"; }'"'"'; wp --path=$P vendure-stock status'
U Vendureu vrati 621 na 200, „Povuci razliku” (621 razlika −10), odaberi 621 i klikni „Pošalji na WooCommerce (1)” bez pregleda. Zatim isti pokret pošalji ponovno wp-cli-jem s istim ref-om (uzmi ga iz Vendure baze).
docker compose -f compose.dev.yml exec -T postgres psql -U plant_garden -d plant_garden -c 'select ref, sku, delta, "qtyAfter", origin, "sentAt", note from woo_stock_movement order by id desc limit 3'
REF=ZALIJEPI-REF-OVDJE; ssh -i ~/.ssh/rasadnik paveljame@178.105.119.208 "P=/var/www/dev-master.rasadnik-milic.hr; printf '%s' '{\"source\":\"replay\",\"generatedAt\":\"'\$(date -u +%Y-%m-%dT%H:%M:%SZ)'\",\"movements\":[{\"ref\":\"$REF\",\"sku\":\"621\",\"delta\":10,\"qtyAfter\":200,\"stockStatus\":null,\"backorders\":null,\"origin\":\"vendure\",\"at\":\"2026-09-10T12:00:00Z\",\"note\":\"replay\"}]}' > /tmp/replay.json; wp --path=\$P vendure-stock apply --file=/tmp/replay.json"
Tri odbijanja koja moraju biti čitljiva. (a) wp-cli paket sa šifrom koje nema. (b) U WP adminu prebaci Mode na read-only, u Vendureu „Pregled slanja” za bilo koji redak, pa vrati na full. (c) Paket star više od 15 minuta.
ssh -i ~/.ssh/rasadnik paveljame@178.105.119.208 "P=/var/www/dev-master.rasadnik-milic.hr; printf '%s' '{\"source\":\"probe\",\"generatedAt\":\"'\$(date -u +%Y-%m-%dT%H:%M:%SZ)'\",\"movements\":[{\"ref\":\"'\$(cat /proc/sys/kernel/random/uuid)'\",\"sku\":\"NEMA-OVOG\",\"delta\":-1,\"qtyAfter\":0,\"stockStatus\":null,\"backorders\":null,\"origin\":\"vendure\",\"at\":\"2026-09-10T12:00:00Z\",\"note\":\"probe\"}]}' > /tmp/unknown.json; wp --path=\$P vendure-stock apply --file=/tmp/unknown.json --dry-run; printf '%s' '{\"source\":\"probe\",\"generatedAt\":\"2026-09-10T00:00:00Z\",\"movements\":[]}' > /tmp/stale.json; wp --path=\$P vendure-stock apply --file=/tmp/stale.json --dry-run; echo \"exit=\$?\""
Za svaki primijenjeni pokret na masteru smije postojati točno jedan redak dnevnika. Ispiši sve retke od koraka 5 nadalje.
ssh -i ~/.ssh/rasadnik paveljame@178.105.119.208 'wp --path=/var/www/dev-master.rasadnik-milic.hr vendure-stock movements --since=1 --limit=50'
Brojke iz koraka 1–8 idu u spec pod „Faza 2 — izmjereno”, u README oba plugina, flora-atlas/stanje/plugin-inventory.md (Live-verified, faze 1–2), roadmap 57 i ovu stranicu. Tek onda plan 03.
Polazno stanje izmjereno 11. 9. u 9:40: obje strane su na 65 za SKU 1452 (proizvod 174152 na masteru), dnevnik mastera ima 16 redaka, unsentMovements 0, lastAcknowledgedId 16. Ako se brojke u međuvremenu pomaknu, to nije problem: svaki korak kaže što gleda, ne koji je broj. Cijeli niz je prošao 11. 9. 2026. (koraci 1–9; brojke su u specu pod „Faza 3 — izmjereno”), pa ostaje kao recept za ponavljanje nakon svake promjene plugina. Radi korake redom i u polje ispod svakog zalijepi što si vidio, pa na kraju klikni „Kopiraj izvještaj” i pošalji ga u razgovor.
U Dashboardu, Katalog → „Zalihe: WooCommerce”, blok Automatika: način mora biti „Odmah i po rasporedu”, „Dnevno usklađivanje” uključeno. Zapiši i obje zalihe.
docker compose -f compose.dev.yml exec -T postgres psql -U plant_garden -d plant_garden -c "select v.sku, sum(sl.\"stockOnHand\") as vendure from product_variant v join stock_level sl on sl.\"productVariantId\"=v.id where v.sku='1452' group by v.sku"
ssh -i ~/.ssh/rasadnik paveljame@178.105.119.208 'P=/var/www/dev-master.rasadnik-milic.hr; wp --path=$P eval "echo \"master: \", wc_get_product(174152)->get_stock_quantity(), \"\n\";"; wp --path=$P vendure-stock status'
U Dashboardu smanji zalihu SKU 1452 za 3 (npr. 65 → 62) i ne diraj ništa drugo. Pričekaj 10 sekundi, pa pokreni:
ssh -i ~/.ssh/rasadnik paveljame@178.105.119.208 'P=/var/www/dev-master.rasadnik-milic.hr; wp --path=$P eval "echo \"master: \", wc_get_product(174152)->get_stock_quantity(), \"\n\";"; wp --path=$P vendure-stock movements --since=15 --limit=10'
Brzo, jedna za drugom (unutar 5 sekundi): 62 → 61, pa 61 → 60. Pričekaj 15 sekundi.
ssh -i ~/.ssh/rasadnik paveljame@178.105.119.208 'P=/var/www/dev-master.rasadnik-milic.hr; wp --path=$P eval "echo \"master: \", wc_get_product(174152)->get_stock_quantity(), \"\n\";"; wp --path=$P vendure-stock movements --since=15 --limit=10'
Sad obrnuti smjer. Postavi na masteru 1452 na 75 i pričekaj 15 sekundi.
ssh -i ~/.ssh/rasadnik paveljame@178.105.119.208 'P=/var/www/dev-master.rasadnik-milic.hr; wp --path=$P wc product update 174152 --stock_quantity=75 --user=1 --porcelain; sleep 15; wp --path=$P vendure-stock status | grep -E "unsentMovements|lastAcknowledgedId"'
docker compose -f compose.dev.yml exec -T postgres psql -U plant_garden -d plant_garden -c "select v.sku, sum(sl.\"stockOnHand\") as vendure from product_variant v join stock_level sl on sl.\"productVariantId\"=v.id where v.sku='1452' group by v.sku"
Ovo je ključni test. Zapiši polaznu zalihu Z (npr. 75). U razmaku od nekoliko sekundi: u Dashboardu smanji 1452 za 1 (Z → Z−1), a odmah zatim na masteru pokreni naredbu ispod koja mu oduzima 2 od njegove trenutne razine. Pričekaj dva prolaza (oko minute).
ssh -i ~/.ssh/rasadnik paveljame@178.105.119.208 'P=/var/www/dev-master.rasadnik-milic.hr; wp --path=$P eval "\$p=wc_get_product(174152); wc_update_product_stock(\$p, 2, \"decrease\"); echo \"master sada: \", wc_get_product(174152)->get_stock_quantity(), \"\n\";"'
sleep 70; docker compose -f compose.dev.yml exec -T postgres psql -U plant_garden -d plant_garden -c "select v.sku, sum(sl.\"stockOnHand\") as vendure from product_variant v join stock_level sl on sl.\"productVariantId\"=v.id where v.sku='1452' group by v.sku"; ssh -i ~/.ssh/rasadnik paveljame@178.105.119.208 'wp --path=/var/www/dev-master.rasadnik-milic.hr eval "echo \"master: \", wc_get_product(174152)->get_stock_quantity(), \"\n\";"'
U storefrontu kupi 1 komad SKU 1452 i narudžbu dovedi do isporuke. Dok je samo rezervirana, pokret je ALLOCATION koji se namjerno ne šalje. Zatim tu narudžbu otkaži.
docker compose -f compose.dev.yml exec -T postgres psql -U plant_garden -d plant_garden -c "select id, type, quantity from stock_movement order by id desc limit 5"
docker compose -f compose.dev.yml exec -T postgres psql -U plant_garden -d plant_garden -c "select id, left(ref,8) ref, sku, delta, \"qtyAfter\", \"sentAt\" is not null as sent, note from woo_stock_movement order by id desc limit 6"
Upiši zalihu na masteru mimo dnevnika, pa u bloku Automatika klikni „Uskladi sad”.
ssh -i ~/.ssh/rasadnik paveljame@178.105.119.208 'P=/var/www/dev-master.rasadnik-milic.hr; PFX=$(wp --path=$P db prefix); wp --path=$P db query "UPDATE ${PFX}postmeta SET meta_value=999 WHERE post_id=174152 AND meta_key=\"_stock\""; wp --path=$P db query "UPDATE ${PFX}wc_product_meta_lookup SET stock_quantity=999 WHERE product_id=174152"; wp --path=$P cache flush; echo "master sada 999, dnevnik nije dirnut"'
Prvo isključi kvačicu „Dnevno usklađivanje” i spremi: pločica mora reći ne, a gumb „Uskladi sad” i dalje raditi. Vrati je na uključeno.
Zatim postavi način na „Isključeno”, spremi, i u Dashboardu promijeni zalihu 1452 za −1. Pričekaj minutu.
U postavkama provjeri da je upisan e-mail za greške. U WP adminu (WooCommerce → Vendure Stock Sync) privremeno pokvari zajedničku tajnu (dodaj slovo) i spremi. Pričekaj dva prolaza, pa vrati tajnu.
Kad pošalješ izvještaj, brojke idu u spec pod „Faza 3 — izmjereno”, u README oba plugina, u flora-atlas/stanje/plugin-inventory.md (Live-verified, faze 1–3), roadmap 57 i na ovu stranicu. Tek onda potprojekt 2 (nexus).
Slaže se sam iz kvačica i polja iznad. Kopiraj i zalijepi u razgovor — iz njega se vidi točno gdje je stalo, bez dodatnih pitanja.
Dokaz za deploy: flora-base/sync-nexus/ansible.log bilježi dvadeset tri pokretanja 16. rujna, od 09:58 do 21:09 — ovdje je do 18. 9. navečer pisalo „dvadeset", a prebrojavanje po PLAY [Refuse a run that would quietly match nothing] unutar zapisa toga dana daje 23. Zadnje dovršeno je u 20:58 sa sync-probe : ok=40 changed=10 — poslije spajanja E16 (18:03) i E17, pa server nosi oba. Sadržaj same ploče nije očitan iz ove sesije; dokaz je uspješan deploy, ne pregled ekrana. Taj je dnevnik ujedno jedini zapis o tome što je na serveru, a u .gitignore je — živi na jednom računalu i nestaje s njim. Dok nema CI-ja ni deploy zapisa koji preživi, „što je gore” mjeri se ponovnim čitanjem te datoteke.
Rječnik se 16. rujna promijenio: ono što se do tada zvalo zaglavljeno na svim ekranima i u pošti sada se zove nesinkronizirano (E17, vlasnikova odluka — razlika koja je preživjela tri kruga i dva sata nije zaglavljen stroj nego promjena koja nije stigla). Stariji odjeljci ove stranice nose staru riječ jer opisuju ono što je tada pisalo; adresa ?zaglavljeno=1 i interna imena namjerno ostaju.
Sinkronizacija već ima dnevno usklađivanje i mail za vlastite greške. Ono što nema je vanjski svjedok. Ako se u Vendureu i na masteru istodobno pokvari isto, oba će tvrditi da je sve u redu; ako master padne, neće javiti da je pao; ako netko zalihu upiše ravno u bazu, mimo WooCommercea, dnevnik o tome ne zna ništa — to je 11. 9. i izmjereno, upis broja 999 nije ostavio nikakav trag.
Nexus je zaseban mali server koji rješava tri stvari koje iznutra nisu rješive. Usporedbu više od dva sustava: sinkronizacija zna za master i Vendure, a hrvatski i slovenski child nitko ne uspoređuje ni s čim. Dokaz da je izvor živ: šutnja je nalaz, a sustav koji šuti ne može sam prijaviti da šuti. Povijest: kad razlika iskoči, prvo je pitanje kad je nastala i što se u međuvremenu događalo, a na to danas nema odgovora.
Nexus ništa ne ispravlja i ni u jedan sustav ne piše. On prima, uspoređuje, pamti i viče; ispravak je uvijek ljudska radnja u Vendureu ili na masteru. Ne zove ni izvore — sav promet ide od izvora prema njemu, pa nijedna instalacija zbog nadzora ne treba otvoren put prema van. Specifikacija iza svega ovoga je flora-atlas/specs/specs/2026-09-11-nadzor-zaliha-nexus-design.md.
Nadzor ne smije dijeliti stroj s onim što nadzire, jer tada pad stroja ušutka i nadzor. Adresa je sync-probe.rasadnik-milic.hr.
Master, hrvatski child, slovenski child i Vendure. Dakle i skripta za djecu, koja promjene mora izračunati sama iz vlastitog prošlog snimka, i sva četiri para usporedbe.
Puna stanja zaliha žive sedam dana, zatim se sažimaju u jedan redak po danu i izvoru. Pokreti, narudžbe i rezultati usporedbi ostaju trideset dana. Razlog je veličina: četiri izvora × oko tisuću i pol šifri × šest izvještaja dnevno ≈ 36.000 redaka na dan, odnosno preko milijun u mjesec dana.
Ključ u varijabli okoline. Namjerno ne isti put kojim šalje Vendure: nadzor mora moći vikati i kad je pokvareno upravo ono što nadzire.
Stalo bi u besplatni plan i ne bi moglo postati plaćeno samo od prometa, ali bi tražilo prepisivanje u JavaScript i projektiranje oko granica od 10 ms procesorskog vremena po pozivu, 50 podzahtjeva i 50 upita u bazu po pozivu. Nexus zato ostaje PHP server, kako je i planirano.
Ništa od ovoga sesija ne kupuje, ne otvara i ne izmišlja. Tajne nikad ne ulaze u repozitorij; u testovima su lažne. Stupac desno kaže koji korak stane bez toga.
| Što | Detalj | Blokira |
|---|---|---|
| VPS i DNS zapis | Ne treba novi VPS. Odlukom od 11. 9. nexus ide na postojeći kontrolni server, kroz docker compose, iza nginxa koji je već ondje i već ima certifikate — Let's Encrypt nije dio ovog koraka. Trebaju: pristup tom stroju (SSH korisnik i ključ, sudo), slobodan port za petlju, gdje nginx drži vhostove, i DNS za sync-probe.rasadnik-milic.hr prema tom stroju. Tajne u .env — lozinku dashboarda, API token, četiri tajne izvora i NEXUS_TRUSTED_PROXIES — upisuješ ti, playbook ih ne vidi. | riješeno 14. 9. nexus radi na tom stroju |
| SMTP2GO račun i ključ | Račun na SMTP2GO-u i API ključ; uz to adresa (ili adrese) primatelja i adresa pošiljatelja, čija domena mora biti verificirana kod SMTP2GO-a prije živog slanja. | riješeno — od 15. 9. ključ, pošiljatelj i primatelji mogu se upisati i na stranici postavki (iza druge lozinke), a ne samo u .env; ondje je i gumb za probnu poruku |
| Četiri tajne, jedna po izvoru | woocommerce-master, woocommerce-hr, woocommerce-si, vendure. Generiraj ih sam (openssl rand -hex 32) i drži kod sebe. Tajna je po izvoru namjerno: kompromitirani child ne smije slati izvještaje u ime mastera. | riješeno — upisane 14. 9. Vendureovi podkanali ne traže nove tajne: kanal se potpisuje tajnom poslužitelja i ne upisuje se u NEXUS_SOURCES |
| Cron na masteru i oba childa | Pristup cronu na masteru, HR childu i SI childu, i potvrda da na njima postoji wp-cli — skripta se pokreće kroz wp eval-file. Na te strojeve ti upisuješ i tri WooCommerce tajne. | riješeno — cronovi postavljeni playbookom; ostaje jednokratni backfill=7 nakon iduće isporuke skripte |
| Iduća isporuka | Redom: deploy-nexus.yml, pa deploy-sources.yml na dev djecu i tek onda na produkciju, pa Vendure plugin običnim buildom. Nakon toga jednom po dućanu wp eval-file … backfill=7 i na kraju bin/migracija.php --apply na nexusu — time stari pokreti iz razlike snimaka dobivaju vrijeme narudžbe. U Vendureu još označiš kanale i upišeš jednu tajnu. | čeka tebe |
| Umami (neobavezno) | Ako želiš statistiku ploče: NEXUS_ANALYTICS_URL, NEXUS_ANALYTICS_ID i, samo ako želiš i snimke sesija, NEXUS_ANALYTICS_RECORDER_URL u .env. Bez njih se ne učitava nijedna tuđa skripta. Adrese ekrana nose šifre i imena izvora, pa tko drži Umami to može čitati — kod self-hostinga to si ti. | ugrađeno 15. 9. |
Prvi dan nakon puštanja u rad nexus je analiziran kao cjelina: kod, testovi i produkcijska snimka (Postavke → Dijagnostika → Puni izvoz, 3 MB). Mjerenje je odlučilo o prioritetima: sa šest izvora svaki izvještaj je ponovno vrtio svih 15 parova, pa je prozor od 12 usporedbi u lib/Stuck.php trajao 4 sata a ne „dva dana”, 35 od 36 zaglavljenih nalaza stajalo je na 12 krugova „od iste minute”, u 8 sati je otišlo 9 mailova za skup koji se nije mijenjao (3 u 10 minuta, jer HR i SI jave prije mastera), a 99,3 % od 373 tisuće redaka usporedbi bilo je iz devet skrivenih Woo↔Vendure parova. Vlasnik je odabrao stavke koje traju dan ili manje; tri veće (A2, A3, N2) su odgođene, S3 odbijen. Svaka izgrađena stavka ima svoj commit, testove i odlomak u flora-base/sync-nexus/README.md; plan i puni zapis su u flora-atlas/specs/plans/2026-09-15-nadzor-zaliha-e10-analiza.md.
| # | Kategorija | Prijedlog | Prio | Dana | Stanje | Bilješka |
|---|---|---|---|---|---|---|
| S1 | sigurnost | CSRF token na svim POST rutama | P1 | 1 | gotovo | b5a58661 · SameSite=Lax ne štiti od susjeda na istoj domeni (www., master.) |
| S2 | sigurnost | display_errors isključen + globalni handler | P1 | 0.5 | gotovo | 332e0a4d · izmjereno: slika ne učitava php.ini, trace je išao u tijelo |
| S3 | sigurnost | Rotacija tajne s prijelaznim prozorom | P2 | 1 | odbijeno | odluka vlasnika 15. 9. |
| S4 | sigurnost | SMTP2GO ključ šifriran u bazi | P2 | 1 | nije odabrano | |
| S5 | sigurnost | Granice ulaza i nginx limit_req | P2 | 1 | gotovo | f5f1394e · nginx dio provjeren u kontejneru, na hostu tek s deployem |
| A1 | arhitektura | Usporedba samo kad se ulaz promijenio | P1 | 2 | gotovo | 17020803 · 90 → 30 usporedbi po ciklusu; pregled i dalje vidi sve pokidano |
| A2 | arhitektura | Razbiti index.php na tablicu ruta i module | P2 | 3 | odgođeno | veće od jednog dana |
| A3 | arhitektura | Kontekst zahtjeva s memoizacijom | P2 | 1.5 | odgođeno | veće od jednog dana |
| A4 | arhitektura | CI: testovi i syntax-check na svakom pushu | P2 | 0.5 | nije odabrano | |
| A5 | arhitektura | Sirovo tijelo izvještaja 7 dana | P3 | 1 | gotovo | 4ca51f24 · report_bodies, bin/izvjestaj.php |
| O1 | otpornost | Noćni backup baze izvan servera | P1 | 1 | nije odabrano | preporuka: prvo sljedeće |
| O2 | otpornost | Heartbeat prema vanjskom nadzoru | P1 | 0.5 | nije odabrano | preporuka: prvo sljedeće |
| O3 | otpornost | Izlazni red za poštu | P2 | 2 | nije odabrano | |
| O4 | otpornost | BEGIN IMMEDIATE i eksplicitni busy_timeout | P1 | 0.5 | nije odabrano | |
| O5 | otpornost | Potpis u trenutku slanja (Woo skripta) | P1 | 0.5 | nije odabrano | 401 ako čitanje kataloga traje dulje od 5 min |
| N1 | nove mogućnosti | Epizode zaglavljenosti kao trajna tablica | P1 | 2 | nije odabrano | |
| N2 | nove mogućnosti | Razlike objašnjene zabilježenim prodajama | P2 | 2 | odgođeno | veće od jednog dana |
| N3 | nove mogućnosti | Dnevnik promjena postavki | P2 | 1 | gotovo | febee84c · tab Postavke → Promjene, ključ pošte se ne bilježi |
| N4 | nove mogućnosti | Prijedlozi i istek pravila zanemarivanja | P2 | 1.5 | nije odabrano | |
| N5 | nove mogućnosti | Polje problems iz dućana na ekranu | P3 | 1 | gotovo | 546a3e14 · nečitljivi artikli na pilulici, u panelu i u mailu |
| P1 | poboljšanje | Zaglavljeno mjereno vremenom i novim ulazom, „najmanje od” | P1 | 1 | gotovo | c5f63a6c · 3 kruga + 2 h + obje strane javile |
| P2 | poboljšanje | Otisak pošte s vrstom i zaglavljenošću, čekanje istine | P1 | 1 | gotovo | f9ebebe3 · jedan krug, jedan mail |
| P3 | poboljšanje | XLSX izvoz nosi sve retke i sve filtre | P1 | 0.5 | gotovo | 26387584 · rezao je na 500 i gubio dva filtra |
| P4 | poboljšanje | Dijagnostika, mail i ekran kažu isto | P1 | 0.5 | nije odabrano | pet malih ispravaka |
| P5 | poboljšanje | Vendure izvještaj usklađen s Woo prije izlaska iz skrivenih | P2 | 1 | nije odabrano | prije SI cutovera |
| E11 | poboljšanje | Prekidač kartice „van synca” i modal na karticama dućana | P1 | 1 | deployano 16. 9. | 774fcb11, 144633fa · 4 od 35 na crvenoj kartici, 35 razbacanih po karticama dućana; grana nexus-e11, 590 testova |
| E12 | poboljšanje | Preglednost dijagnostike: sažetak na vrhu i sklopivi odsjeci | P1 | 1 | deployano 16. 9. | ed5d6007 … fd24f899 · 5 pločica, naslovi kao pitanja, pošta 7 dana s filtrom, izvoz po odsjeku; grana worktree-nexus-e12, 598 testova |
| E13 | poboljšanje | Dorada dijagnostike po pregledu: kapa, linkovi, info paneli, boje | P1 | 0.5 | deployano 16. 9. | 551e6c60 · dva kvara iz E12 (pillovi dizali stranicu, kapa bila po paru) plus zašto-je-prigušeno, linkovi, tri info panela i popravak trake; 603 testa |
| E14 | nove mogućnosti | Narudžbe: kalendarski rasponi u zoni čitatelja i dva grafa | P2 | 1 | deployano 16. 9. | 1f55c229 … a3aa3b41 · NexusRaspon kao čista funkcija, testovi na oba smjera ljetnog računanja; grana worktree-nexus-e14, 618 testova |
| E16 | poboljšanje | Rasponi na povijesti i crti, oblačići, starost problema, dijagnoza žive stranice | P2 | 1 | spojeno 16. 9. | bcaf54ae … 3796a102 · šest commitova na grani worktree-nexus-e16, 632 testa |
| E15 | poboljšanje | Pošta: imena dućana, blok stanja na vrhu, mobilni raspored | P1 | 1 | deployano 16. 9. | 0e4dfefc … d67e5a43 · interni ključ bio je jedini jezik pošte; uz to dva kvara koja je našao end-to-end test; grana worktree-nexus-e15, 623 testa |
| E17 | poboljšanje | Pošta: sekcije po dućanu u obliku modala, prekidač kartice na oba mjesta | P1 | 0.5 | spojeno 16. 9. | grana worktree-nexus-e16, 637 testova; uz to popravljeno kreiranje adresnice iz popisa narudžbi (GLS je preimenovao argument, a test je tvrdio zastarjeli oblik) |
Što deploy mijenja na produkciji. Usporedbe se pišu samo kad je jedna od dviju strana poslala nov izvještaj (stari redci bez id-ova usporede se još jednom); mail o neslaganju ide samo u krugu koji je pokrenuo izvještaj izvora istine, dakle jednom po ciklusu; otvorena kartica preglednika dobit će 403 na prvom spremanju dok se ne osvježi (token obrasca); greške idu u docker logs sync-nexus, ne na ekran; nginx dobiva dvije zone (/api/ 30/min, /prijava 10/min) kroz novu datoteku u conf.d. Deploy: iz worktreeja, ansible-playbook deploy-nexus.yml --check --diff pa bez --check; skripte na dućanima se ne mijenjaju.
Ako se radi još troje od neodabranih: O1 backup baze izvan servera (jedini primjerak podataka), O2 heartbeat (nadzornik ne može javiti vlastitu smrt), O5 potpis u trenutku slanja (spor master → 401 nerazlučiv od krive tajne).
Potprojekt 2 je gotov i radi uživo od 14. 9.: nexus stoji u flora-base/sync-nexus/, svih osam koraka je napisano i deployano, a dorada poslije toga (E9) ide po onome što se vidi na pravim podacima, a E10 po analizi od 15. 9. — 580 testova. Ovo su gotovi promptovi za svih osam koraka, redoslijedom iz odjeljka 13 specifikacije flora-atlas/specs/specs/2026-09-11-nadzor-zaliha-nexus-design.md. Svaki korak dolje kaže na koji broj testova mora doći; E1 je svoj prag od 18 prešao s 41. Prvih pet koraka radi lokalno, na lažnim izvještajima, bez ijednog živog sustava; tek šesti traži pristup tuđim strojevima.
Kako se petlja vrti: kopiraj Developer prompt u novu sesiju i pusti je da radi. Kad javi da je gotovo, kopiraj Verifikator prompt u drugu sesiju — ona ništa ne popravlja, nego samo provjerava, sama, bez oslanjanja na izvještaj prve. Tek kad verifikator kaže „prihvatiti”, korak je gotov i ide se na sljedeći.
shema, potpis, idempotencija · ništa se još ne uspoređuje
Prazan server koji zna samo primiti: SQLite shema svih osam redaka tablice iz odjeljka 5 specifikacije, jedna ruta POST /api/report iza potpisa, i pravilo da ponovljeni izvještaj ne upisuje ništa. Usporedbe nema, pošte nema, sučelja nema — to su koraci E2, E3 i E5.
Potpis se ne izmišlja: ista shema kao u potprojektu 1 (HMAC-SHA256 nad metodom, rutom, vremenom i tijelom, tolerancija ±300 s), koja je već napisana na obje strane i dokazana uživo. Razlika je jedna i važna: tajna je po izvoru, da kompromitirani child ne može slati izvještaje u ime mastera.
Vlasnik: četiri tajne, jedna po izvoru (woocommerce-master, woocommerce-hr, woocommerce-si, vendure). Generiraj ih sam (npr. openssl rand -hex 32) i drži ih kod sebe — sesija ih ne izmišlja, ne commita i ne treba ih za testove, koji rade na lažnim tajnama iz fixtura. Trebaju tek na VPS-u (E8) i u skriptama (E6, E7).
# Zadatak: kostur nexusa (E1, nadzor zaliha)
Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. Pročitaj flora-atlas/stanje/README.md,
flora-atlas/prompts/README.md (posebno "The loop" i "Standing rules") i spec
flora-atlas/specs/specs/2026-09-11-nadzor-zaliha-nexus-design.md, odjeljke 3, 4,
5 i 13. Ne učitavaj više — kontekst potrošen na čitanje je kontekst nepotrošen
na mjerenje.
## Zatečeno stanje (izmjereno 11. 9. 2026)
- Nexus NE POSTOJI. Ovo je prva datoteka, i njegov broj testova danas je 0.
- Potprojekt 1 je gotov i dokazan uživo: WP plugin flora-core/wp-venture-sync
(91 test, pokreće se u Dockeru:
docker run --rm -v "$PWD":/app -w /app php:8.2-cli php tests/run.php)
i Vendure plugin flora-core/src/plugins/woocommerce-stock-sync (504 testa).
- ./flora check: 4.443 testa ukupno (3.531 u flora-coreu kroz 346 datoteka,
plus 76 flora-libs, 78 + 75 storefrontovi i 650 sync-nexus u PHP-u) — izmjereno 18. 9., 0 type errors, exit 0.
Ovaj korak NE dira nijedan TS/JS — taj broj mora ostati IDENTIČAN.
- Potpis je već napisan dvaput i dokazan: PHP strana u
flora-core/wp-venture-sync/includes/class-wvss-signature.php, TS strana u
flora-core/src/plugins/woocommerce-stock-sync/woo-signature.ts. Kopiraj shemu,
ne izmišljaj novu.
## Zadatak
Nexus ide u sync-nexus/, po uzoru na flora-core/wp-venture-sync:
public/index.php, public/api.php, lib/, views/, tests/run.php, README.md.
PHP 8.2, PDO SQLite, BEZ composera i bez frameworka.
a) Shema. Osam redaka tablice iz odjeljka 5 specifikacije, što je devet stvarnih
tablica jer orders i order_lines idu u paru: reports, stock_levels,
stock_daily, movements, orders, order_lines, comparisons, comparison_items,
alerts. Uz svaku u kodu stoji komentar s njezinom retencijom: 30 dana za sve,
OSIM stock_levels (7 dana) i alerts (90 dana). U ovom koraku se retencija
samo ZAPISUJE, ne provodi — brisanje i sažimanje su korak E4.
Putanja baze dolazi iz varijable okoline i leži IZVAN mape koju služi nginx.
b) POST /api/report prima tijelo iz odjeljka 4 specifikacije (source,
generatedAt, items, movements, orders) i upisuje ga u jednoj transakciji.
c) Potpis. HMAC-SHA256 nad "METODA\nruta\nvrijeme\ntijelo", zaglavlja
X-WVSS-Timestamp i X-WVSS-Signature, tolerancija ±300 sekundi, usporedba
hash_equals. Tajna je PO IZVORU, iz varijable okoline; popis očekivanih
izvora je postavka. Odbijen potpis = 401 BEZ tijela. Izvor kojeg nema na
popisu = 403. Vrijeme izvan tolerancije = 401.
d) Idempotencija. Par (source, generatedAt) je jedinstven u bazi, ne samo u
kodu. Ponovljeno slanje vraća 200 s točno {"duplicate": true} i ne upisuje
NIJEDAN redak (dokaži brojem redaka prije i poslije). Svjež izvještaj vraća
200 s {"stored": true, "items": N}. Ta dva oblika odgovora su ugovor za
korake E5, E6 i E7 — ako ih mijenjaš, javi, ne mijenjaj tiho.
e) Testovi u tests/run.php, istim stilom kao WP plugin (bez composera, PHP 8.2
u Dockeru): valjan potpis, krivi potpis, vrijeme +301 s i -301 s, nepoznat
izvor, tajna drugog izvora nad tuđim izvorom, duplikat, prazan items,
izvještaj s 1.500 stavki (mjeri vrijeme i zapiši ga).
## Poznate anomalije (ne popravljaj ih iz opsega)
- 554 šifre postoje samo u Vendureu, na masteru ih nema. To je zatečeno stanje
iz faze 1 (993 uparene) i NIJE kvar.
- wp_wc_product_meta_lookup na masteru drži 726 siročadi — zato se proizvodi
čitaju uz spoj na wp_posts i samo objavljeni. Tebe u ovom koraku ne dira.
- reconcileEnabled je u spremljenim postavkama Vendurea trenutno false.
## STANI i predaj — dvije vrste, ne idu na isto mjesto
- TEHNIČKI BLOKATOR (ide orkestratoru, ne vlasniku): ako SQLite u ovoj verziji
PHP-a ne da jedinstveni indeks kakav idempotencija traži, ili se shema potpisa
iz potprojekta 1 ne da prenijeti doslovno — javi i stani, ne izmišljaj drugu
shemu potpisa.
- ODLUKA ZA VLASNIKA: ništa u ovom koraku. Ako naletiš na nešto što miriše na
poslovnu odluku, to je znak da si izašao iz opsega.
## Ne diraj
flora-core/wp-venture-sync (ni jedan bajt), flora-core/ (nijedan TS),
www-plant-garden-{hr,si}/, sve .env datoteke, flora-atlas/stanje/priorities.md.
Nikakav composer, nikakav framework, nikakva vanjska knjižnica.
## Pravila
Commitovi na hrvatskom BEZ IKAKVE ATRIBUCIJE. NE pushaj — vlasnik pusha.
git add po imenu datoteke, NIKAD git add -A.
Vlasnikovi portovi 3000, 4331, 4332, 5175 i 5432 su njegovi — svoj PHP server
digni na 8090 i ugasi ga prije kraja (lsof -i :8090 prazan).
Tajne unosi vlasnik: ne izmišljaj ih, ne commitaj ih, u testovima su lažne.
Kod i README na engleskom, commit poruke na hrvatskom.
## Gotovo je kad, s brojevima kao dokazom
1. tests/run.php: nexus ima >= 18 testa, svi prolaze, exit 0. Prije ovog koraka
ih je bilo 0 — reci točan broj.
2. Devet tablica postoji (ispis .schema iz sqlite3), svaka s komentarom o
retenciji.
3. Duplikat dokazan brojem redaka: reports, stock_levels i movements prije i
poslije ponovljenog POST-a — iste brojke, odgovor {"duplicate": true}.
4. 401 bez tijela na krivi potpis (ispis curl -i), 403 na nepoznat izvor.
5. Izvještaj s 1.500 stavki: izmjereno vrijeme upisa u milisekundama.
6. ./flora check i dalje 4.443, exit 0 (nisi dirao TS — dokaži).
7. git diff --stat: samo sync-nexus/.
# Provjera: kostur nexusa (E1) Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. Ti si NEOVISNI VERIFIKATOR. Pozovi skill verifying-session-reports i drži se njegovog redoslijeda. TI NIŠTA NE POPRAVLJAŠ — ni tipfeler, ni krivi komentar. Nalaz ide u izvještaj. Polazno: nexus prije ovog koraka nije postojao, njegov broj testova bio je 0. ./flora check bio je 4.443, exit 0. ## Provjeri, sam, ne iz izvještaja 1. Pokreni tests/run.php u Dockeru i prepiši točan broj testova i exit kod. Usporedi s brojem koji sesija tvrdi. Manje od 18 je pad. 2. Ispiši shemu baze (.schema) i prebroji tablice. Devet ih mora biti. Provjeri da uz svaku u kodu stoji retencija, i da se 7 / 30 / 90 dana slažu s odjeljkom 5 specifikacije. 3. Potpis, uživo, curl-om na vlastiti server (port 8090, ugasi ga poslije): valjan potpis prolazi; promijeni jedan znak u potpisu → 401 i tijelo PRAZNO; pomakni X-WVSS-Timestamp za 301 sekundu → 401; potpiši izvor tajnom drugog izvora → ne smije proći; pošalji izvor kojeg nema na popisu → 403. 4. Idempotencija: pošalji isti izvještaj dvaput. Prebroji retke u reports, stock_levels i movements prije i poslije drugog slanja. Ako je ijedan broj narastao, to je nalaz bez obzira što odgovor kaže. 5. Potvrdi da baza NIJE u mapi koju služi web server i da se putanja čita iz varijable okoline, ne iz konstante u kodu. 6. Pokreni ./flora check sam: mora biti 4.443 i exit 0. Svaka promjena tu znači da je sesija dirala TS izvan opsega. 7. git diff --stat i git log: samo sync-nexus/, commit poruke na hrvatskom, NIJEDAN Co-Authored-By ni druga atribucija, ništa nije pushano, nijedan .env u diffu, nikakav composer.json ni vendor/. 8. Grep po diffu za stvarne tajne i lozinke. Prava tajna u repozitoriju je nalaz najviše težine. ## Izvještaj Dva popisa, bez ublažavanja: - ŠTO STOJI — svaka stavka s izlazom naredbe iza sebe. - GDJE JE KRIVO ILI NEDOKAZANO — razvrstano u netočno / nedokazano / prešućeno. Pa: tvoj broj testova, tvoj izlaz ./flora check, i jedna rečenica presude — prihvatiti / prihvatiti uz popravke (koje) / vratiti.
pet parova, tri vrste nalaza · bez pošte i bez sučelja
Četiri para: master s HR childom, master sa SI childom, master s Vendureom, HR child s Vendureom. Master je u tri od četiri jer je on izvor istine za zalihu. Tri vrste nalaza po šifri — različita količina, različit status (uključujući backorders) i šifra samo na jednoj strani.
Treća vrsta je najbučnija i zato ima vlastiti prekidač po paru: iz faze 1 se zna da Vendure ima 554 šifre kojih na masteru nema, i to ne smije svaka četiri sata slati poštu. Zadano je uključeno za parove među WooCommerceima, isključeno za parove s Vendureom. Šifra se uspoređuje doslovno — razlika u praznini ili veličini slova je nalaz, ne stvar koju treba tiho zagladiti.
Usporedba se pokreće nakon svakog primljenog izvještaja, ali samo ako su svi očekivani izvori javili unutar zadnja četiri sata. Nepotpuna usporedba bi lagala, pa se u tom slučaju ne radi ništa.
Dopuna 11. 9. (odluka vlasnika, nakon izvršenja): dodan je i peti par — SI child s Vendureom, prekidač isključen kao i na ostalim parovima s Vendureom, jer SI prvi prelazi na novi sustav. Traženo je i da se izvor uklanja postavkom: jedna riječ iz NEXUS_SOURCES i njegovi parovi nestaju s njim, a izvještaj koji i dalje šalje dobiva 403. Donji prompt je ostavljen kakav je izvršen, s četiri para.
# Zadatak: usporedba (E2, nadzor zaliha)
Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. Pročitaj flora-atlas/prompts/README.md
("The loop", "Standing rules"), spec
flora-atlas/specs/specs/2026-09-11-nadzor-zaliha-nexus-design.md odjeljke 6 i 13,
i sync-nexus/README.md. Više ne treba.
## Zatečeno stanje
- Korak E1 je gotov: nexus u sync-nexus/ prima potpisane izvještaje i
sprema ih; njegov tests/run.php ima >= 18 testa (prebroji, ne vjeruj ovom
broju naslijepo — ako se ne slaže, to je prvi nalaz).
- Ništa se još ne uspoređuje i ništa se ne šalje.
- ./flora check: 4.443, exit 0. Ovaj korak NE dira nijedan TS.
## Zadatak
a) Četiri para, imenovana u postavkama, ne u kodu raspršena:
master↔HR child, master↔SI child, master↔Vendure, HR child↔Vendure.
b) Tri vrste nalaza po šifri: qty_mismatch, status_mismatch (status ILI
backorders), only_one_side.
c) Prekidač po paru za only_one_side. ZADANO: uključen za parove među
WooCommerceima, ISKLJUČEN za oba para s Vendureom. Razlog je 554 šifre iz
faze 1 koje postoje samo u Vendureu i koje NISU kvar.
d) Šifra se uspoređuje doslovno. Bez trim(), bez strtolower(), bez ikakve
normalizacije. "1452" i "1452 " su dvije različite šifre i to je nalaz.
e) Okidač: nakon svakog primljenog izvještaja provjeri je li SVAKI očekivani
izvor javio unutar zadnja 4 sata. Ako jest, usporedi najnovije izvještaje
svakog izvora. Ako nije, ne radi ništa i zapiši zašto (npr. "čeka
woocommerce-si").
f) Rezultat ide u comparisons i comparison_items iz sheme E1. Nijedna nova
tablica bez javljanja.
g) Testovi. Bez pošte, bez sučelja — u ovom koraku nexus ne šalje ništa.
## Poznate anomalije (ne popravljaj ih)
- 554 Vendure-only šifri: zatečeno stanje, NE smije postati uzbuna. Ako tvoj
test s realnim brojkama pokaže 554 nalaza only_one_side na paru s Vendureom
a prekidač je zadano isključen, sve radi kako treba.
- 993 šifre su uparene između mastera i Vendurea (mjereno u fazi 1).
- Vendure ima šifre kojih master nema; obrnuto se u fazi 1 nije dogodilo.
## STANI i predaj
- TEHNIČKI BLOKATOR (orkestratoru): ako se ispostavi da izvještaji nemaju sve
što usporedba treba (npr. backorders nedostaje s neke strane) — javi i stani.
NE izmišljaj zadanu vrijednost za polje kojeg nema.
- ODLUKA ZA VLASNIKA: ako nađeš peti par koji ima smisla (npr. HR child ↔ SI
child), predloži ga s cijenom i STANI. Ne dodaj ga sam.
## Ne diraj
Potpis, idempotenciju i shemu iz E1 — ako ih moraš mijenjati, to je STANI.
flora-core/wp-venture-sync, flora-core/, www-plant-garden-{hr,si}/, sve .env datoteke.
Nikakva pošta, nikakav dashboard, nikakav cron u ovom koraku.
## Pravila
Commitovi na hrvatskom BEZ ikakve atribucije; NE pushaj. git add po imenu, nikad
git add -A. Portovi 3000, 4331, 4332, 5175 i 5432 su vlasnikovi; svoj server na
8090 i ugasi ga. Tajne ne izmišljaš i ne commitaš.
## Gotovo je kad, s brojevima kao dokazom
1. tests/run.php: nexus >= 40 testa (bilo ih je >= 18), svi prolaze, exit 0.
Reci koliko si točno dodao.
2. Za svaki od četiri para postoji test svake od tri vrste nalaza, plus test
prazne strane (izvor bez ijedne stavke) — to je 4 × 3 + 4 = 16 slučajeva
pokrivenih, nabroji ih.
3. Dokaz da prekidač radi: isti ulaz, prekidač uključen pa isključen, broj
nalaza se mijenja za točno onoliko koliko ima šifri samo na jednoj strani.
4. Dokaz da nepotpun skup ne uspoređuje: tri izvora od četiri → 0 usporedbi i
zapisan razlog.
5. Dokaz doslovne usporedbe: "1452" i "1452 " daju nalaz, ne tišinu.
6. ./flora check i dalje 4.443, exit 0.
7. git diff --stat: samo sync-nexus/.
# Provjera: usporedba (E2) Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. NEOVISNI VERIFIKATOR, skill verifying-session-reports. NIŠTA NE POPRAVLJAŠ. Polazno: prije ovog koraka nexus je imao >= 18 testa i nije uspoređivao ništa. ## Provjeri, sam 1. Pokreni tests/run.php: točan broj (>= 40) i exit kod. Usporedi s izvještajem. 2. Dokaži da novi testovi PADAJU bez nove logike: uzmi parent commit (git archive u scratchpad), ubaci nove testove i pokreni ih tamo. Test koji prolazi i na starom kodu ne dokazuje ništa i to je nalaz. 3. Sam sastavi lažne izvještaje i provjeri sve tri vrste nalaza na SVA ČETIRI para. Ne prepisuj brojke iz izvještaja sesije. 4. Prekidač only_one_side: provjeri ZADANE vrijednosti u postavkama. Ako je za ijedan par s Vendureom zadano uključen, to je pad — 554 Vendure-only šifri bi značilo uzbunu svaka četiri sata. 5. Doslovnost: pošalji "1452" s jedne i "1452 " s druge strane. Mora biti nalaz. Grep po kodu za trim, strtolower, mb_strtolower, str_replace nad šifrom. 6. Okidač: pusti tri izvora od četiri i potvrdi da je broj usporedbi 0. Pa pusti četvrti i potvrdi da usporedba nastane. Pa pusti izvor star 5 sati i potvrdi da se opet ne uspoređuje. 7. Potvrdi da nexus NIJE poslao nijedan mail (u ovom koraku ga još ni nema) i da nije nastala nijedna nova tablica izvan sheme iz E1. 8. ./flora check: 4.443, exit 0. 9. git diff --stat protiv "ne diraj" liste; commit poruke bez atribucije; ništa pushano. ## Izvještaj ŠTO STOJI / GDJE JE KRIVO ILI NEDOKAZANO (netočno, nedokazano, prešućeno), sve s izlazom naredbe. Na kraju presuda u jednoj rečenici.
SMTP2GO, otisak skupa, tihi prozor 24 h, mail o šutnji izvora
Dvije vrste pošte. Neslaganje: jedan mail po skupu, s prvih pedeset šifri i poveznicom na dashboard, a isti skup se ne šalje ponovno unutar 24 sata. Istost se mjeri otiskom skupa šifri i para, ne brojem — nova šifra u skupu znači novi mail. To je ista logika kao prigušenje u potprojektu 1, gdje je 11. rujna izmjereno da pet padova daje točno dva maila, jedan po vrsti.
Šutnja izvora: ako izvor ne javi u 4 sata i 30 minuta, zaseban mail. Pola sata tolerancije postoji da spor cron ne pravi lažnu uzbunu. Ponavlja se jednom na 24 sata dok izvor šuti, a kad progovori stiže kratka potvrda.
Put je namjerno drugi nego onaj kojim šalje Vendure: SMTP2GO kroz njihov API, ključ u varijabli okoline. Nadzor mora moći vikati i kad je pokvareno baš ono što nadzire.
Vlasnik: otvori račun na SMTP2GO i izradi API ključ. Sesija ga ne izrađuje i ne vidi — u testovima je lažni ključ i lažni HTTP klijent.
Vlasnik: reci na koju adresu (ili adrese) mail ide i s koje adrese se šalje. Domena pošiljatelja mora biti verificirana kod SMTP2GO-a prije živog slanja.
# Zadatak: pošta (E3, nadzor zaliha)
Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. Pročitaj flora-atlas/prompts/README.md
("The loop", "Standing rules"), spec
flora-atlas/specs/specs/2026-09-11-nadzor-zaliha-nexus-design.md odjeljak 7, i
sync-nexus/README.md.
## Zatečeno stanje
- E1 i E2 su gotovi: nexus prima izvještaje i uspoređuje PET parova (četiri iz
specifikacije plus SI↔Vendure, dodan odlukom vlasnika 11. 9.). Njegov
tests/run.php ima 104 testa. Prebroji sam prije nego počneš.
- Nexus dosad NIJE poslao nijedan mail. Ovo je prvi put.
- Prigušenje pošte iz potprojekta 1 je dokazano uživo 11. 9.: pet padova s 401
dalo je točno DVA maila, jedan po vrsti. Isti oblik prigušenja tražim ovdje.
- ./flora check: 4.443, exit 0. Ovaj korak NE dira TS.
## Zadatak
a) SMTP2GO kroz njihov API (curl iz PHP-a, bez composera i bez knjižnice),
ključ i adrese iz varijabli okoline. NE preko Vendureovog transporta — to je
odluka vlasnika od 11. 9. i razlog je da nadzor mora vikati i kad je
pokvareno ono što nadzire.
b) Mail o neslaganju: naslov "Neslaganja zaliha: N šifri, parovi X i Y",
u tijelu PRVIH PEDESET šifri s brojkama po izvoru i poveznicom na dashboard.
Ako ih je više od pedeset, u tijelu piše koliko ih je ostalo.
c) Tihi prozor. Otisak = stabilan hash nad parom + POREDANIM skupom šifri.
Isti otisak unutar 24 sata: mail se NE šalje, ali se pokušaj zapiše u alerts.
Skup s jednom novom šifrom ima drugi otisak i mail ide odmah.
d) Mail o šutnji: izvor koji nije javio 4 h 30 min dobiva vlastiti mail
("izvor X šuti od ..."), ponavlja se jednom na 24 sata, a kad izvor
progovori šalje se kratka potvrda. Ovo je ODVOJENA vrsta od neslaganja i ima
vlastito prigušenje.
e) Slanje ide kroz jedan sitan HTTP klijent koji se u testovima zamjenjuje
lažnim, da testovi NIKAD ne zovu mrežu. Test koji zove SMTP2GO je pad.
f) Tekst mailova na hrvatskom.
## Poznate anomalije (ne popravljaj ih)
- 554 Vendure-only šifri su zatečeno stanje. Prekidač iz E2 ih drži izvan
nalaza; tvoj posao je da ih slučajno ne vratiš u mail nekim drugim putem.
- WooMultistore 5.4.9 na dev-masteru ispisuje upozorenje pri svakom upisu
zalihe. To nije tvoj mail i ne prijavljuje se kroz nexus.
## STANI i predaj
- ODLUKA ZA VLASNIKA: primatelji i adresa pošiljatelja. Ako ih nema u
varijablama okoline kad počneš, predloži oblik i STANI — ne upisuj adresu u
kod ni u test.
- ODLUKA ZA VLASNIKA: šalje li se kratka potvrda "izvor se javio" uvijek ili
samo ako je prije toga poslan mail o šutnji. Predloži i pitaj.
- TEHNIČKI BLOKATOR (orkestratoru): ako SMTP2GO API traži nešto što se bez
računa ne da ni ispitati (npr. obavezno verificirana domena za sandbox), javi
i stani — ne prelazi tiho na mail() ni na SMTP.
## Ne diraj
Vendureov email transport i email-studio plugin. Potpis, shemu i usporedbu iz
E1 i E2 osim kroz javljeno proširenje. flora-core/wp-venture-sync. Sve .env
datoteke. Vlasnikove portove.
## Pravila
Commitovi na hrvatskom BEZ atribucije; NE pushaj; git add po imenu, nikad -A;
svoj server na 8090 i ugašen prije kraja; tajne unosi vlasnik.
## Gotovo je kad, s brojevima kao dokazom
1. tests/run.php: nexus >= 58 testa (bilo >= 40), svi prolaze, exit 0.
2. Dokaz prigušenja s brojkama: isti skup poslan tri puta u 24 sata → točno
JEDAN mail i dva zapisa o prigušenom pokušaju. Skup + jedna nova šifra →
drugi mail. Ukupno 2 maila na 4 pokušaja.
3. Mail o šutnji: izvor tih 4 h 29 min → 0 mailova; 4 h 31 min → 1 mail;
još 12 sati šutnje → i dalje 1; nakon 24 h → 2.
4. Skup od 120 šifri: u tijelu točno 50 šifri i rečenica da ih je još 70.
5. Nijedan test ne zove mrežu — dokaži (pokreni testove bez mreže).
6. ./flora check i dalje 4.443, exit 0.
7. git diff --stat: samo sync-nexus/; grep po diffu bez ijednog pravog
ključa i bez prave adrese.
# Provjera: pošta (E3) Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. NEOVISNI VERIFIKATOR, skill verifying-session-reports. NIŠTA NE POPRAVLJAŠ. Polazno: prije ovog koraka nexus je imao >= 40 testa i nije slao poštu. ## Provjeri, sam 1. tests/run.php: točan broj (>= 58), exit kod. Usporedi s izvještajem sesije. 2. Novi testovi moraju PASTI na parent commitu — dokaži kopijom (git archive). 3. Prigušenje ponovi sam, brojkama: isti skup tri puta → 1 mail; skup s jednom novom šifrom → 2. mail. Ako brojka odstupa, ne presuđuj dok ne objasniš zašto. 4. Otisak: potvrdi da se računa nad PAROM i POREDANIM skupom šifri, ne nad brojem i ne nad redoslijedom kojim su stigle. Promijeni redoslijed istih šifri — otisak mora ostati isti. 5. Šutnja: 4 h 29 min → 0 mailova, 4 h 31 min → 1. Provjeri da je to ODVOJENO prigušenje od onog za neslaganja (jedno ne smije ušutkati drugo). 6. Skup od 120 šifri: prebroji šifre u tijelu maila. Mora ih biti točno 50. 7. Pokreni testove BEZ mreže i potvrdi da prolaze. Grep po testovima za smtp2go, curl_exec, file_get_contents s http — test koji zove mrežu je nalaz. 8. Grep po cijelom diffu za prave API ključeve i prave adrese e-pošte. Bilo koja prava tajna u repozitoriju je nalaz najviše težine. 9. Potvrdi da Vendureov email transport i email-studio NISU dirani (bajt na bajt). 10. ./flora check: 4.443, exit 0. git log bez atribucije, ništa pushano. ## Izvještaj ŠTO STOJI / GDJE JE KRIVO ILI NEDOKAZANO, sve s izlazom naredbe, pa presuda u jednoj rečenici.
dnevni posao u 3:00 · sažimanje, brisanje, VACUUM
Jedan dnevni posao u tri ujutro, u točno ovom redoslijedu: prvo upiši dnevne sažetke za puna stanja starija od sedam dana, pa ta stanja obriši, zatim obriši sve što je prešlo svoju granicu (30 dana za sve osim alerts, koji ima 90), pa VACUUM.
Brojka koja objašnjava zašto: četiri izvora puta tisuću i pol šifri puta šest izvještaja dnevno je oko 36.000 redaka na dan, odnosno preko milijun u mjesec dana. Uz sedam dana punih stanja baza stoji na oko 250.000 redaka, što je za SQLite sitnica.
# Zadatak: retencija (E4, nadzor zaliha) Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. Pročitaj flora-atlas/prompts/README.md i spec flora-atlas/specs/specs/2026-09-11-nadzor-zaliha-nexus-design.md odjeljak 5. ## Zatečeno stanje - E1–E3 gotovi: nexus prima, uspoređuje i šalje poštu; tests/run.php >= 58 testa. Prebroji sam. - Retencija je dosad bila SAMO komentar uz tablice. Ništa se ne briše, ništa ne sažima. Baza raste. - Očekivani rast: 4 izvora × ~1.500 šifri × 6 izvještaja dnevno ≈ 36.000 redaka na dan. Uz 7 dana punih stanja ravnotežno stanje je ≈ 250.000 redaka. - ./flora check: 4.443, exit 0. Ovaj korak NE dira TS. ## Zadatak Jedan posao, jedna ulazna točka koju cron zove u 03:00 (cron se postavlja u E8; ovdje samo napravi naredbu i dokaži je ručno). Redoslijed je dio ugovora: a) SAŽMI: za svaki dan i izvor stariji od 7 dana upiši jedan redak u stock_daily (dan, izvor, broj šifri, zbroj količina, broj nula). Sažimanje je idempotentno — drugi prolaz istog dana ne smije udvostručiti retke. b) OBRIŠI stock_levels starije od 7 dana, ali TEK nakon što je sažetak upisan. Ako sažimanje padne, brisanje se NE izvodi. c) OBRIŠI sve preko granice: reports, movements, orders, order_lines, comparisons, comparison_items i stock_daily starije od 30 dana; alerts stariji od 90 dana. d) VACUUM na kraju, i tek na kraju. e) Suhi način rada (--dry-run) koji ispiše što bi obrisao i sažeo, a ne dira ništa. f) Posao zapisuje što je napravio: broj sažetih dana, broj obrisanih redaka po tablici, veličinu datoteke prije i poslije VACUUM-a. ## STANI i predaj - TEHNIČKI BLOKATOR (orkestratoru): ako se pokaže da se order_lines ne daju obrisati bez sirotišta (redak bez svoje narudžbe), javi i stani — ne ostavljaj sirotinju i ne izmišljaj kaskadu tiho. - ODLUKA ZA VLASNIKA: ako ispadne da 7 dana punih stanja nije dovoljno za ekran "vremenska crta" iz E5 (koji traži 7 dana), predloži brojku i STANI. Ne mijenjaj retenciju sam. ## Ne diraj Potpis, prijem i usporedbu. Podatke starije od granice NE briši ručno mimo posla. flora-core/wp-venture-sync, flora-core/, sve .env datoteke. ## Pravila Commitovi na hrvatskom BEZ atribucije; NE pushaj; git add po imenu, nikad -A; svoj server na 8090, ugašen prije kraja; tajne unosi vlasnik. ## Gotovo je kad, s brojevima kao dokazom 1. tests/run.php: nexus >= 70 testa (bilo >= 58), svi prolaze, exit 0. 2. Test s umjetnom poviješću: napuni bazu s 30 dana podataka (reci točan broj redaka), pokreni posao, pa izmjeri. Očekujem: stock_levels drži samo 7 dana, stock_daily ima točno jedan redak po danu i izvoru za starije, alerts preživi do 90 dana, sve ostalo do 30. 3. Idempotencija sažimanja: drugi prolaz istog dana → 0 novih redaka u stock_daily. Broj prije i poslije. 4. Redoslijed dokazan: namjerno obori sažimanje i pokaži da brisanje NIJE izvedeno i da nijedan redak nije nestao. 5. Veličina datoteke baze prije i poslije VACUUM-a, u bajtovima. 6. --dry-run: 0 promijenjenih redaka, uz ispis onoga što bi napravio. 7. ./flora check i dalje 4.443, exit 0. git diff --stat: samo sync-nexus/.
# Provjera: retencija (E4) Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. NEOVISNI VERIFIKATOR, skill verifying-session-reports. NIŠTA NE POPRAVLJAŠ. Polazno: prije ovog koraka nexus je imao >= 58 testa i nije brisao ni sažimao ništa; retencija je bila samo komentar uz tablice. ## Provjeri, sam 1. tests/run.php: točan broj (>= 70), exit kod. 2. Novi testovi padaju na parent commitu — dokaži kopijom. 3. Sam napuni bazu poviješću od 40 dana i pokreni posao. Prebroji retke PO TABLICI prije i poslije. Provjeri svaku granicu posebno: 7 dana za stock_levels, 30 za reports/movements/orders/order_lines/comparisons/ comparison_items/stock_daily, 90 za alerts. Granica koja je "otprilike" je nalaz — provjeri i redak točno na granici i redak jednu sekundu preko nje. 4. Sažimanje: potvrdi da je zbroj količina u stock_daily jednak zbroju iz punih stanja tog dana, prije nego su obrisana. Sažetak koji ne odgovara izvoru je gori od nikakvog. 5. Idempotencija: pokreni posao dvaput zaredom i potvrdi 0 novih redaka. 6. Redoslijed: obori sažimanje (npr. samo za čitanje) i potvrdi da brisanje nije izvedeno. Podatak izgubljen prije nego je sažet je nalaz najviše težine. 7. --dry-run: potvrdi 0 promjena brojanjem redaka prije i poslije. 8. ./flora check: 4.443, exit 0. git log bez atribucije, ništa pushano. ## Izvještaj ŠTO STOJI / GDJE JE KRIVO ILI NEDOKAZANO, s izlazom naredbe, pa presuda.
pet ekrana, četiri JSON rute · lozinka za ljude, token za strojeve
Pet ekrana na hrvatskom: pregled po parovima (četiri pločice i traka stanja izvora), tablica neslaganja (šifra, naziv, količina iz svakog sustava, status, backorders, poveznica na proizvod, filtar po paru i vrsti), povijest trideset dana (graf i popis usporedbi), vremenska crta sedam dana (pokreti i narudžbe svih izvora na jednoj crti — ekran na koji se ide kad treba odgovoriti kada je razlika nastala) i narudžbe sedam dana s oznakom „naručeno više nego što zaliha ima".
Uz njih četiri JSON rute za isto. Dvije odvojene brave: lozinka u kolačiću za ljude, Basic token za API. Jedno nije drugo — token koji otvara i ekrane je pad.
# Zadatak: dashboard i JSON API (E5, nadzor zaliha)
Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. Pročitaj flora-atlas/prompts/README.md i
spec flora-atlas/specs/specs/2026-09-11-nadzor-zaliha-nexus-design.md odjeljke 7
i 8.
## Zatečeno stanje
- E1–E4 gotovi: prijem, usporedba, pošta, retencija. tests/run.php >= 70 testa.
Prebroji sam.
- Sučelja nema. Ovo je prvi HTML koji nexus služi.
- ./flora check: 4.443, exit 0. Ovaj korak NE dira TS i NE dira storefronte.
## Zadatak
Tehnika je namjerno dosadna: PHP 8.2, PDO, SQLite, public/index.php za ljude i
public/api.php za strojeve, uz lib/ i views/. BEZ composera, bez JS okvira.
Graf je inline SVG, bez knjižnice. Sučelje na hrvatskom.
a) PET ekrana, točno onih iz odjeljka 8:
1. Pregled po parovima: četiri pločice (zelena/crvena), broj neslaganja i
vrijeme zadnje usporedbe, uz traku stanja izvora (kad je koji zadnji javio).
2. Tablica neslaganja: šifra, naziv, količina iz svakog sustava s istaknutom
razlikom, status, backorders, poveznica na proizvod u svakom sustavu;
filtar po paru i po vrsti nalaza.
3. Povijest 30 dana: graf broja neslaganja po danu (inline SVG) i popis
usporedbi.
4. Vremenska crta 7 dana: pokreti i narudžbe svih izvora na jednoj crti,
filtar po šifri i izvoru.
5. Narudžbe 7 dana po izvoru, s oznakom "naručeno više nego što zaliha ima"
(odjeljak 7, zadnji odlomak). Ta se oznaka NE mailira.
b) ČETIRI JSON rute: /api/latest, /api/mismatches?since=,
/api/activity?days=7&sku=, /api/orders?days=7.
c) Dvije odvojene brave:
- ljudi: jedna lozinka iz varijable okoline, sesija u kolačiću, HttpOnly,
Secure, SameSite=Lax, plus ograničenje broja pokušaja prijave;
- strojevi: Basic autentikacija s tokenom iz DRUGE varijable okoline.
Token NE smije otvarati ekrane, lozinka NE smije otvarati API. To je test.
d) Nexus ne služi datoteku baze ni pod kojim putem. To je test.
e) Sve brojke na ekranima dolaze iz baze. Nijedan primjer, nijedan lažni redak,
nijedan "placeholder" broj u HTML-u.
## Poznate anomalije (ne popravljaj ih)
- 554 Vendure-only šifri se na ekranu SMIJU vidjeti (prekidač gasi poštu, ne
pogled), ali ne smiju bojati pločicu para u crveno ako je prekidač isključen.
Ako ti se to čini spornim, to je STANI, ne tiha odluka.
- reconcileEnabled je u Vendureu trenutno false — nexus to ne zanima, on ionako
ništa ne ispravlja.
## STANI i predaj
- ODLUKA ZA VLASNIKA: oblik poveznice na proizvod u svakom sustavu (master, HR,
SI, Vendure Dashboard). Predloži četiri obrasca i STANI.
- TEHNIČKI BLOKATOR (orkestratoru): ako neki ekran traži podatak kojeg u shemi
iz E1 nema, javi i stani. NE dodaj tablicu ni stupac tiho.
## Ne diraj
Prijem, usporedbu, poštu i retenciju. Nijedan gumb koji mijenja zalihu — nexus
NIŠTA NE ISPRAVLJA (odjeljak 12 specifikacije). Nikakvo drugo korisničko ime i
nikakve uloge: jedna lozinka, kako je odlučeno 9. 9.
flora-core/wp-venture-sync, flora-core/, www-plant-garden-{hr,si}/, sve .env datoteke.
## Pravila
Commitovi na hrvatskom BEZ atribucije; NE pushaj; git add po imenu, nikad -A;
svoj PHP server na 8090 i ugašen prije kraja (lsof -i :8090 prazan); vlasnikovi
portovi 3000, 4331, 4332, 5175 i 5432 se ne diraju; tajne unosi vlasnik.
## Gotovo je kad, s brojevima kao dokazom
1. tests/run.php: nexus >= 82 testa (bilo >= 70), svi prolaze, exit 0.
2. Svih pet ekrana otvoreno u pregledniku na 8090, sa snimkom zaslona, i svaki
pokazuje brojke koje se slažu sa SQL upitom nad istom bazom — priloži oboje.
3. Sve četiri JSON rute vraćaju 200 s tokenom i 401 bez njega (curl -i).
4. Token na /index.php → 401 ili preusmjerenje na prijavu, NE sadržaj.
Kolačić sesije na /api/latest → 401, NE sadržaj.
5. Pokušaj dohvata datoteke baze kroz web server → 404 ili 403 (pokaži curl).
6. Ograničenje prijave: nakon N krivih pokušaja (reci N) prijava se odbija;
pokaži brojkom.
7. ./flora check i dalje 4.443, exit 0. git diff --stat: samo sync-nexus/.
8. lsof -i :8090 prazan prije nego javiš da si gotov.
# Provjera: dashboard i API (E5) Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. NEOVISNI VERIFIKATOR, skill verifying-session-reports. NIŠTA NE POPRAVLJAŠ — ni tipfeler u HTML-u. Polazno: prije ovog koraka nexus je imao >= 70 testa i nije služio nijednu stranicu. ## Provjeri, sam 1. tests/run.php: točan broj (>= 82), exit kod. Novi testovi padaju na parentu — dokaži kopijom. 2. Digni server sam na 8090 i OTVORI svih pet ekrana. Ne vjeruj snimkama iz izvještaja. Za svaki ekran napiši što si vidio. 3. Za barem tri brojke s ekrana napiši SQL kojim si ih provjerio i usporedi. Brojka koja se ne slaže s bazom je nalaz, makar izgledala razumno. 4. Dvije brave, četiri kombinacije: lozinka na ekranu (prolazi), lozinka na API (pada), token na API (prolazi), token na ekranu (pada). Sve četiri s curl -i. 5. Datoteka baze kroz web server: pokušaj je dohvatiti po svim očitim putanjama. Ako je itko dohvati, to je nalaz najviše težine. 6. Ograničenje prijave: probaj krivu lozinku dok te ne odbije i prebroji pokušaje. 7. Potvrdi da NIGDJE nema gumba, forme ni rute koja piše u master ili Vendure. Nexus ništa ne ispravlja — grep po kodu za POST forme izvan prijave. 8. Potvrdi da su brojke iz baze, ne iz koda: grep za tvrdo upisane brojeve i primjere u views/. 9. ./flora check: 4.443, exit 0. git diff --stat protiv "ne diraj" liste. git log bez atribucije, ništa pushano. lsof -i :8090 prazan kad završiš. ## Izvještaj ŠTO STOJI / GDJE JE KRIVO ILI NEDOKAZANO, s izlazom naredbe i s onim što si stvarno vidio na ekranu, pa presuda u jednoj rečenici.
report-woocommerce.php · master iz dnevnika, djeca iz prošlog snimka
Jedna skripta s dvije grane. Master ima sync plugin, pa ima i dnevnik: čita proizvode i varijacije s wc_get_product(), uzima pokrete od prošlog izvještaja (ne fiksnih četiri sata, da se ništa ne izgubi ako ciklus preskoči) i narudžbe iz zadnja četiri sata.
Djeca nemaju plugin pa nemaju ni dnevnik: promjene se dobivaju usporedbom s prošlim snimkom koji skripta čuva kraj sebe kao JSON. Prvi prolaz nema s čim usporediti, pa šalje prazan popis pokreta i to označi poljem firstRun.
Stanje se čita, ne računa: wc_get_product() po svakom proizvodu i varijaciji, nikako iz wc_product_meta_lookup — ta tablica na dev-masteru drži 726 siročadi, izmjereno 10. rujna. U snimku su samo objavljeni proizvodi, isto pravilo kao u fazi 1.
Vlasnik: pristup cronu na masteru i na oba childa (HR i SI), i potvrda da wp-cli na njima postoji — skripta se pokreće kroz wp eval-file.
Vlasnik: tajne za woocommerce-master, woocommerce-hr i woocommerce-si (iste one iz E1) upisuju se na te strojeve, i to ti radiš — sesija ih ne vidi.
# Zadatak: skripte na WordPressima (E6, nadzor zaliha)
Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. Pročitaj flora-atlas/prompts/README.md,
spec flora-atlas/specs/specs/2026-09-11-nadzor-zaliha-nexus-design.md odjeljke 4
i 9, i flora-core/wp-venture-sync/README.md (dio o snimku i o dnevniku).
## Zatečeno stanje (izmjereno)
- E1–E5 gotovi: nexus prima, uspoređuje, šalje poštu, briše i služi ekrane.
tests/run.php >= 82 testa. Prebroji sam.
- WP plugin flora-core/wp-venture-sync ima 91 test i VEĆ zna raditi snimak i voditi
dnevnik pokreta. Master ga ima, DJECA GA NEMAJU — to je cijeli razlog za dvije
grane.
- wp_wc_product_meta_lookup na dev-masteru drži 726 SIROČADI (mjereno 10. 9.).
Zato se proizvodi čitaju uz spoj na wp_posts i samo objavljeni, i zato se
stanje čita s wc_get_product(), nikad iz lookup tablice.
- Dev-master: 1.000 proizvoda, 0 varijacija, svi sa šifrom, backorders posvuda
"no". Varijacije se dakle na devu NE MOGU dokazati — to je poznata rupa, reci
je naglas, nemoj je zaobići lažnim podatkom.
- ./flora check: 4.443, exit 0. Ovaj korak NE dira TS.
## Zadatak
Skripta ide u sync-nexus/sources/report-woocommerce.php, pokreće se s
wp eval-file, i sama prepoznaje je li na masteru ili na childu (ili joj se to
kaže varijablom okoline — odaberi i objasni).
a) GRANA ZA MASTER: items iz wc_get_product() po svakom proizvodu I svakoj
varijaciji; movements iz dnevnika koji je postavio sync plugin, OD PROŠLOG
IZVJEŠTAJA (ne fiksnih 4 sata); orders iz wc_get_orders za zadnja 4 sata.
b) GRANA ZA DJECU: items isto; movements iz razlike prema PROŠLOM SNIMKU koji
skripta čuva kraj sebe kao JSON; prvi prolaz šalje prazne pokrete i postavlja
firstRun. Snimak se piše ATOMSKI (privremena datoteka pa rename), da prekinut
prolaz ne ostavi pola snimka.
c) Obje grane: potpis po shemi iz potprojekta 1, tajna iz varijable okoline ili
iz wp-config konstante (odaberi i objasni), POST na /api/report nexusa.
d) ŠALJE SE I KAD NEMA PROMJENA — šutnja je nalaz, pa se prazan izvještaj i
dalje mora poslati.
e) SUHI NAČIN RADA (--dry-run): ispiše što bi poslao (broj stavki, broj pokreta,
broj narudžbi, prvih pet šifri) i NE pošalje ništa. Ovo je ono čime vlasnik
prvi put pokreće skriptu na živom stroju.
f) Testovi idu u tests/run.php nexusa (ista PHP 8.2 Docker mašinerija), s lažnim
wc_get_product i lažnim dnevnikom.
## Poznate anomalije (ne popravljaj ih, ne zaobilazi ih)
- 726 siročadi u lookup tablici mastera: razlog za spoj na wp_posts, ne kvar
koji trebaš čistiti.
- WooMultistore 5.4.9 ispisuje upozorenje pri svakom upisu zalihe na
dev-masteru. Tvoja skripta NIŠTA NE UPISUJE, pa je ne bi smjela ni vidjeti;
ako je vidiš, to je nalaz.
- Debug mu-plugin iz faze 0, wvss-hook-trace.php, još je instaliran na
dev-masteru. NE uklanjaj ga i ne oslanjaj se na njega.
- 554 šifre postoje samo u Vendureu. Na WordPressu ih nema i to je uredu.
## STANI i predaj
- TEHNIČKI BLOKATOR (orkestratoru): nemaš pristup živim WordPressima. Sve se
gradi i dokazuje na lažnim podacima i na dev-masteru ako ga vlasnik otvori.
Ako ti treba pristup — javi i STANI, ne izmišljaj brojke s produkcije.
- ODLUKA ZA VLASNIKA: gdje stoji tajna na childu (wp-config konstanta ili
varijabla okoline u cronu) i gdje smije ležati JSON snimak (izvan web roota).
Predloži i STANI.
- ODLUKA ZA VLASNIKA: ako se pokaže da je snimak na childu pregrub, spec
predviđa plugin i na childu u načinu koji SAMO ČITA. To je novi opseg —
predloži cijenu i STANI, ne kreni sam.
## Ne diraj
Nijedan bajt plugina flora-core/wp-venture-sync — ovo je zasebna skripta, ne
proširenje plugina. Nijedan upis u WooCommerce: skripta samo čita.
flora-core/, www-plant-garden-{hr,si}/, sve .env datoteke. Produkcijski master se NE dira ni
na koji način u ovom koraku.
## Pravila
Commitovi na hrvatskom BEZ atribucije; NE pushaj; git add po imenu, nikad -A;
svoj server na 8090 i ugašen prije kraja; vlasnikovi portovi 3000, 4331, 4332,
5175 i 5432 se ne diraju; tajne unosi vlasnik i nikad ne idu u repozitorij.
Ako išta ideš deployati Ansibleom, produkcija se cilja ISKLJUČIVO izričitim
-e target_hosts=production_master, a flora-core/wp-venture-sync/ansible/inventory.yml
je lokalan i git-ignoriran — ne commitaj ga i ne prepisuj.
## Gotovo je kad, s brojevima kao dokazom
1. tests/run.php: nexus >= 94 testa (bilo >= 82), svi prolaze, exit 0.
2. Suhi prolaz obje grane nad lažnim podacima, s brojkama: broj stavki, pokreta
i narudžbi, i 0 poslanih zahtjeva (dokaži da mreža nije dirana).
3. Grana za djecu: prvi prolaz → firstRun true i 0 pokreta; drugi prolaz nakon
promjene jedne šifre → točno 1 pokret s točnom deltom; treći bez promjene →
0 pokreta, ali izvještaj SE ŠALJE.
4. Prekinut prolaz (ubij proces usred pisanja snimka) → snimak ostaje cjelovit i
sljedeći prolaz ne izmisli lažne pokrete. Pokaži kako si to izazvao.
5. Dokaz da se stanje čita s wc_get_product(): grep po skripti za
wc_product_meta_lookup mora biti PRAZAN (osim u komentaru koji objašnjava
zašto se ne koristi).
6. Izvještaj primljen: pošalji ga svom lokalnom nexusu na 8090 i pokaži da je
upisan, pa pošalji isti ponovno i pokaži {"duplicate": true}.
7. ./flora check i dalje 4.443, exit 0. git diff --stat: samo
sync-nexus/.
# Provjera: skripte na WordPressima (E6) Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. NEOVISNI VERIFIKATOR, skill verifying-session-reports. NIŠTA NE POPRAVLJAŠ. Polazno: prije ovog koraka nexus je imao >= 82 testa; WP plugin ima 91 test i NIJE se smio dirati. ## Provjeri, sam 1. tests/run.php nexusa: točan broj (>= 94), exit kod. Novi testovi padaju na parentu — dokaži kopijom. 2. WP plugin: pokreni njegovih 91 test i potvrdi da ih je i dalje 91 i da prolaze. Pa git diff nad flora-core/wp-venture-sync — mora biti PRAZAN. Ijedan promijenjen bajt ondje je nalaz. 3. Grep po skripti za wc_product_meta_lookup. Ako se koristi za čitanje stanja, to je pad — 726 siročadi je razlog zbog kojeg to pravilo postoji. 4. Grep za svaki upis: update_post_meta, wc_update_product_stock, save(), wp_insert_post. Skripta SAMO ČITA. Ijedan upis je nalaz najviše težine. 5. Grana za djecu, sam je provozaj: prvi prolaz (firstRun, 0 pokreta), promijeni jednu šifru pa drugi prolaz (točno 1 pokret, točna delta), treći bez promjene (0 pokreta ali izvještaj poslan). Prepiši brojke. 6. Atomski snimak: prekini pisanje i potvrdi da sljedeći prolaz ne izmisli pokrete. Ako sesija to nije dokazala, to je NEDOKAZANO, ne "vjerojatno radi". 7. Suhi način: potvrdi 0 mrežnih zahtjeva (pokreni bez mreže). 8. Potvrdi da ništa nije poslano ni na jedan živi WordPress i da u diffu nema nijedne prave adrese, tajne ni inventory.yml. 9. ./flora check: 4.443, exit 0. git log bez atribucije, ništa pushano. ## Izvještaj ŠTO STOJI / GDJE JE KRIVO ILI NEDOKAZANO, s izlazom naredbe. Posebno reci što se NIJE dalo dokazati na devu (varijacije, put child → master) — to nije pad, ali mora biti napisano. Na kraju presuda u jednoj rečenici.
woo-stock-report, treći ScheduledTask u sync pluginu
Treći raspoređeni zadatak woo-stock-report u postojećem pluginu woocommerce-stock-sync, svaka četiri sata. Danas su ondje točno dva zadatka (woo-stock-sync svake minute i woo-stock-reconcile), pa je ovaj treći.
Ne gradi se ništa novo: snapshot i movements već postoje i koriste se za sinkronizaciju. Zadatak im dodaje narudžbe, potpisuje vlastitom tajnom iz postavki i šalje na nexus.
Vlasnik: tajna za izvor vendure (ista ona iz E1) i adresa nexusa upisuju se u postavke plugina kroz Dashboard, nakon što sesija napravi polja. Sesija ih ne upisuje i ne vidi.
# Zadatak: raspoređeni zadatak woo-stock-report (E7, nadzor zaliha)
Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. Pročitaj flora-atlas/prompts/README.md
("The loop", "Standing rules"), spec
flora-atlas/specs/specs/2026-09-11-nadzor-zaliha-nexus-design.md odjeljke 4 i 9,
i README plugina flora-core/src/plugins/woocommerce-stock-sync. Ako postoji
projektni skill vendure-plugin, pozovi ga.
## Zatečeno stanje (izmjereno 11. 9. 2026)
- Plugin flora-core/src/plugins/woocommerce-stock-sync ima 504 testa i TOČNO DVA
raspoređena zadatka u scheduled-tasks.ts: woo-stock-sync (svake minute) i
woo-stock-reconcile. Tvoj je TREĆI. Prebroji sam prije nego počneš.
- ./flora check: 4.443 ukupno (3.531 flora-core u 346 datoteka, 76 + 78 + 75 + 650) — 20. 9.,
0 type errors, exit 0. Ti DODAJEŠ testove → flora-core mora biti > 3.531.
- snapshot i movements već postoje i koriste se; woo-signature.ts već zna
potpisati po shemi iz potprojekta 1.
- Nexus (E1–E6) prima izvještaje na POST /api/report, vraća 200
{"stored": true, "items": N} za svjež i 200 {"duplicate": true} za ponovljen.
- reconcileEnabled je u spremljenim postavkama trenutno FALSE. To je zatečeno
stanje i NE mijenjaš ga.
## Zadatak
a) Treći ScheduledTask, id woo-stock-report, raspored svaka 4 sata,
preventOverlap uključen, timeout kakav ostala dva imaju (pogledaj i objasni
ako odstupaš).
b) Sastavi izvještaj iz odjeljka 4: items iz postojećeg snapshota, movements iz
postojećeg dnevnika OD PROŠLOG IZVJEŠTAJA, orders iz zadnja 4 sata.
PONOVNO ne piši ni snapshot ni movements — koristi ih.
c) Potpis vlastitom tajnom iz postavki plugina (novo polje), zasebno od tajne
koju sync već koristi. Adresa nexusa je također postavka.
d) Zadatak koji je isključen ili bez adrese/tajne ne pada nego se tiho preskoči
i to zapiše u run log, isto kao ostala dva.
e) Suhi način rada: mutacija ili polje koje ispiše što bi poslao i ne pošalje.
f) Prijevodi Dashboarda za sva nova polja — sva četiri jezika koja plugin već
ima. Neprevedeno polje je pad.
g) Konvencija #3 (strojna površina) vrijedi: ako dodaješ radnju koju čovjek može
pokrenuti, mora postojati i put kroz API iza iste permisije. Ako to ovdje
nema smisla, objasni zašto u jednoj rečenici.
## Poznate anomalije (ne popravljaj ih)
- 554 šifre postoje samo u Vendureu, na masteru ih nema. Tvoj izvještaj ih ŠALJE
kao i sve ostale; nexus ih gasi prekidačem iz E2. Ne filtriraj ih ovdje.
- reconcileEnabled = false. Ne diraj.
- Dashboard tsconfig ne type-checka plugin-root dashboard.tsx — gate je Vite
build, ne tsc. Ako diraš Dashboard, provjeravaj kroz build.
## STANI i predaj
- TEHNIČKI BLOKATOR (orkestratoru): ako se pokaže da snapshot ili movements ne
daju oblik koji odjeljak 4 traži bez mijenjanja postojeće sinkronizacije —
javi i STANI. Sinkronizacija je dokazana uživo i ne prepravlja se zbog nadzora.
- ODLUKA ZA VLASNIKA: ide li izvještaj po kanalu ili jedan za cijeli Vendure.
Predloži i STANI.
## Ne diraj
woo-stock-sync i woo-stock-reconcile — ni raspored, ni timeout, ni logiku.
Postojeće postavke sinkronizacije. reconcileEnabled. vendure-config.ts se NE
proširuje usput. flora-core/wp-venture-sync. Sve .env datoteke. Migracije moraju
biti reverzibilne.
## Pravila
Commitovi na hrvatskom BEZ atribucije; NE pushaj; git add po imenu, nikad -A.
Svoj Vendure na 3010 — vlasnikovi 3000, 4331, 4332, 5175 i 5432 se NE diraju.
Ugasi svoje prije kraja (lsof -i :3010 prazan). Tajne unosi vlasnik.
Kod i docs na engleskom.
## Gotovo je kad, s brojevima kao dokazom
1. scheduled-tasks.ts ima TRI zadatka; ispiši popis zadataka iz pokrenutog
servera, ne iz koda.
2. ./flora check: flora-core > 3.531 (reci koliko si dodao), ukupno > 4.443,
0 type errors, exit 0. Plugin > 504 testa.
3. Novi test PADA na parent commitu — dokaži izlazom iz kopije (git archive).
4. Uživo na 3010: pokreni zadatak ručno, uhvati izvještaj na lokalnom nexusu
(8090) i pokaži broj stavki, pokreta i narudžbi. Pošalji isti drugi put i
pokaži {"duplicate": true}.
5. Krivi potpis prema nexusu → 401, i zadatak to zapiše, ne sruši se.
6. Prijevodi: sva nova polja u sva četiri jezika — ispiši ključeve i potvrdi da
nijedan ne fali.
7. git diff --stat: samo plugin woocommerce-stock-sync (i migracija ako je bilo
potrebna). Nijedna druga datoteka.
8. Baza kao zatečena: broj narudžbi i stockAllocated prije i poslije (iste
brojke).
# Provjera: woo-stock-report (E7)
Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. NEOVISNI VERIFIKATOR, skill
verifying-session-reports. NIŠTA NE POPRAVLJAŠ.
Mjerila PRIJE ovog koraka: plugin woocommerce-stock-sync 504 testa i TOČNO DVA
raspoređena zadatka; ./flora check 4.443 (flora-core 3.531 u 346 datoteka) — 20. 9., exit 0.
## Provjeri, sam
1. ./flora check sam: flora-core > 3.531, ukupno > 4.443, 0 type errors, exit 0.
Usporedi sa svakim brojem iz izvještaja.
2. Prebroji testove plugina (> 504) i zadatke (točno 3, ni jedan manje ni više).
Popis zadataka uzmi iz POKRENUTOG servera, ne iz koda.
3. Novi test pada na parentu — dokaži kopijom parent commita.
4. Uživo na 3010: pokreni woo-stock-report i uhvati izvještaj na svom nexusu
(8090). Provjeri da se broj stavki slaže sa SQL upitom nad Vendure bazom.
5. Ponovljeno slanje → {"duplicate": true}. Krivi potpis → 401 i uredan zapis,
bez pada zadatka.
6. Potvrdi da woo-stock-sync i woo-stock-reconcile NISU dirani: git diff nad ta
dva zadatka i njihovim testovima mora biti prazan, a reconcileEnabled i dalje
false u spremljenim postavkama (provjeri SQL-om, ne pogledom u kod).
7. Prijevodi: prođi sva četiri jezika i potvrdi da nijedno novo polje nije
engleski ostatak. Provjeri kroz BUILD Dashboarda, ne kroz vite dev.
8. Migracija (ako je ima) je reverzibilna — pokreni je dolje pa gore.
9. Baza kao zatečena: broj narudžbi i stockAllocated prije i poslije tvoje
provjere. Svoje testne podatke očisti i dokaži brojkama.
10. git diff --stat protiv "ne diraj" liste; git log bez atribucije; ništa
pushano; nijedan .env u diffu. lsof -i :3010 prazan na kraju.
## Izvještaj
ŠTO STOJI / GDJE JE KRIVO ILI NEDOKAZANO, s izlazom naredbe, pa presuda u
jednoj rečenici.
sync-probe.rasadnik-milic.hr · postojeći kontrolni server, docker compose iza host nginxa, cron, Europe/Zagreb
Ansible uloga po uzoru na postojeću za WP plugin, s vlastitom datotekom zaliha koja se ne commita. Na stroju nema PHP-a i ne instalira se: sve ide kroz docker compose sa slikom php:8.2-cli, koja već nosi pdo_sqlite, curl, json i sqlite3. Host nginx i certifikati su već ondje. Cron i vremenska zona Europe/Zagreb. Nexus je jedini dio ovog sustava s domenom prema van i zato prima samo potpisane zahtjeve, ima ograničenje prijave i ne služi datoteku baze.
Pa živi prolaz, točno onaj iz odjeljka 11 specifikacije: tri lažna izvještaja s namjernim odstupanjem, mail stigne jednom, drugi prolaz s istim skupom ne pošalje ništa, dashboard pokazuje točno te šifre. Zatim jedan izvor namjerno ušuti i mail o šutnji mora stići nakon četiri i pol sata.
Vlasnik: pristup postojećem kontrolnom serveru — SSH korisnik, ključ i sudo. Novi VPS se ne kupuje: odluka od 11. 9. je da nexus ide na stroj koji već radi, kroz docker compose.
Vlasnik: DNS zapis za sync-probe.rasadnik-milic.hr prema tom stroju, i postojeći certifikat za tu domenu — host nginx ih već izdaje i playbook ih ne dira.rtifikat i korak stane na prvoj prepreci.
Vlasnik: sve tajne na stroj (četiri po izvoru, SMTP2GO ključ, lozinka dashboarda, API token) unosiš ti. One nikad ne ulaze u repozitorij ni u Ansible datoteke koje se commitaju.
Ovaj prompt je zastario i ne treba ga pokretati. Napisan je prije vlasnikovih odluka od 11. 9. — nema novog VPS-a, nema instalacije PHP-a ni Let's Encrypta na stroju, nego docker compose na postojećem kontrolnom serveru iza nginxa koji već ima certifikate. Ono što je stvarno napravljeno stoji u flora-atlas/specs/specs/2026-09-11-ansible-deploy-nexus-design.md i flora-atlas/specs/plans/2026-09-11-nadzor-zaliha-e8-ansible-deploy.md. Zadržan je kao zapis polazišta.
# Zadatak: Ansible, VPS i živi prolaz (E8, nadzor zaliha)
Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. Pročitaj flora-atlas/prompts/README.md,
spec flora-atlas/specs/specs/2026-09-11-nadzor-zaliha-nexus-design.md odjeljke
10, 11 i 12, i flora-core/wp-venture-sync/ansible/ (uloga, deploy.yml,
inventory.example.yml) kao uzor.
## Zatečeno stanje
- E1–E7 gotovi: nexus radi lokalno, prima od sva četiri izvora, uspoređuje,
šalje poštu, briše i služi pet ekrana. tests/run.php >= 94 testa.
Prebroji sam.
- Postojeća Ansible uloga za WP plugin cilja hostove ovako:
hosts: "{{ target_hosts | default('dev_master') }}", a stvarni inventory.yml
je LOKALAN I GIT-IGNORIRAN (u repozitoriju je samo inventory.example.yml).
Istu podjelu napravi i ovdje.
- ./flora check: 4.443, exit 0. Ovaj korak NE dira TS.
## Zadatak
a) Ansible uloga za nexus u sync-nexus/ansible/: PHP 8.2 s pdo_sqlite,
curl i json; nginx; certifikat preko Let's Encrypta; cron; vremenska zona
Europe/Zagreb. Uz nju deploy.yml i inventory.example.yml. STVARNI inventory
se NE commita — dodaj ga u .gitignore isto kao onaj za WP plugin.
b) nginx: služi samo public/, NIKAD mapu s bazom. HTTPS, HSTS, bez listanja
mapa. Dokaži da datoteka baze nije dohvatljiva.
c) Cron: retencijski posao (E4) u 03:00 po Europe/Zagreb. Provjera šutnje
izvora (E3) dovoljno često da 4 h 30 min ima smisla — predloži interval i
obrazloži ga.
d) Tajne se na stroj unose izvan repozitorija (varijable okoline za servis).
Nijedna tajna, adresa ni lozinka ne smije završiti u commitu.
e) ŽIVI PROLAZ, redoslijedom iz odjeljka 11, i to je glavni dokaz ovog koraka:
1. tri lažna izvještaja s namjernim odstupanjem → točno JEDAN mail;
2. drugi prolaz s ISTIM skupom → nijedan mail;
3. dashboard pokazuje točno te šifre i nijednu drugu;
4. jedan izvor namjerno ušuti → mail o šutnji nakon 4 h 30 min.
Točku 4 ne skraćuj mijenjanjem sata na stroju ako to razbija ostalo; ako
pomičeš vrijeme, reci točno kako i vrati ga.
## Poznate anomalije (ne popravljaj ih)
- 554 Vendure-only šifri NE SMIJU proizvesti mail. Ako ti u živom prolazu stigne
mail o njima, to je nalaz, ne "očekivano".
- WooMultistore 5.4.9 upozorenja i debug mu-plugin wvss-hook-trace.php na
dev-masteru nisu tvoj posao.
- reconcileEnabled je false u Vendureu. Ne diraj.
## STANI i predaj
- TEHNIČKI BLOKATOR (orkestratoru): nema VPS-a ili DNS zapis ne pokazuje na
njega. JAVI I STANI. Ne registriraj domene, ne kupuj poslužitelje, ne
postavljaj nexus negdje drugdje "privremeno".
- ODLUKA ZA VLASNIKA: tko sve dobiva pristup dashboardu i s koje se mreže smije
otvarati (svi, ili samo s poznatih adresa). Predloži i STANI.
## Ne diraj
Produkcijski master i oba childa — u ovom koraku se NE deployaju. Produkcija se
općenito cilja ISKLJUČIVO izričitim -e target_hosts=production_master; bez toga
sve ide na dev. flora-core/wp-venture-sync/ansible/inventory.yml je lokalan i
git-ignoriran: ne commitaj ga, ne prepisuj, ne čitaj naglas.
Sve .env datoteke. Vlasnikovi portovi 3000, 4331, 4332, 5175, 5432.
## Pravila
Commitovi na hrvatskom BEZ atribucije; NE pushaj — vlasnik pusha. git add po
imenu datoteke, NIKAD git add -A (u ovom koraku je to najopasnije, jer u radnoj
mapi lako završi inventory ili datoteka s tajnama). Tajne unosi vlasnik.
## Gotovo je kad, s brojevima kao dokazom
1. ansible-playbook --syntax-check prolazi; suhi prolaz (--check) protiv
inventory.example.yml pokazuje što bi napravio.
2. tests/run.php i dalje >= 94, exit 0 (ništa nisi slomio).
3. Živi prolaz, sve četiri točke, s brojkama: 3 izvještaja → 1 mail;
ponovljeni skup → 0 mailova; dashboard pokazuje točno N šifri i to su iste
one iz maila; šutnja 4 h 30 min → 1 mail o šutnji, a javljanje izvora →
potvrda.
4. curl na datoteku baze kroz domenu → 403 ili 404 (priloži izlaz).
5. Certifikat valjan (openssl s_client ili curl -v), TLS radi.
6. date na stroju pokazuje Europe/Zagreb; crontab -l pokazuje posao u 03:00.
7. git diff --stat: samo sync-nexus/ i .gitignore. Nijedan inventory,
nijedna tajna, nijedna prava adresa e-pošte u commitu — dokaži grepom.
8. ./flora check i dalje 4.443, exit 0.
# Provjera: Ansible, VPS i živi prolaz (E8) Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base. NEOVISNI VERIFIKATOR, skill verifying-session-reports. NIŠTA NE POPRAVLJAŠ — ni krivi redak u nginxu. Polazno: prije ovog koraka nexus je radio samo lokalno; tests/run.php >= 94. ## Provjeri, sam 1. tests/run.php: točan broj (>= 94), exit kod. 2. ansible-playbook --syntax-check i --check sam pokreni. Prepiši izlaz. 3. NAJVAŽNIJE — tajne i inventory: git log -p nad ovim koracima, grep za ključeve, lozinke, tokene, prave adrese e-pošte i za inventory.yml. Provjeri i da je .gitignore stvarno pokriva. Ijedna prava tajna u repozitoriju je nalaz najviše težine i presuda je "vratiti". 4. Živi prolaz ponovi SAM, ne vjeruj izvještaju: pošalji tri lažna izvještaja s odstupanjem, prebroji mailove (mora biti 1), ponovi isti skup (mora biti 0), otvori dashboard i prebroji šifre — moraju biti iste one iz maila. 5. Šutnja: provjeri kako je sesija dokazala 4 h 30 min. Ako je pomicala sat na stroju, provjeri da ga je vratila (date). Ako je dokaz samo test, a ne živi stroj, to je NEDOKAZANO, ne pad — ali mora biti napisano. 6. curl na datoteku baze kroz domenu, po nekoliko putanja. Pa provjeri listanje mapa i da nginx ne služi ništa izvan public/. 7. Certifikat: izdavatelj, datum isteka, TLS verzija. Provjeri i da HTTP preusmjerava na HTTPS. 8. date i crontab -l na stroju: Europe/Zagreb i posao u 03:00. 9. Potvrdi da produkcijski master i childovi NISU dirani: nigdje u izvedenim naredbama nema -e target_hosts=production_master osim ako je vlasnik izričito tražio, i nema deploya na child. 10. ./flora check: 4.443, exit 0. git log bez atribucije, ništa pushano. ## Izvještaj ŠTO STOJI / GDJE JE KRIVO ILI NEDOKAZANO, s izlazom naredbe. Posebno odvoji što je dokazano na ŽIVOM stroju od onoga što je dokazano samo testom. Na kraju presuda u jednoj rečenici: prihvatiti / prihvatiti uz popravke (koje) / vratiti.
šest gotovih promptova za kasnije
Ovo nije korak izgradnje. To je šest gotovih promptova za kasnije — kad nexus već radi, a ti želiš nešto u njemu promijeniti. Svaki je samostalan (sesija ne treba znati ništa o E1–E8 osim onoga što u promptu piše) i svaki kaže što ne smije puknuti: testovi, retencija, potpis.
# Promjena nexusa: novi izvor izvještaja Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base, u sync-nexus/. Nexus je gotov i radi. Ovo je IZMJENA, ne izgradnja. Želim dodati novi izvor: __________ (ime izvora, npr. woocommerce-de). ## Što napraviti 1. Dodaj izvor na popis očekivanih izvora u postavkama, s VLASTITOM tajnom. Tajnu unosi vlasnik — ti je ne izmišljaš, ne commitaš i ne stavljaš u test. 2. Reci koje parove usporedbe novi izvor otvara i PITAJ vlasnika koje od njih uključiti. Ne dodaj par sam. 3. Za svaki novi par postavi prekidač za nalaz "šifra samo na jednoj strani" — zadano ISKLJUČENO dok se ne izmjeri koliko ih ima. Razlog: između Vendurea i mastera ih je 554 i to bi slalo poštu svaka četiri sata. 4. Dashboard: nova pločica i novi stupac u tablici neslaganja. ## Što NE smije puknuti - Broj testova ne smije pasti; novi izvor donosi nove testove (barem: potpis svojom tajnom, tuđom tajnom pada, usporedba u novom paru). - Potpis i idempotencija (source, generatedAt) ostaju netaknuti. - Retencija ostaje ista: 7 dana puna stanja, 30 dana ostalo, 90 dana alerts. - Usporedba se i dalje pokreće SAMO kad su SVI očekivani izvori javili u zadnja 4 sata — pazi da novi izvor koji još ne šalje ne ušutka cijeli nadzor. Ako to prijeti, javi PRIJE nego dodaš izvor na popis. ## Pravila Commit na hrvatskom bez atribucije, ne pushaj, git add po imenu. Tajne unosi vlasnik. Prije i poslije: točan broj testova i exit kod.
# Promjena nexusa: pravila usporedbe Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base, u sync-nexus/. Nexus je gotov i radi. Ovo je IZMJENA. Želim promijeniti: __________ (npr. "utišaj nalaz o statusu na paru master↔SI child", ili "uključi 'šifra samo na jednoj strani' za par s Vendureom"). ## Što napraviti 1. Promjena ide u POSTAVKE, ne u kod. Ako za ono što tražim nema prekidača, napravi prekidač — po paru i po vrsti nalaza — i objasni zadanu vrijednost. 2. Prije nego išta promijeniš, IZMJERI: koliko nalaza te vrste na tom paru postoji danas. Reci brojku. Utišavanje bez brojke je gađanje u mraku. 3. Napiši u README što je utišano, na kojem paru i zašto — utišan nalaz koji nitko ne pamti je rupa u nadzoru. ## Što NE smije puknuti - Šifra se i dalje uspoređuje DOSLOVNO. Bez trim(), bez strtolower(). Razlika u praznini je nalaz, ne stvar koju treba zagladiti. - Usporedba se i dalje NE pokreće dok svi očekivani izvori nisu javili u zadnja 4 sata. - Utišavanje gasi POŠTU, ne zapis. Nalaz i dalje ulazi u comparison_items i vidi se na dashboardu. - Broj testova ne pada; svaka promijenjena zadana vrijednost dobiva test. ## Pravila Commit na hrvatskom bez atribucije, ne pushaj, git add po imenu. Točan broj testova prije i poslije, exit kod.
# Promjena nexusa: retencija Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base, u sync-nexus/. Nexus je gotov i radi. Ovo je IZMJENA. Želim promijeniti: __________ (npr. "puna stanja 14 dana umjesto 7", ili "pokreti 90 dana"). ## Što napraviti 1. Prije promjene izmjeri: broj redaka po tablici i veličinu datoteke baze u bajtovima. Procijeni novu veličinu i reci brojku. Polazna računica: 4 izvora × ~1.500 šifri × 6 izvještaja dnevno ≈ 36.000 redaka na dan; uz 7 dana punih stanja ravnoteža je ≈ 250.000 redaka. 2. Promijeni granicu na JEDNOM mjestu (postavke ili konstante uz shemu), ne na pet mjesta u upitima. 3. Ako produžuješ rok, provjeri da postojeći sažeci ostaju točni i da se sažimanje ne izvodi dvaput nad istim danom. ## Što NE smije puknuti - REDOSLIJED posla ostaje: sažmi → obriši puna stanja → obriši preko granice → VACUUM. Brisanje se NE izvodi ako je sažimanje palo. - Sažimanje ostaje idempotentno: drugi prolaz istog dana daje 0 novih redaka. - Suhi način (--dry-run) i dalje ne mijenja nijedan redak. - Broj testova ne pada; nova granica dobiva test i na granici i jednu sekundu preko nje. ## Pravila Commit na hrvatskom bez atribucije, ne pushaj, git add po imenu. Brojke prije/poslije: redaka po tablici i bajtova datoteke.
# Promjena nexusa: pošta Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base, u sync-nexus/. Nexus je gotov i radi. Ovo je IZMJENA. Želim promijeniti: __________ (npr. "dodaj drugog primatelja", "tihi prozor na 12 sati", "u tijelu 100 šifri umjesto 50", "drugi naslov"). ## Što napraviti 1. Primatelji, pošiljatelj i ključ ostaju u VARIJABLAMA OKOLINE. Nikad u kodu, nikad u testu, nikad u commitu. Vlasnik ih unosi. 2. Prag (koliko šifri ide u tijelo) i tihi prozor su postavke s brojkom, ne tvrdo upisane vrijednosti. 3. Tekst mailova ostaje na hrvatskom. ## Što NE smije puknuti - Prigušenje po OTISKU skupa: isti skup šifri i isti par unutar tihog prozora ne šalje drugi mail; skup s jednom novom šifrom šalje. Otisak se računa nad parom i POREDANIM skupom šifri — ne nad brojem i ne nad redoslijedom dolaska. - Mail o ŠUTNJI izvora ima vlastito prigušenje, odvojeno od mailova o neslaganju. Jedno ne smije ušutkati drugo. - Put ostaje SMTP2GO API, a NE Vendureov transport. Nadzor mora moći vikati i kad je pokvareno ono što nadzire. - Nijedan test ne zove mrežu. Pokreni testove bez mreže i dokaži. - Broj testova ne pada. ## Pravila Commit na hrvatskom bez atribucije, ne pushaj, git add po imenu. Grep po diffu: nijedna prava adresa i nijedan pravi ključ.
# Promjena nexusa: dashboard Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base, u sync-nexus/. Nexus je gotov i radi. Ovo je IZMJENA. Želim: __________ (npr. "stupac s vremenom zadnje promjene šifre", "ekran s narudžbama koje traže više nego što zaliha ima", "filtar po izvoru"). ## Što napraviti 1. Prvo provjeri ima li podatak već u shemi. Ako ga nema, JAVI I STANI — nova tablica ili novi stupac su promjena ugovora s izvorima, ne kozmetika. 2. Tehnika ostaje dosadna: PHP, PDO, inline SVG za grafove, bez composera i bez JS okvira. Sučelje na hrvatskom. 3. Sve brojke dolaze iz baze. Nijedan primjer i nijedan tvrdo upisan broj u views/. ## Što NE smije puknuti - DVIJE ODVOJENE BRAVE: lozinka u kolačiću za ljude, Basic token za API. Token ne otvara ekrane, kolačić ne otvara API. Provjeri sve četiri kombinacije. - Nexus NIŠTA NE ISPRAVLJA. Nema gumba koji piše u master ili u Vendure. - Datoteka baze i dalje nije dohvatljiva kroz web server. - Broj testova ne pada. ## Pravila Commit na hrvatskom bez atribucije, ne pushaj, git add po imenu. Svoj PHP server na 8090 i ugašen prije kraja (lsof -i :8090 prazan); vlasnikovi portovi 3000, 4331, 4332, 5175 i 5432 se ne diraju. Priloži snimku ekrana i SQL kojim si brojke provjerio.
# Promjena nexusa: opći obrazac Radiš u /Users/bruno_afk/Dev/rasadnik/flora-base, u sync-nexus/. Nexus (nadzor zaliha, potprojekt 2) je gotov i radi. Ovo je IZMJENA, ne izgradnja. Spec je flora-atlas/specs/specs/2026-09-11-nadzor-zaliha-nexus-design.md. ## Želim ovo promijeniti __________________________________________________________________ (napiši svojim riječima; ako ne znaš kako se to zove u kodu, opiši što vidiš i što bi htio vidjeti umjesto toga) ## Kako želim da to napraviš 1. Prvo mi reci što si RAZUMIO da tražim, i koje datoteke to dira. Ako je dvosmisleno, pitaj prije nego dirneš išta. 2. Izmjeri zatečeno stanje brojkom prije promjene (broj testova, broj redaka, što god je mjerljivo u ovom slučaju). 3. Napravi promjenu, s testom koji bi PAO prije nje. 4. Reci mi brojke prije i poslije. ## Što NE smije puknuti, nikad - Potpis (HMAC-SHA256, tolerancija ±300 s, tajna PO IZVORU) i idempotencija para (source, generatedAt). - Retencija: 7 dana puna stanja, 30 dana ostalo, 90 dana alerts; redoslijed sažmi → obriši → VACUUM. - Prigušenje pošte po otisku skupa i odvojeno prigušenje za šutnju izvora. - Doslovna usporedba šifri, bez normalizacije. - Nexus NIŠTA NE ISPRAVLJA — ne piše ni u master ni u Vendure. - Broj testova ne pada, i svi prolaze (exit 0). ## STANI Ako ono što tražim ruši bilo što s gornjeg popisa, NEMOJ to napraviti tiho. Reci mi što se ruši, predloži dvije opcije s cijenom, i stani. ## Pravila Commit na hrvatskom bez atribucije, ne pushaj, git add po imenu datoteke. Tajne unosim ja — ne izmišljaj ih i ne commitaj ih. Vlasnikovi portovi 3000, 4331, 4332, 5175 i 5432 se ne diraju; svoj server digni na 8090 i ugasi ga.