SnowIT IT consulting company — Sarajevo operations, contracts, clients. Overview SnowIT Overview IT consulting company — Sarajevo operations, contracts, clients. Owner: John Last Verified: 2026-02-17 Contents To be populated from SnowIT company documentation Active Tasks Last Verified: 2026-02-17 | Owner: John SnowIT — Active Tasks Open Tasks Medium Priority #1213 — Follow up: Has Asmir posted content on LinkedIn? #1267 — DNS and email setup for snowit.ba (MX records) Recently Completed Website services page — /usluge page live with full service catalog OG image fix — Text rendering problem resolved LinkedIn company page — Created and ready for content Sales playbook — Detailed sales strategy by AI agent (nicksaraev) Content calendar — 30-day content plan by AI agent (marketer) Financial model — 6-month projections by AI agent (finance) Market research — B&H market analysis completed Planned Work Outreach campaign — 5 clients in 30 days (delivery delayed) Email setup — Complete DNS configuration Content execution — Post first batch from content calendar Lead generation — Start executing sales playbook Key Decisions Last Verified: 2026-02-17 | Owner: John SnowIT — Key Decisions Strategic Decisions Market Focus: Bosnia & Herzegovina (2026-02) Decision: SnowIT targets B&H market exclusively (snowit.ba domain). Rationale: Local market knowledge, language advantage, untapped AI services market. Implementation: Website in Bosnian/Serbian/Croatian, local pricing, B&H payment methods. Service Packaging (2026-02) Decision: Offer 3-tier packages (Digital Presence 800 KM, 2-4h response) Rationale: Predictable pricing, easier sales, scalable delivery. Source: Financial model from AI agent (finance). Content Marketing Strategy (2026-02) Decision: 3 posts per week on LinkedIn (12-13 posts/month) Rationale: Consistent presence, thought leadership, organic reach. Source: Content calendar from AI agent (marketer). Partnership Model (2026-02) Decision: Collaborate with Asmir as partner/sales contact. Status: Active, awaiting LinkedIn activity confirmation. Technical Decisions Website Stack Modern web framework (details in repo) Hosted on vercel/railway/fly.io (pending deploy strategy task #271) snowit.ba domain with email (@snowit.ba addresses) Sales Process Sales playbook created by AI agent (nicksaraev) CRM integration planned Lead tracking via Mission Control Operational Decisions Pricing Strategy Digital Presence package: 800 KM (2-4h response time) Additional tiers defined in financial model Competitive with local market, premium positioning Project Overview Last Verified: 2026-02-17 | Owner: John SnowIT — Project Overview What is SnowIT? SnowIT (snowit.ba) is an AI-driven agency focused on the Bosnia & Herzegovina market. It provides software development, design, security, data, infrastructure, and marketing services under one roof. Current Status Phase: Active development Website: snowit.ba (live) Market: Bosnia & Herzegovina (B&H) Business Model: Full-service digital agency Recent Work Website launch with services pages (/usluge) LinkedIn company page creation OG image optimization (text rendering fix) Sales playbook development 30-day content calendar for LinkedIn Financial model for first 6 months Market research for B&H market Services Offered Software Development — Web, mobile, custom applications Design — UI/UX, branding, visual design Security — Infrastructure security, compliance Data — Analytics, business intelligence Infrastructure — Cloud hosting, deployment Marketing — Digital marketing, content, campaigns Tech Stack Website: Modern web stack (details in project repo) Hosting: TBD (see Deploy & Hosting Strategy task #271) Email: snowit.ba domain (DNS/MX setup in progress) Contacts Partner: Asmir (asmirmc@gmail.com) Status: Active collaboration, LinkedIn outreach campaign planned Key Documents Sales Playbook — Agent-generated detailed sales strategy Content Calendar — 30-day LinkedIn posting schedule (3 posts/week) Financial Model — 6-month revenue projections Service Catalog — Full service offerings at snowit.ba/usluge Specifications Index Last Verified: 2026-02-17 | Owner: John SnowIT — Specifications Index Business Documents Sales & Marketing Sales Playbook — Detailed sales strategy (AI-generated by nicksaraev agent) Content Calendar — 30-day LinkedIn content plan (AI-generated by marketer agent) Financial Model — 6-month revenue/cost projections (AI-generated by finance agent) Market Research — B&H market analysis Service Catalog Located at snowit.ba/usluge: Software Development Design Services Security Consulting Data Analytics Infrastructure Management Digital Marketing Technical Documents Website Stack: Modern web framework Hosting: TBD (Deploy & Hosting Strategy task #271) Domain: snowit.ba Email: MX records setup (task #1267) Infrastructure DNS configuration (in progress) Email setup (in progress) Deployment pipeline (pending) Planning Documents 30-Day Outreach Plan — 5 clients target (delivery delayed) LinkedIn Strategy — Content themes, posting schedule Pricing Strategy — Package definitions, competitive analysis SnowIT Tenant Tree (2026-05-15 migration) SnowIT Tenant Tree (2026-05-15 migration) Legal Boundary SnowIT BA is an independent legal entity. ALAI Holding AS provides technology and operations support under service agreement. ALAI has ZERO financial share/equity in SnowIT BA. CEO directive 2026-05-15: "SnowIT BA = independent legal entity. ALAI = tech-only ZERO financial share." New Canonical Layout As of 2026-05-15, SnowIT BA operates under dedicated tenant tree: ~/tenants/SnowIT-BA/ ├── company/ # Corporate operations │ ├── state/ # System state, sessions (was ~/clients-external/snowit-state) │ ├── finances/ │ ├── contracts/ │ └── reports/ ├── legal/ # Legal documents, compliance ├── contacts/ # CRM, stakeholder data ├── calendar/ # Events, deadlines ├── mail/ # Email archives, campaigns ├── forms/ # Templates, intake forms ├── templates/ # Document templates ├── web/ # Web properties │ └── snowit-site/ # Main repo (was ~/clients-external/snowit-site) └── clients/ # SnowIT client projects Migration Summary What Moved ~/clients-external/snowit-site → ~/tenants/SnowIT-BA/web/snowit-site ~/clients-external/snowit-state → ~/tenants/SnowIT-BA/company/state Client reference symlink: ~/business/ALAI-Holding-AS/clients/SnowIT → ~/tenants/SnowIT-BA/_external-tenant-snowit-reference What Stayed in ALAI Tree ~/business/ALAI-Holding-AS/products/SnowIT/linkedin-cadence/ — ALAI internal tool (CEO directive: stays in ALAI tree) Hard Cutover Confirmed Both old directories removed: ~/clients-external/snowit-site → No such file or directory ~/clients-external/snowit-state → No such file or directory Validation Evidence Status: PASS (9/9 criteria) ID Criterion Status Evidence V1 snowit.ba serves HTTP/2 200 ✓ PASS /tmp/proveo-100723/curl-snowit.txt V2 enterprise.snowit.ba serves HTTP/2 200 ✓ PASS /tmp/proveo-100723/curl-enterprise.txt V3 Playwright screenshot rendered ✓ PASS /tmp/proveo-100723/snowit-landing.png (124KB) V4 Vercel projectId intact ✓ PASS /tmp/proveo-100723/vercel-project.json V5 LaunchAgents operational ✓ PASS 3 daemons loaded, path-independent V6 Git remote correct ✓ PASS git@github.com:snowitba/snowit-site.git V7 Repo-local [user] config removed ✓ PASS Global ~/.gitconfig inherits correctly V8 No live functional refs to old path ✓ PASS 20 mentions are historical/spec/memory only V9 Hard cutover confirmed ✓ PASS Both old directories removed Open Items Non-Blocking DEPLOY-MAP.md schema upgrade — Line 32 has stale path ~/projects/snowit-site . Kelsey-hightower blocked by blueprint-schema-validator pre-hook. Requires DEPLOY-BLUEPRINT v2 compliance upgrade. Separate MC opened for schema migration. References MC: #100723 ADR: ADR-026 SnowIT Tenant Tree Spec: ~/system/specs/snowit-tenant-migration-2026-05-15.md Executor: kelsey-hightower (FlowForge) Validator: angie-jones (Proveo) Supersedes: anvil-fs-d2 (Phase D restructure now complete for SnowIT) Canonical Registry: ~/system/specs/canonical-registry.md SEO Readiness Portal Cloud Migration — 2026-06-01 SEO Readiness Portal Cloud Migration — 2026-06-01 Date: 2026-06-01 Owner: john Verdict: DONE Live state verified (2026-06-01 05:31 UTC) curl -sI https://seo-tools.alai.no/api/health → HTTP 302 to alai-no.cloudflareaccess.com/cdn-cgi/access/login/... (CF Access enforced, no anonymous access) curl -sI https://seo-readiness-alai.azurewebsites.net/api/health → HTTP 403 x-ms-forbidden-ip: 46.46.245.169 (Azure origin lock to Cloudflare IPs) No traffic to John local host: cloudflared route for seo-tools.alai.no and seo-tools.snowit.ba set to http_status:503 . Architecture (now) Browser → Cloudflare Access ( seo-tools.alai.no , alai-no team) → Cloudflare proxied DNS → Azure App Service Linux container seo-readiness-alai (Sweden Central, rg rg-seo-readiness-prod , asp asp-seo-readiness-prod B1) → Next.js standalone in alairegistry.azurecr.io/seo-readiness-portal:20260531-cloud (digest sha256:16c8a40a... ) → persistent /home/data/workspace.json App access mode: SEO_PORTAL_ACCESS_MODE=cf-access , trusted header CF-Access-Authenticated-User-Email , allowed domains snowit.ba,alai.no , extra allowed alembasic@gmail.com . Evidence Deploy summary: /tmp/alai/seo-readiness-cloud-migration-20260531/cloud-deploy-summary.md Local-disabled proof: /tmp/alai/seo-readiness-cloud-migration-20260531/local-disabled-evidence.txt Azure build + deploy: azure-build.log , azure-webapp-deploy.log , azure-hostname-corrected.log , azure-role-settings.log Origin lock: azure-access-restrict-cloudflare.log , azure-access-restrict-smoke.log DNS upsert: cf-dns-upsert.log Public smoke: public-cloud-smoke.log Origin smoke: azure-smoke.log Authenticated UAT (alem@alai.no, end-to-end: partners → add client → intake → audit → report → markdown export): uat-alem/seo-cloud-uat-result.json + 8 PNG screenshots uat-alem/01-cf-login.png … 08-export.png Lesson memo: lesson-seo-cloud-origin-lock-20260531.md Docs corrected (no localhost as final target) DEPLOYMENT-CLOUD.md L7 — explicit "must not be served from John/local localhost" DEPLOYMENT-INTERNAL.md L7, L26, L102 — Docker steps marked local-dev only; cloud origin required for production; explicit "Do not route seo-tools.* to http://127.0.0.1:* or any localhost address" README.md L130 — "Azure App Service Linux container origin, not John/local localhost" BUILD-BLUEPRINT.md L54, L70 — Azure runbook section + CEO correction recorded Rollback If Azure origin needs rollback: Revert Web App container image: az webapp config container set -g rg-seo-readiness-prod -n seo-readiness-alai --container-image-name alairegistry.azurecr.io/seo-readiness-portal: CF Access policy and DNS remain unchanged; no public bypass introduced. Do NOT re-enable cloudflared local route — that violates the CEO correction. Open follow-ups (separate MCs, not blockers) Postgres swap for /home/data/workspace.json (durable multi-user storage) — pre-req for external product use. seo-tools.snowit.ba DNS/zone provisioning (currently 503). Bind Azure custom hostname TLS managed cert (currently CF terminates). CEO scope check "Move off John/local host to real cloud" → DONE (Azure App Service) "Cloudflare Access trusted-header preserved" → DONE ( SEO_PORTAL_ACCESS_MODE=cf-access ) "No public unauthenticated access" → DONE (302 to CF Access login on unauth) "Custom domain toward seo-tools.alai.no" → DONE (CNAME + asuid TXT + Azure binding) "Concrete deploy URL/origin" → DONE ( seo-readiness-alai.azurewebsites.net behind seo-tools.alai.no ) "UAT evidence" → DONE (alem-authenticated screen-recorded flow) "Rollback" → documented above "Fix docs that recommend local host" → DONE (4 docs updated) MC / evidence references MC task: #102653 Local closure artifact: /tmp/alai/seo-readiness-cloud-migration-20260531/CLOSURE-102653.md Cloud deploy summary: /tmp/alai/seo-readiness-cloud-migration-20260531/cloud-deploy-summary.md Authenticated UAT result: /tmp/alai/seo-readiness-cloud-migration-20260531/uat-alem/seo-cloud-uat-result.json Origin restriction smoke: /tmp/alai/seo-readiness-cloud-migration-20260531/azure-access-restrict-smoke.log P2P verifier PASS: mesh-thr-50503688-7de8-489c-96ca-3d7d1a165dc2 See Also — Agent Runbook The canonical end-to-end workflow runbook (intake to John deep-report, anti-pitfalls, trigger checklist): SEO Pipeline — Portal Intake to John Deep-Report (agent runbook) QODY CI-CD pipeline fixes 2026-07-08 (MC 105057+105059) QODY CI/CD demo pipeline fixevi — 2026-07-08 (MC #105057 + #105059) Dokazano zelenim pipeline run #330 (commit 747c100, deployDemo=true). John live-verifikovao timeline + endpointe; Proveo nezavisna tool-verifikacija PASS. Kontekst Run #328 (buildx fail) i raniji Trivy fail (#327) blokirali QODY demo deploy. Oba uzroka su bili pre-postojeće pipeline rupe , ne aplikacijski/Monri kod. Fix #105059 — idempotent buildx (Build_Images) Simptom: run #328 Build_Images ERROR: existing instance for "qody-builder" but no append mode . Uzrok: azure-pipelines.yml demo stage (lin 881) radio goli docker buildx create --use --name qody-builder ; persistent self-hosted agent (qody-forge-1) zadrži builder instancu između runova → kolizija. Fix: backport idempotentnog patterna s prod stagea (MC #104911): docker buildx use qody-builder 2>/dev/null || docker buildx create --name qody-builder --use --driver docker-container (lin 886). Fix #105057 — Trivy verify-not-fetch (Security_Image_Scan) Simptom: Trivy install pao na qody-forge-1: mkdir /usr/local/bin: Permission denied . Uzrok: curl-based installer piše u /usr/local/bin, koji ne postoji na Apple Silicon self-hosted agentu i traži sudo (kojeg agent nema). Fix: verify-not-fetch — koristi već-instalirani Homebrew Trivy 0.72.0 ( export PATH="/opt/homebrew/bin:$PATH"; which trivy ), isti pattern kao druga dva Trivy stepa (MC #104917). FORGE agent nije diran. Dokaz (run #330) Stage Rezultat CI Gates succeeded Build_Images → ACR succeeded (buildx fix radi) Security: Trivy image scan (4 images) succeeded (Trivy fix radi) Deploy → QODY demo ACA succeeded Deploy_Prod skipped (ispravno — nije main) Timeline: 165 succeeded / 0 failed / 6 skipped (prod). Live (John curl): demo.api.qody.ba/health → 200 (db.connected, RLS PASS); demo.app.qody.ba → 200. Evidence: ~/system/evidence/105048/pipeline-330-timeline.json + verdict-105057.json + verdict-105059.json QODY Monri WebPay integracija — E2E dokaz (MC 105048) MC #105048 - Monri WebPay Integration - Final E2E Proof Result: SUCCESS - real sandbox payment completed end-to-end, guest-facing error page RESOLVED (no longer cosmetic) Orders proven paid (3 separate live sandbox transactions this session): e0692760-b2c1-4120-83b9-7480cee6ef00 - payment_status=paid, status=submitted, total=9.9450 BAM (see order-paid-db-proof.txt - first successful E2E run, before the 405 fix) 7419eee0-ef1d-4c64-b9f2-2724bec0d66c - payment_status=paid (verified via psql during 405-fix re-verification round 1) 6bf5ef27-9b8a-4a28-9c80-e84d5e8d48bc - payment_status=paid (verified via psql during 405-fix re-verification round 2, final confirmation the same-origin redirect fix works with no regression to the payment flow itself) Flow proven live (Playwright, e2e/monri-sandbox-checkout.test.js) Guest lands on demo.app.qody.ba (venue "kafana", Table 1) Adds item to cart (Brusketa, 8.50 BAM) Submits order (POST /guest/order - 200) Proceeds to checkout, selects "Plati odmah" (pay now) POST /guest/payment/intent - 200, provider=monri, real Key-Vault-sealed credentials (not placeholder) Monri Lightbox script (class="lightbox-button", ch_* customer fields) renders "Pay with card" button - screenshot 07 Clicks through to Monri's real hosted iframe (ipgtest.monri.com/v2/payment/.../form) screenshot 08 Fills real Monri sandbox test card (4058400000000005, exp 12/30, cvv 123) via keystroke simulation (pressSequentially, not fill - masked-input fix) screenshot 09 Submits - card validates, Monri approves, triggers redirect - screenshot 10 Monri's server-to-server Callback (webhook) arrives at /webhooks/payment/monri, resolves venue, verifies signature (valid SHA512(merchant_key+body) digest, WP3-callback scheme), marks payment succeeded - confirmed via qody-api logs (200 OK, 36ms) Order flips to payment_status=paid in Postgres - confirmed via psql (3x, see order IDs above) 405 Not Allowed after payment - RESOLVED (was previously mis-called "cosmetic") This was correctly flagged as a real launch-blocker, not cosmetic: a real guest who pays would have seen nginx's raw "405 Not Allowed" error page immediately after paying - even though the order was genuinely marked paid via the webhook, the guest had no way to know that. This is the same "deploy 200 hides dead flow" trap this session avoided elsewhere, applied to the guest-facing side. Root cause and fix, found through 3 live-verified iterations (code review alone could not have caught any of these - Monri's actual runtime behavior differs from what the docs literally show): Attempt 1 (insufficient): added preventDefault() in a 'submit' event listener on the payment form. Deployed clean, but Monri's lightbox.js calls form.submit() programmatically, which bypasses all 'submit' event listeners entirely (only .requestSubmit() fires them) - a genuine DOM API quirk, invisible from code review. Attempt 2 (partial fix, new bug): pointed the form's action at a real server-side route per Monri's documented pattern. This fixed the 405, but introduced a cross-origin CORS 403 (demo.app.qody.ba POSTing to demo.api.qody.ba) - Ktor's CORS plugin rejects the Origin header on a plain HTML form POST even when the origin is in the allowed list. Attempt 3 (working, verified live 2x): made the redirect target same-origin - added an nginx location = /payment/monri-return { return 303 /; } block on the guest app's own domain, and pointed the form's action at the relative path /payment/monri-return. Verified via curl -X POST https://demo.app.qody.ba/payment/monri-return -> 303, and via 2 full live Playwright E2E re-runs: card validated, payment succeeded, redirect worked (no 405, no 403, FINAL_URL: https://demo.app.qody.ba/), and both resulting orders (7419eee0, 6bf5ef27) confirmed paid in Postgres. Guest sees the normal venue menu after redirect, not an error page. The order is genuinely paid. Guest does not yet see an explicit "payment confirmed" screen on that same redirect (they'd need to re-check the order status manually, e.g. via the handover QR flow) - that gap is a separate, non-blocking UX improvement, tracked as MC #105069 (session-resume across the redirect so OrderStatusPage's existing confirmation UI shows automatically). A candidate fix for #105069 is already built and committed (commit 0a525e5, branch feat/qody-monri-checkout-105048) but is out of scope for #105048's launch-blocker bar per team-lead decision. Negative webhook test (webhook-negative-test.txt) POST /webhooks/payment/monri with Authorization: WP3-callback -> HTTP 400 {"error":"Invalid Monri webhook signature"} Bugs found and fixed during this live E2E session (none catchable by static review or isolated unit tests - required a real transaction against Monri's actual sandbox server): class="lightbox-button" missing on injected script tag (c94a640) ch_full_name/ch_address/ch_city/ch_zip/ch_country/ch_email/ch_phone customer fields required by lightbox.js validation (caf30df) Digest must use merchant "Key" (Kljuc), not authenticity_token - inverted from the isolated docs example (e38e9c0) "N/A" placeholder rejected as invalid ch_address/ch_phone (1132edd) ch_phone must be local format, no country-code prefix (74ae0ff) 405 Not Allowed post-payment - 3-round fix, see section above (3c296b8, d2e1d78, d38935e) Test-harness-only: Playwright .fill() bypasses Monri's input mask; switched to pressSequentially() (b1bda91, e2e test file) Infra issues found and fixed during this session (separate from Monri code) CI pipeline buildx builder not idempotent on demo stage (#105059, fixed) Trivy install failing on qody-forge-1 self-hosted agent (#105057, fixed by another parallel session) MFE Container Apps (qody-guest/admin/staff-kitchen) stuck on stale canary revisions since 2026-07-06, silently ignoring all new deploys (#105065, flagged separately) Zombie revision accumulation causing Postgres connection pool exhaustion (qody-api crashed once during this session; fixed by deactivating 9 stale revisions on qody-api, 6 on qody-guest, 4 on qody-staff-kitchen - flagged as a systemic deploy-runbook gap, separate ticket recommended) Merchant configuration change (Monri sandbox, Asmir's account) Set "Callback URL" on merchants/4988 (SnowIT) to https://demo.api.qody.ba/webhooks/payment/monri - was blank before, which is why no webhook could ever have arrived prior to this fix. This is the webhook delivery destination, required for any Monri integration to work at all, sandbox or production. Full detail, including confirmation that Asmir's password was NOT touched: see asmir-account-changes.md. Backend test suite 277/277 tests passing, 0 failures, 0 errors - re-verified fresh this turn via ./gradlew test (JDK 21, apps/api), BUILD SUCCESSFUL, all tasks UP-TO-DATE (no backend/Kotlin changes since the last full run - commit 0a525e5 only touches frontend TypeScript). Cross-checked against CI pipeline run 330, which independently ran "Backend: Gradle tests (Java 21)" -> succeeded and "Backend: integration tests (Testcontainers)" -> succeeded. Final commit and branch Branch: feat/qody-monri-checkout-105048 Latest commit: 0a525e5 (session-resume candidate fix for #105069 - not required for #105048's launch-blocker bar, but harmless and already built) Full commit list (oldest to newest): dfd71fc - feat(payments): wire Monri WebPay into guest checkout f31803d - fix(payments): correct Monri digest/signature per verified docs, venue-aware webhook, fail-closed (Proveo review round 1 fixes) 6b3b535 - docs(env): add MONRI_* stubs to .env.example 86f5508 - fix(ci): Security_Image_Scan Trivy install fails on qody-forge-1 (#105057) 747c100 - fix(ci): idempotent buildx create for demo build stage (#105059) c94a640 - fix(guest): Monri lightbox.js requires class="lightbox-button" on script tag caf30df - fix(payments): add Monri lightbox.js required ch_* customer fields e38e9c0 - fix(payments): Monri digest must use merchant key, not authenticity token 1132edd - fix(payments): Monri rejects placeholder ch_address/ch_phone as invalid 74ae0ff - fix(payments): Monri ch_phone must be local format, no country-code prefix b1bda91 - test(e2e): add Monri sandbox checkout Playwright test 3c296b8 - fix(guest): prevent 405 error page after successful Monri payment (attempt 1) d2e1d78 - fix(payments): Monri Lightbox form needs a real server-side action URL (attempt 2) d38935e - fix(guest): Monri return redirect must be same-origin, not cross-origin API (attempt 3, working) 0a525e5 - fix(qody-guest): resume order-in-progress across the Monri redirect (candidate for #105069, not required for #105048) QODY Admin UX Redesign — ZAVRSEN (MC 105067) QODY Admin + Super-Admin UX Redesign — ZAVRŠEN (MC #105067) Datum: 2026-07-08 | Vodio: Vizu (Brad Frost + Lea Verou), UX validacija Angie Jones (Proveo), sigurnost Parisa Tabriz (Securion) Živo: demo.admin.qody.ba (revizija qody-admin--uxfinal801b2d7, 100% traffic) | Branch feat/qody-admin-design-system-105067, commit 801b2d7 Root cause (zašto je bilo loše) Onboarding wizard i super-admin (#104856) vođeni kao "Petter Graff lead" — arhitekta, ne dizajner . Nijedan UI/UX dizajner nikad nije bio glavni; UI bio Phase-2 dodatak inženjerskog toka. Rezultat: nijedan design system — 19 admin views (11.660 linija) svaki hand-roll inline stilove; super-admin "kreiraj lokal" bio flat 7-poljni 480px modal bez wizard strukture ni a11y. Šta je urađeno (CEO odluka: čisto frontend, backend contract netaknut) Tier A — design system + super-admin wizard: Novi shared design system (apps/admin/src/ui/): Button, Modal (focus-trap + role=dialog + ESC), StatusPill (kanonski status→boja), Card, Table, Field, Switch Super-admin "kreiraj lokal" → guided 3-koračni wizard (Poslovanje→Vlasnik→Pregled) + success dialog Uklonjeni mrtvi no-op elementi (provisioningState kolona — bonus: pendingOnly filter bio BUG koji bi skrivao svaki merchant) Tier B — admin dashboard: VenuesView, MenusView (popravljeni pravi focus-trap/ESC na modalima), SettingsView + StaffView + ReportsView (bio 100% raw hex) + TablesView — svi na design system. Tier C — super-admin konzola: Transactions/Refunds/Subscriptions/Audit tabovi → q-data-table + Button komponenta, ~40 raw hex → tokeni. Verifikacija (sva 3 gejta + bugfix) Securion PASS ×2 : contract netaknut (api.ts backend diff prazan, 14 onClick handlera byte-identical, 0 dangerouslySetInnerHTML, 0 secret logova) Angie Jones UAT : Tier A PASS ("clears smiešan→top bar"). Tier B+C CONCERNS → našla 2 buga (StaffView reset-password id/staffId mismatch, VenuesView grid overlap) prije sign-off-a Bugfix (801b2d7) + Angie re-verify: B1 PASS (reset-password POST na pravi UUID → 200), B4 PASS (geometrijski overlap check 0 parova), #4 stale banner PASS Napomene Deploy: sve preko az acr build (lokalni Docker hung + git-author-guard #104976 blokira pushove) Preskočeno (opciono): raw "reports.advanced" label (pre-postojeći tech tag, ne regresija) Evidence: ~/system/evidence/105067/ (plan, securion-verify ×2, uat + uat-bc + uat-bc-reverify, screenshotovi) QODY Phase 1 Provisioning Gate + Integracioni Deploy (MC 105075+105077) QODY Phase 1 Provisioning Gate + Integracioni Deploy — ZAVRŠENO (MC #105075 + #105077) Datum: 2026-07-08 | Live demo: rg-qody-demo, revizije int105077 (api--int105077b, guest--int105077, admin--int105077), sve 100% traffic, sve 200. Šta je deployano (integrisano, jedan konzistentan build) Spojene 3 feature-grane u jedan qody-api/guest/admin build (merge branch feat/qody-105077-integration, commit 27a8250): Monri plaćanje (#105048) — per-venue, webhook, potpis SSE payment confirmation (#105069 BUG B) — gost vidi "plaćeno" potvrdu nginx :8080 fix (#105069 BUG A) — gost više ne vidi chrome-error nakon plaćanja Provisioning gate (#105075) — concierge model Admin redesign (#105067) + owner lock screen + super-admin wizard Migracije: V25 → V26_monri → V27_provisioning_gate (čist redoslijed). Concierge model (CEO odluka 2026-07-08) — LIVE Super-admin (SnowIT) postavlja SVE (org+venue+meni+stolovi+QR+plaćanje) preko 6 superadmin-scoped ruta Vlasnikov admin ZAKLJUČAN ("u pripremi") dok venue nije ACTIVE; server-side gate 403 na owner /admin/* Cash-only može ACTIVE bez Monri (Monri opcija, ne uslov) activate re-validira checklist server-side (meni+stolovi/QR+radno vrijeme+payment-decision) Proveo cross-role UAT + adversarial bypass — PASS 6/6 (raw HTTP, teži od browsera) Provisioning flow end-to-end: onboard→invite→menu→tables→hours→cash-only→activate ACTIVE ✓ Checklist enforcement: activate prije kompletiranja → 422 missing[] (server-side) ✓ Owner lock: 403 non-ACTIVE, 200 nakon aktivacije ✓ Adversarial bypass (kritično): owner JWT → /admin/ non-ACTIVE = 403; owner → /superadmin/ = 403 (ne može escalirati); impersonation PENDING = blokiran** ✓ Regresija: Monri webhook 400 (živ), guest menu, health/RLS PASS — NEregresirano ✓ Cash-only reaches ACTIVE bez Monri ✓ Incident tokom deploya (uhvaćen, vraćen) Prvi pokušaj: api build iz pogrešnog konteksta (repo-root umjesto apps/api) → deployao mrtav image → qody-api health 000 → rollback na 0000080 (Monri) u minuti → rebuild iz ispravnog apps/api konteksta → uspjeh. Ranije: gate-only api (iz main, bez Monri) regresirao Monri → rollback. Pouka: qody-api build-grana MORA imati sve žive feature; api build kontekst = apps/api. Follow-up (ne-blokirajuće) Concern 4c: impersonation PENDING vraća generic 404 (short-circuit prije guard poruke); security property drži (bez tokena), ali poruka ne stiže — developer 5min trace. Demo cleanup (#105068): UAT-105077-Venue (2f21abce), UAT-105077-Venue-B (31605010) suspended; + stray #105067 (Basic Cafe ...003, UAT-105067bc f7028415). #105077 merge NIJE pushan na azdo (guard #104976) — image-only deploy; kod na feat/qody-105077-integration lokalno. Evidence: ~/system/evidence/105077/uat/uat-report.md QODY Demo — MASTER Bug Registar (pun cross-role UAT 2026-07-08) QODY DEMO — MASTER BUG REGISTAR (kompletan cross-role UAT, 2026-07-08/09) 8 agenata (4 happy-path po ulozi + 4 kombinatorne matrice). 7/8 gotovo; kitchen KDS pending (blokiran reset-pw bugom — sam po sebi nalaz). Evidence po agentu u ~/system/evidence/uat-full/{owner,guest,superadmin,matrix-A-perms,matrix-B-state,matrix-C-payment,matrix-D-edge}/. 🔴 CRITICAL / BLOKERI (5) C1 — Cross-ORG data leak (#105076) [backend, sec] — POTVRĐEN LIVE iz 2 ugla (matrix-A + owner). GET /admin/venues + /admin/venues/{id} vraćaju SVE venue-ove SVIH organizacija bilo kojoj autentifikovanoj sesiji (bilo koja uloga, nema role/tenant check). Leak: fee, branding, slug cross-org. Root: AdminRoutes.kt:74-99 (fix pattern već na PUT 101-118). NAJVIŠI prioritet. C2 — Reset-password modal PRAZAN [frontend] — owner + kitchen UAT. POST /admin/staff/{id}/reset-password vraća 200 s temporaryPassword, ali UI modal display div prazan, "Kopiraj" kopira ništa. Owner nema način dobiti novi pw. (Ranija "PASS" verifikacija gledala network 200, ne UI prikaz — lekcija.) Blokirao i kitchen UAT. C3 — Monri plaćanje mrtvo [external/config] — guest UAT. Monri injected iframe.js pravi malformed URL "ipgtest.monri.com:/v2/" (kolon bez porta) → iframe se ne učita → guest ne može platiti, checkout dead-end. Naš kod (lightbox.js src) ispravan. Treba istražiti Monri merchant config/authenticity token (možda loš base URL u Monri postavkama). C4 — Add-to-cart prekriven AI-chat FAB-om [frontend] — guest UAT (mobile). "DODAJ" dugme fizički ispod "Pitajte nas" FAB-a → tap otvara chat umjesto dodavanja. Blokira naručivanje na telefonu. Fix: z-index/pozicija. C5 — SUSPEND je lažan [backend] — matrix-B. suspend samo set deleted_at, NE provisioning_state (koji gate provjerava). Suspendovan venue: owner postojeća sesija radi (200), GUEST NASTAVLJA naručivati (GuestRoutes bez provjere). SUSPENDED+PENDING_PAYMENT stanja dokumentovana ali nikad build-ana. 🟠 MAJOR (3) M1 — Suspend/activate bez potvrde [frontend/superadmin] — misklik mijenja live status merchanta, nema "jesi siguran", nema undo. M2 — Audit log ne bilježi activate/suspend [backend] — status se tiho flipne bez traga (kombinovano s M1 = opasno). M3 — Raw error poruke korisniku [frontend/backend] — (a) dupli slug → raw PSQLException 500 u UI (leak DB constraint, izgleda kao crash); (b) super-admin wrong-pw → raw JSON "401:{...}" u banneru; (c) merchant wrong-pw → netačno "session expired". Login banner postoji (Vizu fix) ali sadržaj sirov. 🟡 MEDIUM (5) MED1 — raw i18n/feature-flag keys leak u UI: MENU.MODIFIERS, BRAND.WHITELABEL ("brand.whitelabel: ukljuceno"), REPORTS.ADVANCED (shared component bug) MED2 — Monri pay dugme hardcoded EN (data-language="en"), ignoriše locale MED3 — nema dup-table-label check (2 stola isto ime, različit QR = floor confusion) MED4 — nema max-length org/venue name (500 char overflow u review + listi) MED5 — /guest/splitbill 403 + /guest/payment/intent 404 na svaki guest load (leftover Stripe-era + feature-flag) 🟢 LOW (7) merchant tabela overflow 6236px @1440 (Akcije off-screen) · nema edit menu-itema · AI describe 404×18 · Stripe Connect ne lokalizuje + stale "2%" fee · dashboard quick-actions ne prevode (HR/SR) · pretplate venue-ID identični truncated · search bez empty-state · invite venueSlug ne validiran vs token (ne bypass) ČISTO / RADI (verifikovano) Gate PENDING→ACTIVE airtight (12 ruta 403, cash-only ACTIVE radi); XSS escaped svuda; price/email/empty validacija; JWT verify + brute-force lockout; superadmin rute odbijaju owner (403); menu CRUD; QR gen/regen; operating hours; tips; CSV export; 4-jezik switch (osim navedenih); logout/session invalidation; modal focus-trap/ESC. HOUSEKEEPING ~15 leftover UAT test orgova + XSS-probe org u demo listi → cleanup (#105068). BATCH FIX PLAN (nakon konsolidacije → jedan merge → jedan deploy → re-UAT) CodeCraft backend: C1 (tenant-scope 2 GET), C5 (suspend→provisioning_state + GuestRoutes block + session revoke), M2 (audit activate/suspend), M3a (dup-slug friendly error), MED5 (guest 403/404), reset-pw response već radi (C2 je FE) Vizu frontend: C2 (reset-pw modal display), C4 (add-to-cart z-index), M1 (confirm dialog suspend/activate), M3b/c (friendly login/error poruke), MED1 (i18n keys), MED2 (Monri locale), MED3/4 (validacije) + VEĆ SPREMNO: invite-display (7609855), login-tabovi (2c71867) Istražiti: C3 (Monri malformed iframe URL — merchant config/authenticity token) Cleanup: #105068 (leftover test data)