Changelog — deploy historie
| Datum | Služba | Cíl | Verze/Commit | Status | Kdo |
|---|---|---|---|---|---|
| 2026-08-26 | pulse | hub (hub-new) + prod | 0d86499 (DEPLOY OK pulse hub Libor; INFO T-20260826-002, delta 9d32103→0d86499 = 4 commity, 22 souborů) — CR-225 (OG tagy pro náhledy na sítích) + 2 bugfixy z jednoho hlášení klientky (ukazatel průběhu tvrdil 8 % u hotového výstupu, a tlačítko PDF, které tam být nemělo, to potvrzovalo hláškou pro vývojáře). PRVNÍ ostrý deploy.sh na novém stroji CX33 — celý řetěz proběhl: rsync → build → health → ověření commitu → QA gate → stamp. QA gate RELEASE tier, 15/15 PASS. 🔑 Hlavní přínos nad rámec releasu: opraveno razítkování artefaktů. Po migraci měl hub všech 8 image přestavěných mým ručním docker compose up bez build argumentu, takže nesly GIT_COMMIT=dev/unknown nebo nic — labely tedy neměly čím být podložené a [[feedback_stale_guard_baked_commit]] neměl co číst. Tenhle deploy dokázal, že deploy.sh na hub-new stampuje správně: GIT_COMMIT=0d86499 = label = /api/version {"commit":"0d86499","buildTime":"2026-08-26T03:46:50Z"} — tři nezávislé zdroje se shodly. Zbylých 7 služeb zůstává bez razítka do svého příštího deploye. Migrace ověřeny měřením PŘED i PO: poslední REQ051InterestSignals1710000000170, celkem 167 → beze změny ⇒ nic se nespustilo. ⚠️ Pulsovo DEPLOY.md je hluboce zastaralé — deklaruje db_change: YES, 3 migrace 155/156/157 a migration_from: 0b81dac (prod LIVE), zatímco delta neobsahuje jediný migrační soubor, poslední migrace je 170 a na produkci běží 9d32103. Hlášeno už 2026-08-03, stále neopraveno ⇒ kontrola deklarace migrací u pulsu nehlídá nic a v horším případě by zastaralé „YES" zamaskovalo skutečnou migraci. CR-225 ověřeno chováním, ne buildem: OG blok kompletní (og:site_name, og:type, og:locale, og:title, og:description, og:url, og:image + rozměry 1200×630, twitter:card summary_large_image) a náhledový obrázek se na hubu reálně servíruje — https://pulse.s60hub.cz/app/og-default-v1.jpg → 200, image/jpeg, 137 753 B (= slíbených 134 kB). Bugfixy v nasazeném artefaktu: /app/dist/output/section-progress.util.js přítomen, sectionsCompleted v 9 souborech. 🔎 NÁLEZ k předání pulsu: OG tagy míří natvrdo na produkci — og:url = https://pulselab.cz/, og:image = https://pulselab.cz/app/og-default-v1.jpg, a social-meta.util.js nečte APP_URL ani jednou (0 výskytů), přestože kontejner má APP_URL=https://pulse.s60hub.cz správně. Vypadá to jako záměrná kanonická URL (míří tam og:url i og:image shodně), ne náhodný únik — na produkci to po nasazení bude fungovat správně. Dokud tam ale 0d86499 není, hubový og:image vrací SPA fallback text/html 1 943 B s kódem 200 místo obrázku, takže by sítě sáhly po vlastním výběru — přesně ta vada, kterou CR-225 řeší. Týž vzorec jako venom MODE=production z 08-02. PROD (DEPLOY OK pulse prod, 04:00 UTC) — prod gate prošel na čerstvém stampu (2026-08-26T03:52:54Z commit=0d86499 qa=pass tier=RELEASE), ne na stale; ověřeno předem ve zdrojáku, že gate čte ${PROJECT}-qa-pass (=pulse-qa-pass), zatímco starší s60-pulse-qa-pass z 25. 8. je jen varianta podle služby a nečte se — [[feedback_prod_gate_stamp_name_mismatch]]. Commit VERIFIED nejsilnější formou: .deploy-commit souhlasí, source hash local==remote, zapečený commit 0d86499 potvrzen v artefaktu a build hash se ZMĚNIL (41a064b7… → 875a14ee…) ⇒ doloženě reálná přestavba, ne recreate ze starého image ([[feedback_skip_build_fakes_verified]]). Labely 1/1. No migrations are pending; měřeno před i po: poslední migrace REQ051InterestSignals1710000000170, celkem 167 → beze změny ⇒ zastaralá deklarace 155/156/157 opravdu nic nespustila. Tři zdroje se shodly: GIT_COMMIT = label = /api/version {"commit":"0d86499","buildTime":"2026-08-26T03:59:49Z"}. ⭐ CR-225 se naplno projevil až tady: https://pulselab.cz/app/og-default-v1.jpg → 200, image/jpeg, 137 753 B, zatímco na hubu tatáž URL vracela SPA fallback text/html. Kanonická prod URL v OG tazích tedy dosedla podle záměru — proto bylo správné hlásit ji pulsu jako dotaz, ne jako vadu. /, /app/, /admin/ 200 (/health 200; /api/health vrací 404 správně — pulse má health na /health, na což doplatil i watchdog, viz oprava téhož dne). Kontejner healthy, 0 restartů, v logu žádná chyba. Nález k OG tagům + zastaralé DEPLOY.md předáno pulsu T-20260826-007 |
✅ | sentinel |
| 2026-08-25 | n8n | hub (nový stroj hub-new) | n8nio/n8n:2.11.2 (DEPLOY OK n8n hub Libor) — první deploy na CX33 100.102.29.119, součást migrace hub-alfa CPX31→CX33. Cíl: pin z :latest na 2.11.2 a čerstvý hubový deploy, aby prošel prod gate (blokuje, když je hubový starší než 2 h). Health /healthz 200, image i compose 2.11.2 (ne :latest), binding 127.0.0.1:5678 ⇒ bezpečnostní oprava z 08-12 přenos přežila a port se navenek neotevírá. Vlastnictví increment_workflow_version ověřeno v OBOU DB (s60_n8n_hub_user, s60_n8n_prod_user) — mina, která by shodila migraci novější n8n verze, je zneškodněná na hubu i produ. ⚠️ Krok 7.95 (ověření sentinel labelů) se TIŠE PŘESKOČIL — hub-new nemá /usr/local/bin/update-version-manifest.sh; díra po migraci, chybí celý subsystém sentinel-version (skript + /etc/default/sentinel-version + /etc/cron.d/sentinel-version + /var/www/_sentinel/). Nginx část se přenesla (snippet + include v 7 z 10 vhostů). Řeší deploy/sentinel-version/install-on-target.sh hub. Do té doby aggregator hub nevidí a label verifikace neběží — přesně ten vzorec tichého přeskočení, který vyrábí falešnou jistotu ([[feedback_skip_build_fakes_verified]]). ⚠️ QA gate SKIP — n8n nemá QA konfiguraci ve services.json (stav odjakživa, ne regrese). 🔎 Prázdná hubová DB NENÍ ztráta dat: s60_n8n_hub má workflow=0 credentials=0, ale obě instance míří na externí pg-alfu (100.125.3.121), kterou migrace serveru vůbec nepotkala; prod má workflow=10 / active=9 / credentials=5 ⇒ hubová instance byla prázdná už předtím. Ověřeno dotazem, ne předpokladem. PROD (DEPLOY OK n8n prod, 04:45 UTC) — pin z plovoucího :latest na 2.11.2; verze se nemění (prod už 2.11.2 běžel), mizí jen riziko, že kterýkoli recreate tiše stáhne novější n8n a narazí na migraci LimitWorkflowVersionTriggerToContent…003. Image se stáhl podle pinu (Pulling/Pulled), compose i běžící kontejner 2.11.2, binding 127.0.0.1:5678, health 200 lokálně i veřejně (https://n8n.studio60.cz/healthz). Krok 7.95 na produ PROBĚHL (Sentinel labels: OK 1/1) — na rozdíl od hub-new, kde chybí update-version-manifest.sh. Ověření chováním, ne výpisem: po recreate workflow=10 / active=9 / credentials=5 — beze změny ⇒ N8N_ENCRYPTION_KEY je netknutý a všech 9 aktivních workflow se samo znovu aktivovalo (kdyby klíč neseděl, credentials by se nedešifrovaly a workflow by zůstala mrtvá). V logu žádná chyba dešifrování. ⚠️ Prod gate prošel na QA stampu z 2026-07-21 (qa=manual-override reason=n8n-no-QA-config) — u n8n je override trvalý stav (žádná QA konfigurace ve services.json neexistuje), ale znamená to, že u téhle služby gate reálně nic neověřuje; deep health byl čerstvý. Viz [[feedback_prod_gate_stamp_name_mismatch]] — čti datum stampu. 📝 Dvě hlášky v logu nejsou z tohoto deploye (prod běžel 2.11.2 i předtím): chybějící Python 3 pro task runner v internal módu a vypnutá n8n telemetrie kvůli stáří releasu — předáno n8n agentovi |
✅ | sentinel |
| 2026-08-04 | badwolf | prod (DATA, ne deploy) | online_courses +1 řádek — nový online produkt „Velryby a delfíni – kompletní meditace + hudba" (Moodle course 41, medhud_velryby_a_delfini). Podklad badwolf INFO T-20260804-002, spuštěno na výslovné „ano, pusť to" od Libora. Není migrace ani deploy — datová tabulka, schéma beze změny; online_courses navíc není v sync doméně (ani ALLOW_LISTS, ani reconcile), takže Jenkins applier řádek nepřepíše. Předpoklady ověřeny mnou předem, ne převzaty: řádek s tím kódem ani UUID neexistoval (0), firma ISE = 11f3a9a4-… (Inner Sense s.r.o.) na produkci je (badwolf ji schválně dohledává poddotazem podle kódu, ne natvrdo UUID — při chybějící firmě se vloží 0 řádků místo záznamu s cizí firmou), počet kurzů 34 dle jejich hlášení, sourozenec kmedin_velryby_a_delfini = 4cd2be09-… potvrzuje tvrzení o sdílených UUID napříč prostředími, a žádný NOT NULL sloupec bez defaultu nechybí v INSERTu. ⚠️ Zjištěno navíc: jediné unikátní omezení tabulky je PK na id — na code žádné není, takže idempotence stojí výhradně na pevném UUID; při přepisu SQL s jiným UUID by vznikl duplicitní kód a DB by to nezastavila. UUID c0fe2384-9832-4011-b7d4-847e8293f252 je pevné schválně — Learnia ho už má v postmeta _bw_product_id (T-20260803-012), nové by rozbilo nákup. Spuštěno v transakci s dvojí pojistkou (GET DIAGNOSTICS = přesně 1 vložený řádek a výsledný počet = 35, jinak RAISE EXCEPTION → rollback). Výsledek: 1 řádek, 34 → 35, moodle_id 41, content_type course, company_id Inner Sense. Ověřeno i zvenku veřejným GET https://api.studio60.cz/api/online-courses → 35 položek, nový kurz přítomen s id c0fe2384-… a moodleId 41. Odblokovává prodej na Learnii (cms-learnia měla stopku právě kvůli tomuhle) |
✅ | sentinel |
| 2026-08-03 | pulse | hub + prod | 5141fc0 (hotfix, DEPLOY OK pulse hub + prod Libor; INFO T-20260803-019, delta 2d5543c→5141fc0 = 1 commit, 2 soubory, žádná migrace) — PRODUKČNÍ INCIDENT ZPŮSOBENÝ MNOU. Libor chtěl schválit video recenzi a připsat kredity; /api/admin/reviews/<id>/video vracel [CR-222] Klíč nepatří tomuto tenantovi (13:08 a 13:09 UTC). Řetěz příčin: (1) do REVIEW_MEDIA_S3_PREFIX jsem ráno napsal prod/ — koncové lomítko jsem přidal já, pulse v zadání psal „hub / prod" a kód si lomítko dává sám (review-media-store.ts:105: `${this.prefix}/${tenantId}/…`); (2) klientovo video se v 06:18 uložilo pod klíč prod//<tenant>/<uuid>.mov; (3) v 07:54 jsem prefix opravil na prod — a tím se ten klíč stal nečitelným, protože po odříznutí prefixu vyjde tenant segment prázdný. Moje zásadní chyba nebyla to lomítko, ale neúplné ověření: Liborovi jsem tvrdil „nová recenze zůstane funkční, prod//… pořád začíná na prod/, takže guardem projde" — ověřil jsem jen startsWith a nepodíval se o pár řádků níž na tenantOfKey. Kosmetická nesrovnalost se tím stala nedostupným klientským videem. Video přitom celou dobu leželo v bucketu nepoškozené (507 746 B). Hotfix pulsu: prefix se normalizuje při načtení (replace(/^\/+|\/+$/g,'')), klíč se uhlazuje jen pro porovnání (replace(/\/{2,}/g,'/')) a do úložiště jde vždy původní název ⇒ objekty se nemusí přejmenovávat, žádná oprava dat. Pulse si bere vinu („CR-222 hlídal, ŽE konfigurace existuje, ne JAK vypadá — chybějící půlka fail-fastu"), což je pravda o jejich straně, ale spouštěč byl můj. Ověření chováním, ne řetězcem v souboru: spuštěn nasazený kód v běžícím kontejneru (docker exec … node) — na hubu proti vzorům (prod//… OK, prod/… OK, cizí tenant odmítnut), na produkci proti SKUTEČNÉMU klíči Liborovy recenze: kontrola vlastnictví OK, stat() vrátil 507 746 B video/quicktime (tedy reálné čtení z bucketu, ne jen validace řetězce), podepsaná URL vygenerována, cizí tenant nadále odmítnut ⇒ normalizace nerozvolnila izolaci tenantů. Commit VERIFIED na obou (prod build hash ea2afbce…→e60154dd…), labely 1/1, QA gate hub PASS 15/15. Poslední článek doložil Libor: schválení recenze prošlo a kredity byly připsány (2026-08-03) — autentizovaná akce v adminu, kterou ze sentinelu ověřit nedokážu. Tím je řetěz kompletní: klient nahraje → objekt v S3 → admin přehraje → schválí → kredity. Incident uzavřen. 🧹 Úklid: Libor smazal svou první testovací recenzi z DB; smazal jsem osiřelý objekt prod/00000000-…/36b7d7e7-….mov, který vznikl mou nepovedenou ruční migrací (bucket ověřen výpisem — zůstal jen referencovaný prod//…4d1f1725… a pulsův dev/…). Sirotek na produkci SMAZÁN (WRITE OK ssh prod) — s pojistkou na md5 (c4dce242…; při neshodě by skript nic nemazal) a povinným bezpečnostním výpisem find před smazáním ([[feedback_remote_rm_safety_check]]); odklizen i prázdný tenantí adresář, ale /mnt/pulse-reviews ponechán a ověřen jako zapisovatelný z kontejneru (bind na něm stojí). Finální inventura: S3 = 2 objekty (Liborova recenze prod//…4d1f1725… + pulsův dev/…, oba referencované), disk prod = 0 souborů, disk hub = 0 souborů (můj sentinel-persistence-test.txt smazán tamtéž s pojistkou na md5 8718e019… a kontrolou obsahu; oba adresáře ponechány a ověřeny jako zapisovatelné). ⚠️ Na hubu ale zůstává v DB rozbitý řádek 31ded971… (mediaStorage='fs', videoPath ukazuje na soubor, který od 18. 7. neexistuje) — rozhodnutí pulsu, nesahám na to. 📌 Otevřené: lifecycle pravidlo na <env>/pending/ (mazat objekty starší 1 dne — jinak se hromadí nedokončené nahrávky) a upozornění pulsu, že kontejner běží Node v20.20.2, zatímco AWS SDK v3 bude od začátku 2027 vyžadovat Node ≥22 |
✅ | sentinel |
| 2026-08-03 | pulse | hub | 2d5543c (DEPLOY OK pulse hub Libor ×2 — první token spálil falešný CI FAIL, viz níž; INFO T-20260803-004, delta 9012e6c→2d5543c = 3 commity) — CR-222 F2 (média recenzí do S3), REQ-051 (sledování zájmu), oprava tichého selhání mailů. 6 nových env proměnných REVIEW_MEDIA_S3_* je PODMÍNKOU startu (fail-fast, záměr pulsu — kontejner, který nenaběhne, je incident na minuty; kontejner přijímající klientská videa do prázdna je incident, o kterém dva týdny nikdo neví). Nastaveno do /root/secrets/pulse/.env.{hub,prod} + PULSE_ENV, zálohy .bak-media-20260803-064747; prefix se liší per prostředí (hub/ vs prod/), jinak by si prostředí přepisovala data. ⚠️ Vědomě přijaté riziko (Libor 2026-08-03: „na ty projekty teď nemám čas, nasaď to, oddělíme později"): klíč je projektový a dosáhne i na s60backup — pulse ho ostatně už měl (CORS na bucketu nastavili sami, v bucketu byl jejich dev/ objekt) a žádná bucket policy neexistuje; dopad je omezen na 3. vrstvu záloh (Helsinky), vrstvy 1 (sentinel /var/backups) a 2 (Storage Box přes SSH) jsou jiným typem pověření a mimo dosah — viz [[project_s3_key_scope_risk]]. CI FAIL byl MŮJ, ne jejich: tsc hlásil Cannot find module '@aws-sdk/s3-request-presigner' + 67 spadlých suites, ale závislost v package.json byla — jen moje node_modules byly z 11. 5.; po npm install --legacy-peer-deps prošlo tsc čistě, 179/179 suites, 2106/2106 testů. Docker build by to nikdy neodhalil (dělá si vlastní npm ci uvnitř image). Systémový fix 5301bca: pre-build CI nově instaluje i když jsou node_modules jen zastaralé (package.json -nt node_modules), s retry přes --legacy-peer-deps — jinak by každý release s novou závislostí vyráběl falešný FAIL a sváděl k --skip-ci. Commit VERIFIED (build hash 1bfee018…→ea2afbce…, zapečený commit souhlasí), labely 1/1, QA gate PASS 15/15 (RELEASE). Ověření chováním: boot log [ReviewMediaService] [CR-222] Úložiště médií recenzí je dosažitelné: s60pulse/hub/ (HUB) ⇒ startup kontrola prošla proti reálnému bucketu se správným prefixem i prostředím; [glitchtip] HUB monitoring aktivní ⇒ oprava detekce prostředí zabrala (dřív se hub hlásil jako produkce, protože NODE_ENV je v kontejneru vždy production). Migrace v DB: REQ050CheckoutIntents…168, CR222MediaStorageBackend…169, REQ051InterestSignals…170 — všechny zapsané; checkout_intents i client_interest_signals mají RLS + FORCE RLS + politiku s NULLIF ⇒ oprava politiky z 168, kterou dělá 170 (CR-196), dosedla; client_reviews."mediaStorage" varchar default 's3'. 🔎 NÁLEZ — doložená ztráta dat z původní vady: hubovská recenze 31ded971… (VIDEO, approved, 18. 7.) má mediaStorage='fs' a videoPath, ale soubor na disku NEEXISTUJE — vznikl před bindem, uložil se do zapisovatelné vrstvy kontejneru a zmizel s recreate. Je to jen hub (testovací data), ale je to konkrétní důkaz mechanismu ztráty a zároveň to boří úklidové kritérium pulsu: bind lze odstranit, až WHERE mediaStorage='fs' vrátí prázdno — tenhle řádek to nikdy nesplní, protože soubor už není co přesunout. Rozhodnout: smazat řádek, nebo označit jako poškozený. PROD (DEPLOY OK pulse prod, 07:07): commit VERIFIED (build hash 1bfee018…→ea2afbce…, zapečený commit souhlasí, source hash local==remote), labely 1/1, /api/version → 2d5543c, /app/ + /admin/ 200. Boot log: [CR-222] Úložiště médií recenzí je dosažitelné: **s60pulse/prod/ (PROD)** + [glitchtip] PROD monitoring aktivní — canary 6079 ms + [freelo] PROD eskalace aktivní — tasky se zakládají v: PROD ⇒ všechny tři hlásné kanály živé a prostředí se hlásí správně. Migrace 168/169/170 zapsané, checkout_intents i client_interest_signals mají RLS + FORCE RLS + politiku s NULLIF. Migrace 169 rozdělila stávající recenze správně, ne naslepo: video s existujícím souborem → fs, textová recenze (bez média) → default s3. RUČNÍ MIGRACE MÉDIA (WRITE OK ssh prod + výslovné „pusť to" od Libora): originál /mnt/pulse-reviews/00000000-…/36b7d7e7-….mov (340 447 B, md5 c4dce242…) stažen na sentinel a nahrán na s3://s60pulse/prod/00000000-…/36b7d7e7-….mov — md5 shodné ve všech třech bodech (disk produkce → kopie → objekt), klíč sestaven jako PREFIX + videoPath shodně s aplikací (odpovídá i vzoru dev/…, který tam pulse měl). Teprve pak DB flip v transakci s pojistkou na počet řádků (GET DIAGNOSTICS + RAISE EXCEPTION při n<>1 ⇒ rollback), tenant kontext nastaven přes set_config: 126a9ddc… mediaStorage fs→s3, dotčen přesně 1 řádek, po flipu WHERE mediaStorage='fs' vrací 0 řádků ⇒ kritérium pulsu pro odstranění bindu je na produkci splněné. Originál na disku PONECHÁN a bind zůstává — rollback je SET mediaStorage='fs', soubor leží na místě. ⚠️ NEOVĚŘENO: že admin UI video z S3 reálně přehraje — recenze je submitted, tedy bez veřejného shareUrl, a bez autentizace se k tomu nedostanu; vyžádáno od pulsu ([[feedback_smoke_auth_blocker]]). 📝 Jejich DEPLOY.md navíc deklaruje zastaralé migrace (155/156/157, migration_from 0b81dac) místo skutečných 168/169/170 — neblokuje (kontrola hlídá jen přítomnost deklarace), nahlášeno |
✅ | sentinel |
| 2026-08-02 | pulse | hub | 9012e6c (DEPLOY OK pulse hub Libor ×2 — první token spálil můj chybný ./deploy.sh z resetnutého cwd, viz fix 8bdc5d4 níž; INFO T-20260802-051) — REQ-049 bind /mnt/pulse-reviews:/data/reviews (video recenze se dosud ukládaly do zapisovatelné vrstvy kontejneru: upload TIŠE USPĚL a obsah zmizel s dalším recreate) + nedobrovolně i CR-218 (566aaae) s migrací 167. ⚠️ Pulse se ve svém vlastním zadání spletl — psali „vezmi to jako cherry-pick 9012e6c, ne master HEAD", jenže rodičem 9012e6c JE 566aaae, takže --commit 9012e6c veze CR-218 s sebou; ověřeno git merge-base --is-ancestor. A jejich blokátor už neplatil: varovali, že CR-218 nesmí před CR-217 (a79a35c/kód ee637bf), ale ten je předkem nasazeného 628b280 a migrace CR217*159–166 jsou aplikované na hubu i produ (ověřeno v obou DB) ⇒ pořadí splněno. Migrace 167 přečtena celá před nasazením: aditivní outputs.methodologyVersionId + datový re-pin rozpracovaných konzultací, idempotentní (IS DISTINCT FROM), RLS obchází smyčkou přes tenants (prostý SET LOCAL by minul druhého tenanta 5pd-diagnostika), completed/abandoned záměrně netýká (pin = auditní záznam). Commit VERIFIED (build hash 639d841b…→1bfee018…, zapečený commit souhlasí), labely 1/1, QA gate PASS 15/15 (PATCH). Migrace v kroku 6.5 hlásí „No migrations are pending" — 167 proběhla už při startu kontejneru; ověřeno přímo v DB: řádek CR218PinMethodologyVersion1710000000167 v migrations, sloupec outputs."methodologyVersionId" uuid/nullable, a stav pinů active 59/59, paused 1/1 ⇒ všechny rozpracované konzultace mají pin (completed 165/182 a abandoned 46/46 beze změny, jak migrace slibuje). Bind ověřen chováním, ne configem: docker container inspect → bind /mnt/pulse-reviews → /data/reviews (rw=true), adresář si Docker na hubu založil sám (root:root 755; kontejner běží jako uid 0, takže zapisovatelný — [ -w /data/reviews ] ANO), zápis z kontejneru → soubor vidí hostitel (md5 8718e019…, /mnt/pulse-reviews/sentinel-persistence-test.txt) ⇒ data opravdu opouštějí kontejner. ✅ RECREATE-TEST PROŠEL (slíbená podmínka „hotovo" vůči pulsu; 3. DEPLOY OK pulse hub = re-deploy jako vynucený recreate, QA opět 15/15): container ID f06f3c136db → 45d8fb0f6a5 ⇒ kontejner byl skutečně přetvořen, ne restartován (restart by ID zachoval a nic by nedokazoval), a soubor přesto přežil beze změny — obsah čitelný z NOVÉHO kontejneru, md5 8718e019… na hostiteli identický před i po. Tím je REQ-049 doložený chováním: dřív by upload zmizel právě tady. 🧹 Testovací soubor /mnt/pulse-reviews/sentinel-persistence-test.txt na hubu ponechán (31 B, smazání by stálo další WRITE OK ssh hub). 📝 KB services/pulse/INDEX.md uvádí 3 „známé Dockerfile bugy s lokálními patchi" — v repu jsou už opravené (--legacy-peer-deps 4×, chybné COPY admin/dist/client/dist pryč) ⇒ poznámka je zastaralá, k opravě. PROD (DEPLOY OK pulse prod Libor, ~10:38): commit VERIFIED (build hash 639d841b…→1bfee018…, zapečený commit souhlasí, source hash local==remote), labely 1/1, health 200; /api/version → 9012e6c (buildTime 08:37:03Z = z tohoto běhu), /app/ i /admin/ 200; bind /mnt/pulse-reviews → /data/reviews (rw=true) aktivní a zapisovatelný. Migrace 167 na PRODUKČNÍCH datech — měřeno PŘED i PO (u datové migrace nestačí „OK"): před — CR218 v migrations 0×, sloupec outputs."methodologyVersionId" neexistoval, sessions completed 220/203, active 85/85, abandoned 53/53, paused 1/1, 2 tenanti (⇒ RLS smyčka v migraci má smysl, prostý SET LOCAL by druhého minul); po — migrace zapsaná, sloupec uuid/nullable, počty všech stavů beze změny (re-pin mění hodnoty, ne počty) a otisk pinů rozpracovaných se ZMĚNIL b13fef74… → cbdaa1ca… ⇒ re-pin reálně proběhl. Konvergence ověřena dotazem, ne důvěrou: rozpracované (active+paused) proti aktivní verzi metodiky → prod 76 sedí / 0 NESEDÍ / 10 bez aktivní verze (celkem 86), hub 50 / 0 / 10 (celkem 60). Těch 10 bez aktivní verze sedí přesně s tím, co autor migrace předpověděl v komentáři („10 spících konzultací na 5 vyřazených metodikách") — nezávislé potvrzení, že migrace udělala právě to, co slibovala. Auditní záznamy (completed/abandoned) nedotčeny konstrukčně — WHERE … AND s.status IN ('active','paused') přímo v UPDATE (přečteno z nasazeného zdroje; baseline otisku audit skupiny jsem si předem nevzal, tohle je silnější důkaz než porovnání). RAISE NOTICE '[CR-218] …' se nikam nepropisuje (client-directed, log_min_messages je WARNING) ⇒ počty z logů nedohledatelné, proto dotaz výše. ⚠️ down() re-pin NEVRACÍ (jen dropne sloupec) — rollback migrace by rozpracované konzultace nechal na aktivních verzích; záměr autora, ale je to jednosměrka |
✅ | sentinel |
| 2026-08-02 | billit | hub | 83123a7 (DEPLOY OK billit hub Libor; INFO T-20260802-043) — proti nasazenému 7c490bc jen 2 soubory: tenant-middleware-coverage.spec.ts (+89) a docs/modules/registries/SPEC.md, produkční kód bit-identický ⇒ cíl deploye = srovnat runtime commit s HEAD, aby main přestal hlásit drift. Selective deploy billit-api, migrace „No migrations are pending", health api+web 200. ⚠️ DEPLOY.SH VYHLÁSIL FALEŠNÝ FAIL (STALE ARTEFAKT — zdroj se změnil, ale build v kontejneru ne, src_hash 9d785ac6→a4c6b9c1 změněn, dist_hash c4ada723 beze změny, „Image vznikl 08:00:38 ← starší než předchozí deploy") ⇒ HEALTH_OK=false, QA gate se nespustil, .deploy-info se nezapsalo (zůstalo na 7c490bc, ačkoli .deploy-commit = 83123a7). Verdikt guardu byl ale ŠPATNĚ — doloženo přímými důkazy: /api/version → {"commit":"83123a7","buildTime":"2026-08-02T07:49:20Z"} (= 09:49 CEST, tedy z TOHOTO běhu) a env kontejneru BUILD_COMMIT=83123a7. Proč obě nepřímé kontroly minuly: (1) dist se nezměnil legitimně — .spec.ts se do dist nekompiluje a *.md je v .dockerignore, takže delta se do artefaktu nemá jak promítnout; (2) .Created u multi-stage buildu dědí čas z cachovaných runtime vrstev (dist identický ⇒ cache hit), takže „starší image" ≠ „nepřestavěný" — mění se jen config (ENV BUILD_COMMIT) ⇒ nové image ID se starým Created. FIX c888fe2: stale-guard nově čte zapečený commit z artefaktu (BUILD_COMMIT/GIT_COMMIT/SENTINEL_COMMIT/COMMIT_SHA z env kontejneru) — přímý důkaz původu buildu; při shodě (prefix-tolerantní na zkrácený hash) se obě nepřímé stale-větve přeskočí a vypíše se dist beze změny, ale zapečený commit souhlasí ⇒ delta se nekompiluje; při NEshodě naopak nová tvrdá FAIL větev PŘED nepřímými kontrolami (artefakt sám přiznává jiný commit = nejsilnější důkaz stale buildu). Ověřeno oběma směry: BAKED_OK=true proti 83123a7, false proti 7c490bc. Motivace: falešný poplach je tu nebezpečný dvakrát — učí mě guard přebíjet, a přesně tenhle guard vznikl po incidentu --skip-build ([[feedback_skip_build_fakes_verified]]). Ověření fixu v nasazeném artefaktu: grep TenantMiddleware /app/dist/modules/registries/registries.module.js → přítomno (hotfix 500 na /channels, /vendor-mappings). ⚠️ Billitovy akceptační kroky mají past: GET /v1/accounts/studio-60/channels vrací 200 + HTML — nginx routuje /api,/health,/docs na api a / na web, takže /v1/... trefí frontend; správně /api/v1/... → 401 (auth guard, handler tím neověřen — [[feedback_smoke_auth_blocker]]). RE-RUN (DEPLOY OK billit hub ×2, 10:00) = ostrý test fixu: guard nově vypsal Zapečený commit: 83123a7 (v artefaktu — souhlasí) a VERIFIED (commit + source hash; dist beze změny, ale zapečený commit souhlasí ⇒ delta se nekompiluje — typicky testy/docs) ⇒ falešný FAIL zmizel, aniž by se cokoli přebíjelo flagem; labely nově 2/2 (i billit-web), QA gate PASS 10/10 (PATCH; regression billit-spec-tenants + billit-webhook, authed větve SKIP — chybí billit QA ApiKey po CR-033, tedy známý stav, ne regrese). Evidence srovnána: .deploy-info = 83123a7/a4c6b9c1…, QA stamp 2026-08-02T08:00:33Z commit=83123a7 qa=pass, /api/version = 83123a7 ⇒ záznam a realita souhlasí, drift vyřešen. PROD (DEPLOY OK billit prod, 10:07): opravený guard prošel i tady bez jediného falešného poplachu — Zapečený commit: 83123a7 (souhlasí) + VERIFIED; labely 1/2, billit-web-1=a413e16 akceptován jako starší předek (= ten drift, který main v T-20260802-052 vyhodnotil jako false positive — potvrzuji nezávisle: billit-web/* se mezi a413e16 a 83123a7 nezměnil). Ověření: /api/version → 83123a7 (buildTime 08:07:00Z = z tohoto běhu), /health 200, tři endpointy hotfixu /api/v1/accounts/studio-60/{channels,vendor-mappings,catalog-sync/config} → 401 JSON (routing OK, žádná 500; handler tím ale ověřený NENÍ — auth guard běží dřív, [[feedback_smoke_auth_blocker]]), TenantMiddleware přítomen v /app/dist/modules/registries/registries.module.js. Ověřeny i dvě „NENASTAVOVAT" podmínky billitu: CATALOG_SYNC_PLATFORM_SLUG není v env (cron katalogu tedy zůstal záměrně vypnutý) a BADWOLF_CATALOG_URL není (platí default api.studio60.cz) ⇒ ruční POST /catalog-sync/run zůstává na billitu. 📝 Opravena zastaralá dokumentace: services/billit/INDEX.md uváděl prod URL i health check na billit.cz, ta ale od DEC-014 vrací 301 na ucto.studio60.cz — health check by tiše „prošel" na redirectu místo na aplikaci; doplněna i past s prefixem /api |
✅ | sentinel |
| 2026-08-02 | venom | hub | b09c585 (DEPLOY OK venom hub Libor; TODO T-20260802-064, delta ae66059→b09c585 = 3 commity, 11 souborů) — REQ-036 přehození přihlašovací adresy klienta (detail klienta → Přístupy: „Která adresa je ta správná?" se dvěma cestami — přehodit přihlašování / opravit e-mail klienta) + pojistka, aby propojený klient s adresou, kterou auth nezná, přestal svítit jako „Nemá účet" s nabídkou založení účtu (vyrobilo by témuž člověku DRUHÝ účet). Nasazeno až po badwolf fd69740, schválně — bez něj by 409 z authu propadl jako auth_error. --skip-ci dle runbooku (známý vitest×Playwright misconfig, vite build typechecká sám). Commit VERIFIED (source hash 34179e54… local==remote), labely 1/1, QA gate PASS (RELEASE tier, 4 venom checks). ⚠️ Build hash unknown — venom je statický nginx bez /app/dist/*.js, takže tady build hash nic nedokazuje a rozhoduje servírovaný bundle; ten guard je záměrný (dřív vracel konstantu 886f4202… a tvářil se jako důkaz, viz [[feedback_skip_build_fakes_verified]]). Ověření staženým bundlem /assets/index-OcxPSURX.js (2,67 MB): per-env baked URL api.s60hub.cz 1× + auth.s60hub.cz 2×, api.studio60.cz 0× + auth.studio60.cz 0× ⇒ hubovský build, ne omylem prodovský; REQ-036 fyzicky v kódu — „Která adresa je ta správná" 1×, „Přehodit přihlašování" 1×, conflict_other_identity 1× (párovník k badwolfovu fd69740), sessionsInvalidated 1×, login-email 2×, potvrzovací dialog „zařízen" 1× + „Odhlás" 3×, pojistka „Nemá účet"/„Založit účet" 1×. AUTH_DIRECTORY_* ověřeno v běžícím kontejneru badwolfa: hub AUTH_DIRECTORY_URL=https://auth.s60hub.cz + klíč s60_9e45…, prod https://auth.studio60.cz + s60_f114… ⇒ T-20260801-183 vyřešeno na obou. ⚠️ Na hubu ale REQ-036 zatím skončí „nemáme oprávnění" — hubovský directory klíč má jen directory:read; auth v T-20260802-063 §5 potvrdil, že má dostat i directory:write s vazbou na BW Legacy Integration (hubovské ID), a vazba je NEMĚNNÁ (CR-019 system_binding_immutable) ⇒ jedním vědomým krokem, čeká na Libora. Drobnost k předání: QA audit hlásí migration_from=c107e50 vs. běžící b09c585 — stará hodnota ve venom DEPLOY.md, neblokuje. PROD (DEPLOY OK venom prod): commit VERIFIED (34179e54… local==remote), labely 1/1, bundle /assets/index-CD_K8ji1.js (jiný soubor než hubovský — správně, per-env build), baked URL api.studio60.cz 1× + auth.studio60.cz 3× + venom.studio60.cz 1×, hubovské 0× ⇒ žádný cross-env únik ani jedním směrem; všech 7 REQ-036 řetězců přítomno. Křížová kontrola velikostí: prod bundle je přesně +10 B proti hubovému a per-env hostnames se liší v 5 výskytech × 2 znaky (s60hub→studio60) = +10 B ⇒ rozdíl bundlů je beze zbytku vysvětlený záměnou hostnames, nic jiného se mezi prostředími neliší. 🔎 NÁLEZ MIMO ROZSAH (venom, nahlášeno T-20260802-073, neblokuje): src/main.tsx:10 má environment: import.meta.env.MODE — Vite nastavuje MODE=production při každém vite build, takže hubovský bundle hlásí chyby do GlitchTipu jako production; ověřeno v obou bundlech identicky dsn:"…@errors.studio60.cz/4",environment:"production" a doloženo v GlitchTip DB: projekt 4 (venom) má registrované jediné prostředí production (16 issues, 2026-07-13 → 2026-08-02), zatímco projekt 5 (badwolf) správně rozlišuje hub/prod/dev ⇒ hubovské chyby venoma jsou v produkční telemetrii nerozlišitelné od reálných. Fix je na straně venoma (číst VITE_SENTRY_ENVIRONMENT), pak doplním do /root/secrets/venom/.env.<env> — dnes tam ta proměnná není a kód ji ani nečte (čte jen MODE, VITE_API_URL, VITE_AUTH_URL, VITE_CALLBACK_URL, VITE_SENTRY_DSN). Týž vzorec jako auth REQ-053 z 08-01. Vedlejší, drobné: cortex.studio60.cz/thread/… natvrdo v ThreadsSection.tsx:141 + TimelineItem.tsx:178 ⇒ z hubu vedou odkazy na produkční Cortex |
✅ | sentinel |
| 2026-08-02 | badwolf | hub + prod | fd69740 (DEPLOY OK badwolf hub + DEPLOY OK badwolf prod Libor; TODO T-20260802-067, delta 2033c57→fd69740 = 2 commity, kódově jen f48a040) — narovnání kontraktu CR-021 endpointů podle nálezu venoma (T-20260802-033): 409 z authu doteče ven jako 409 conflict_other_identity (dřív propadl překladem chyb, který znal jen 403/404, a operátor četl „zkus později" u stavu, co se sám nespraví); sessionsInvalidated se čte z odpovědi authu místo natvrdo true (auth odhlašuje jen při status='changed', takže timeline dosud tvrdila odhlášení, ke kterému nedošlo); emailMismatch byl v OpenAPI holý Object → codegen z něj dělal Record<string, never>, nově má DTO. Žádná migrace, žádná env, žádný nový endpoint — ověřeno git diff --name-only, nic pod migrations/. Předletová kontrola podmínky badwolfa (bez tabulky course_sites vrací veřejný GET /api/courses 500 a tahá si z něj katalog web KVT): tabulka na hubu existuje a vlastní ji s60_badwolf_hub_user ⇒ oprava vlastnictví z 08-01 drží (viz [[feedback_su_created_seq_needs_owner]]). Commit VERIFIED — build hash se reálně změnil b494ca3e…→566266f3…, source hash local==remote d16f8108…, labely 1/1, QA gate PASS 4/4 (PATCH tier). Ověření chováním, ne labely (všechny 4 kroky, které si badwolf vyžádal): /api/health → fd69740; EmailMismatchDto.properties → ["clientEmail","primaryEmail"]; ClientEmailConflictDto.properties.conflictClientId.nullable → true; regrese katalogu ?site=nogames → 20, ?site=kvantova → 18, bez filtru → 20 ⇒ shoda s produkcí (badwolf tamtéž naměřil 20/18/20), filtr si udržel větev NOT EXISTS a katalog se nevyprázdnil. PROD (DEPLOY OK badwolf prod, ~6 min po hubu): commit VERIFIED, source hash d16f8108… local==remote, build hash 566266f3… BIT-IDENTICKÝ s hubem (týž zdroj ⇒ deterministický build, extra důkaz parity), labely 1/1, snapshot 20260802-0930-fd69740 (2,4 M); QA gate se na produkci záměrně nespouští — brána místo toho ověřuje hub stamp z předchozího běhu (deploy.sh:1369 gate jen pro ENV==hub, prod kontroluje ${PROJECT}-qa-pass na sentinelu), takže prod nešel naslepo. Ověření chováním na produkci: /api/health → fd69740 + status:ok; EmailMismatchDto → ["clientEmail","primaryEmail"]; conflictClientId.nullable → true; katalog 20/18/20 shodně s hubem i s tím, co badwolf naměřil PŘED deployem ⇒ nic se nerozbilo; select count(*) from courses where is_active=false → 8 na produ i na hubu (badwolf hlásil 8 před deployem, migrace 077 na courses nesáhla ani teď). ⚠️ Pozor na tvar sloupce: v DB je is_active (snake), camelCase "isActive" je jen v API — první dotaz proto spadl na column does not exist, viz [[feedback_facts_not_memory]]. Otevřené, neblokující: RO role s60_badwolf_debug nemá GRANT na course_sites (badwolf to musel ověřovat přes API) — záměrně bez zásahu, rozhodne Libor |
✅ | sentinel |
| 2026-07-30 | pulse | hub + prod | 628b280 (CR-219 heartbeat měří kanál, ne provoz + CR-217 už z a79a35c; DEPLOY OK pulse hub ×2 + WRITE OK secrets pulse Libor; pulse GO neexistoval — INFO T-20260730-021 výslovně „není to pokyn k deployi", Libor rozhodl „nejdřív komplet hub, pak komplet prod"); delta a79a35c→628b280 = 6 commitů, 1 funkční (32d3277), 11 souborů +1441/−270, žádné migrace; nové utily sentry-dsn.util.ts + escalation-target.util.ts = implementace mých dvou hlášení (T-20260730-011 spam + T-20260730-018 DSN); předletová kontrola konfigurace (obava z opakování FREELO_* pasti vyvrácena čtením kódu): všechny nové klíče mají defaulty — FREELO_ESCALATION_ENVS→['PROD'], GLITCHTIP_BASE_URL→https://errors.studio60.cz, ORG/PROJECT_SLUG→studio-60/pulse, canary timeout 90 s / interval 5 s ⇒ žádná nová env proměnná k deployi; dvoufázové ověření na hubu (záměrně rozdělené, aby se nová detekce dala vidět na reálné poruše): fáze 1 deploy se STÁVAJÍCÍM UUID DSN → boot log [GLITCHTIP_INVALID_DSN] SENTRY_DSN je nastavený, ale SDK ho nepřijalo — do GlitchTipu neodchází nic + detail „pomlčky v public key … řešení: týž klíč bez pomlček" ⇒ CR-219 poznalo skutečnou vadu, která měsíce mlčela; fáze 2 SENTRY_DSN přepnut na hex tvar a980259096c14a8a825aae26e63f9ae7 (.env.hub, záloha *.bak-20260730-dsn-hex) + --skip-build propsání → Invalid Sentry Dsn 0 výskytů, boot log [glitchtip] HUB monitoring aktivní — token ✓, **canary event dosedl za 5976 ms**; DŮKAZ V GLITCHTIP DB: issue 71 [canary] pulse alerting heartbeat (count 3) + poprvé i REÁLNÉ chyby aplikace — issue 72 Metodika 'nonexistent-slug-xyz-999' ne… a issue 13 Invalid signature (count 5, vyvolané QA gate testy) ⇒ hex DSN funguje i v Sentry.init(), nejen v ručním curl; QA gate PASS 15/15 obakrát, commit VERIFIED, labely 1/1; hub Freelo mlčí ([freelo] eskalace vypnutá přes FREELO_ESCALATION=false, navíc default ENVS=['PROD'] by to utnul i bez toho); PROD (WRITE OK secrets pulse + DEPLOY OK pulse prod Libor, Liborovo zadání „nejdřív komplet hub, pak komplet prod"): hex DSN nasazen SOUČASNĚ s kódem (.env.prod, záloha *.bak-20260730-dsn-hex, parita hub==prod ověřena) — záměrně, protože FREELO_ESCALATION_ENVS=['PROD'] by z invalid-dsn jinak vyrobil task v Liborově Freelu; timing: před deployem přeměřeno sessions = 79 active, ale 0 aktivních za 2 h i za 30 min, poslední aktivita 12:04 ⇒ CR-217 nikomu nepřerušil běžící konzultaci; commit VERIFIED (source hash 68e4d9a3…), labely 1/1, migrace „No migrations are pending" (159–166 proběhly při startu kontejneru), pulselab.cz/api/version commit=628b280 + /app/ + /admin/ 200; boot log 8× [CR217] (ideal-customer v8 „diakritika obnovena", brand-guide v6 „sloučeno ze 6 fází") + [glitchtip] PROD monitoring aktivní — token ✓, **canary event dosedl za 5721 ms** + [freelo] PROD eskalace aktivní — projekt 584175 dosažitelný, **tasky se zakládají v: PROD**; kontrolní SQL na prod DB: všech 8 metodik otazek=16, extractFields=0 ✅ a klientem viditelný text Řeknete, co zákazníka trápí (bylo Reknete, co zakaznika trapi) ⇒ 128 otázek + 20 026 znaků promptů obnoveno na produkci, bot přestal improvizovat; Freelo po deployi 23 tasků = beze změny (žádný nový falešný alert, 0 ne-heartbeat tasků) a GlitchTip issue 71 canary count 4 (17:02) ⇒ smyčka zlomená: heartbeat teď měří kanál, ne provoz |
✅ | sentinel |
| 2026-07-31 | auth | hub + prod (secrets + DSN) | 54e326e beze změny kódu — doplněn chybějící SENTRY_DSN (WRITE OK secrets auth + DEPLOY OK auth hub Libor; poslední skutečný auth deploy byl 2026-05-22); výchozí stav: SENTRY_DSN= prázdný ve všech vrstvách ⇒ projekt 1 (s60-auth) měl 0 issues za celou existenci; klíč vzat z GlitchTip DB, ne z KB (fb395cb3-e576-49a7-a4b6-54b76dc51778 → hex fb395cb3e57649a7a4b654b76dc51778); ✅ obava z backend/.env pasti VYVRÁCENA měřením: md5 /opt/auth/backend/.env == /root/secrets/auth/.env.prod (a23f6d0e…) ⇒ deploy.sh sype secrets právě sem; /opt/auth/.env (fcd471b5…) je jiný, mrtvý soubor, který backend nečte; VERIFY hub: v kontejneru hex DSN, Invalid Sentry Dsn 0×, backend i frontend running/healthy, md5 /opt/auth/backend/.env == .env.hub (978ed90d…), auth.s60hub.cz/.well-known/openid-configuration 200, QA gate PASS 4/4; 🔴 DVA NÁLEZY PRO AUTH AGENTA (kód, ne moje doména): (1) backend má Sentry.init() v backend/src/main.ts, ale 0 souborů s captureException/captureMessage ⇒ stejně jako badwolf nahlásí jen pád procesu, chyba v endpointu skončí v NestJS filtru; (2) frontend DSN se technicky nedá doručit — frontend/src/main.tsx čte import.meta.env.VITE_SENTRY_DSN (Vite zapéká při buildu), ale compose služby s60-auth-frontend má jen build: ./frontend bez args: a bez env_file ⇒ proměnná nemá jak do buildu vstoupit; přitom právě tady by byl největší přínos, @sentry/browser unhandled chyby zachytává sám bez instrumentace; PROD (DEPLOY OK auth prod Libor, po explicitním upozornění na ~vteřinovou pauzu loginu — auth běžel bez restartu od 2026-05-22): commit VERIFIED (source hash cd1020b2…), labely 2/2, backend i frontend running/healthy, v backendu hex DSN, Invalid Sentry Dsn 0×, 0 ERROR v logu po startu, md5 /opt/auth/backend/.env == .env.prod (aeaddf8a…), auth.studio60.cz/.well-known/openid-configuration 200 s issuer=https://auth.studio60.cz a 4 endpointy ⇒ login provider naskočil čistě; ⚠️ projekt 1 zůstane na 0 issues, dokud auth agent nedoplní captureException + build arg pro frontend (nahlášeno T-20260731-005) |
✅ | sentinel |
| 2026-07-30 | s60-mail | hub + prod (secrets + DSN) | 36a41f6 beze změny kódu — doplněn SENTRY_DSN (WRITE OK secrets s60-mail → poté WRITE OK secrets mail + DEPLOY OK s60-mail hub ×2 Libor); ⚠️ SEBEKOREKCE — první pokus šel do SLEPÉ VĚTVE: zapsal jsem hex DSN do /root/secrets/s60-mail/, deploy proběhl čistě (QA 3/3), ale v kontejneru zůstalo NENASTAVEN; root cause: deploy.sh:515 má natvrdo zadrátované přemapování [[ "$PROJECT" == "s60-mail" ]] && SECRET_PROJECT="mail" ⇒ živý adresář je /root/secrets/mail/, zatímco /root/secrets/s60-mail/ je mrtvý duplikát, který nikdo nečte; jak jsem to prokázal: md5 nasazeného /opt/s60-mail/.env (6baa11d0…) == /root/secrets/mail/.env.hub, ≠ /root/secrets/s60-mail/.env.hub (0d45e3b0…) ⇒ „deploy skončil zeleně" NEDOKAZUJE, že se hodnota propsala; korekce diagnózy: mail neměl „DSN v UUID tvaru" — v živých secrets neměl SENTRY_DSN vůbec (ten s pomlčkami existoval jen v opuštěném duplikátu) ⇒ proto 3 issues naposled 25. 6.; FIX: SENTRY_DSN=https://7e308f4baf8742bf9e589244d28935c7@errors.studio60.cz/6 (hex, projekt 6) přidán do /root/secrets/mail/.env.{hub,prod} (zálohy *.bak-20260730-dsn), hub propsán --skip-build → v kontejneru hex DSN, Invalid Sentry Dsn 0×, running/healthy, /opt/s60-mail/.env má proměnnou; ✅ mail MÁ instrumentaci (Sentry.init() + captureException/captureMessage v 5 souborech) → na rozdíl od badwolfa bude reálně reportovat; KB opravena — services/mail/INDEX.md tvrdila Status: stopped (čeká na Resend domain verification), ve skutečnosti kontejner běží healthy na hub i prod (stale od ~07/2026) + doplněna sekce o pasti se secrets adresářem; PROD (DEPLOY OK s60-mail prod Libor): propsáno --skip-build, commit VERIFIED, labely 1/1, v kontejneru hex DSN, Invalid Sentry Dsn 0×, running/healthy, a md5 cross-check /opt/s60-mail/.env == /root/secrets/mail/.env.prod (8e0906ef…) = důkaz propsání, ne jen zelený deploy; TODO: mrtvý duplikát /root/secrets/s60-mail/ smazat/přejmenovat (čeká na Liborovo OK) + prověřit, zda podobný mismatch jméno-služby vs adresář-secrets není i jinde |
✅ | sentinel |
| 2026-07-30 | ekosystém | audit (GlitchTip DSN napříč službami) | Změřeno, kdo do GlitchTipu reálně posílá (po nálezu hex-DSN u pulse; Liborovo „proměř to"); metoda: tvar SENTRY_DSN/VITE_SENTRY_DSN v secrets + hodnota v běžícím kontejneru + Invalid Sentry Dsn v logu + issue_events_issue per projekt — ne jen jedna vrstva; ⚠️ SEBEKOREKCE: první scan označil auth jako „hex OK" — chyba klasifikace (prázdná hodnota nemá pomlčku ⇒ spadla do větve hex); a hypotéza „celý ekosystém posílá nulu" NEPLATÍ; výsledek: ✅ billit (hex v kontejneru, 42 issues, ticho od 25. 7. = málo chyb ≠ porucha), ✅ venom (má OBĚ proměnné — backendový SENTRY_DSN s pomlčkami se nepoužívá, ale VITE_SENTRY_DSN je hex a jde do prohlížečového bundlu ⇒ 15 issues, poslední 29. 7.), ✅ pulse (opraveno dnes); ❌ badwolf (UUID s pomlčkami, Invalid Sentry Dsn v prod logu, 0 issues za celou existenci), ❌ s60-mail (UUID v secrets a navíc v /opt/s60-mail/.env i v kontejneru chybí úplně ⇒ nedoručený env, 3 issues, poslední 25. 6.), ❌ auth (SENTRY_DSN= PRÁZDNÝ ve všech vrstvách — secrets → /opt/auth/.env → /opt/auth/backend/.env → kontejner ⇒ 0 issues nikdy; navíc backend kontejner čte jiný soubor /opt/auth/backend/.env než ten, který plní deploy.sh → po doplnění hodnoty ověřit, že dorazí tam, kam má); FIX badwolf (WRITE OK secrets badwolf + DEPLOY OK badwolf hub Libor): SENTRY_DSN → hex 34969ed625ac45d0a5f3a4627b067735 v .env.{hub,prod} (zálohy *.bak-20260730-dsn-hex), hub propsán --skip-build (QA PASS 4/4) → v kontejneru hex, Invalid Sentry Dsn 0×; prod dostane opravu zdarma s čekajícím deployem f987af1; 🔴 DRUHÝ BLOKÁTOR U BADWOLFA (kód, ne moje doména): @sentry/node v10 + Sentry.init() v main.ts, ale ANI JEDEN captureException/captureMessage, žádný ExceptionFilter/@Catch() ⇒ i s funkčním DSN nahlásí jen pád procesu (globální handlery), běžná chyba v endpointu skončí v NestJS filtru jako HTTP 500 a do GlitchTipu se nedostane ⇒ „0 issues" mělo dvě příčiny; nahlásit badwolfovi (samotná oprava DSN nestačí) |
✅ | sentinel |
| 2026-07-30 | hub | ops (UFW) | 150.228.35.120 povolena na 443/tcp (ufw allow … comment 'libor testing 2026-07-30', Liborův explicitní pokyn; runbook hub-add-libor-ip.md, model [[project_hub_ufw_allowlist]]); ostatní pravidla nedotčena; ⚠️ allowlist bobtná — už 4 „libor testing" IP (78.80.97.19 06-19, 150.228.35.49 07-18, 150.228.35.236 07-23, 150.228.35.120 07-30) = dynamická IP, starší jsou nejspíš mrtvé → nabídnut úklid, čeká na pokyn |
✅ | sentinel |
| 2026-07-30–31 | badwolf | hub + prod | f987af1 (CR-012 viditelnost termínu + CR-013 kurzy do sync domény; badwolf TODO T-20260730-026, DEPLOY OK badwolf hub + samostatné „migrace OK" Libora — deploy token jsem záměrně nebral jako souhlas s daty); delta c0eabd9→f987af1 = 5 commitů; byznys: 6 budoucích termínů skrytých kanceláří se na webu tváří prodejně (Jenkins terms.visible se do BW nikdy nepřenesl) + 15 z 19 kurzů má názvy/ceny zmražené na 2026-02-15 (tabulka courses nebyla v syncu vůbec); PŘEDPOKLADY OVĚŘENY PŘED STARTEM: sync_rowhash() existuje v obou DB (073 na ni věší trigger) + /opt/badwolf/docker-compose.yml má build: sekci ⇒ nehrozí [[feedback_deploy_build_command_dead]] tichý no-op; baseline hub == prod (žádný z nových sloupců neexistoval, 352 course_dates, 20 courses = 19 mapovaných + TEST-01); MIGRACE RUČNĚ (badwolf má migration_command: null, deploy.sh je nespouští — pořadí je nevratné: kód selectuje is_visible/is_active, bez sloupců by hub 500-oval): pg_dump courses+course_dates → /var/backups/badwolf-cr012-013/hub-pre072-073.sql (110K, pg-alfa), pak 072 (ADD COLUMN is_visible + sync_hash_columns) a 073 (is_active backfill z metadata.isActive, nevratné odmazání metadata.isActive/isVisible, row_hash + trg_rowhash_courses, sync_hash_columns) jako app_user na přímém :5432 (ne SU → trigger vlastní app user, žádný [[feedback_su_created_seq_needs_owner]] problém), ON_ERROR_STOP=1, obě v BEGIN/COMMIT → UPDATE 20 + UPDATE 20; VERIFY DB: oba sloupce existují, metadata s isActive/isVisible zbývá 0, trigger na místě, sync_hash_columns = end_date,is_visible,start_date,state / base_price_czk,base_price_eur,is_active,name, row_hash NULL u 0 z 20 (trigger si hash dopočítal — přesně badwolfovo očekávané číslo); DEPLOY: commit VERIFIED (source+build hash f18552f0…), labely 1/1, QA gate PASS 4/4 (PATCH), api.s60hub.cz/api/course-dates 200 se 352 položkami a novými poli isVisible+isDatePlaceholder, isDatePlaceholder=true u přesně 5 ✅ = shoda s badwolfovým měřením; 🔴 BLOKÁTOR post-deploy kroku: applier course_dates vrátil samé nuly — v sync_outbox (dev) leží 352 + 19 řádků ve status_hub='needs_review' s chybou 42703: column "is_visible"/"is_active" … does not exist, vytvořené dnes 05:45 a 06:49 hodinovým cronem, tedy PŘED migracemi ⇒ data v pořádku, jen zaparkovaná; reset SQL si nepíšu sám (runbook jenkins-sync-applier.md: „Cizí reset SQL neopravuju sám — autor dodá jenkins_id seznam") — navíc 073 změnila hub data, takže naivní reset statusu může vyrobit guardConflict proti expected_baseline → vyžádat postup od badwolfa; DOKONČENO 2026-07-31 — badwolf dodal reset (T-20260730-031) a posunul cíl na HEAD 74579e7 (kód f36c133; přibylo CR-014 telemetrie do GlitchTipu = implementace mého nálezu T-20260730-040, a CR-015 selhané BullMQ joby; bez migrací, nová env SENTRY_ENVIRONMENT); (1) RESET (reset OK Libor): pg_dump sync_outbox+sync_state (13M), blast radius RO ověřen — rozsah 698650–699020 = přesně 371 řádků, defer_count=9 > MAX_DEFER 8 → terminální stav; UPDATE zabalen do DO bloku s guardem na ROW_COUNT ≠ 371 → RAISE → rollback → OK: resetováno 371 řádků; status_prod i error záměrně nedotčeny (badwolfova past: defer_count/next_attempt_at jsou sdílené napříč env ⇒ předčasný reset produ by zastavil i hub applier); (2) APPLIER: courses 19/19, course_dates 352/352, guardConflict 0 v obou; (3) VERIFIKACE — všech 8 badwolfových čísel SEDÍ: is_visible 90 false / 262 true, 10 budoucích skrytých z toho 6 open, isDatePlaceholder u 5; is_active=false u přesně těch 8 slugů, hojnost→true, petidenni přejmenován, nogames 7900/330, popis u petidenni-opakovani zachován, row_hash NULL u 0; sync_state.hub_applied_hash u courses 19/19 (bylo 0), nové sync_conflicts 0; (4) DEPLOY HEAD (DEPLOY OK badwolf hub): commit VERIFIED, QA 4/4, healthy restarts=0, /api/health version=74579e7, oba endpointy 200, v kontejneru hex DSN + SENTRY_ENVIRONMENT=hub; 🔬 CR-014 OVĚŘENO ŽIVĚ (badwolf měl do včera 0 issues za celou existenci): 2× kontrolované 500 → oba eventy dosedly (issue 77 nový + 74 count→3), 404 nevytvořilo nic ⇒ filtr jen na 5xx funguje; tags->>'environment' u mých eventů = hub, zatímco včerejší dev event nesl production ⇒ zpětný důkaz cross-env kontaminace i její nápravy; (5) REPRICE (apply OK Libor): dry-run 3 kandidáti → --apply → 3 termíny 6900/290 → 7900/330, druhý běh 0 kandidátů (idempotence), cena mimo hash allow-list ⇒ žádný CAS churn; pozn. nogames je neaktivní a ty termíny skryté (D3) ⇒ příprava dat, ne změna pro zákazníka; PROD DOKONČEN 2026-07-31 (migrace OK, reset OK, apply OK + DEPLOY OK badwolf prod Libor): (1) pg_dump courses+course_dates → prod-pre072-073.sql (110K); (2) migrace 072→073 jako app_user na :5432 — SQL soubory md5-identické s těmi, co jely na hubu (f89c2aca…), UPDATE 20 + UPDATE 20, verify: sloupce ✅, metadata zbývá 0, trigger ✅, row_hash NULL u 0 z 20, sync_hash_columns u obou tabulek; (3) deploy HEAD 74579e7: commit VERIFIED (source hash 7161e216…), labely 1/1, :3000/api/health 200, [6.5] No migration configured → skip (manual_sql, správně); (4) RESET prod varianta (s error=NULL) pod stejným ROW_COUNT guardem → OK: resetováno 371 řádků (prod); (5) APPLIER: courses 19/19, course_dates 352/352, guardConflict 0; (6) VERIFIKACE — prod čísla shodná s hubem i s badwolfovým měřením: is_visible 90 false / 262 true, 10 budoucích skrytých z toho 6 open, is_active=false u přesně těch 8 slugů, hojnost→true, petidenni→„Kurz kvantové terapie I", petidenni-opakovani popis zachován, row_hash NULL u 0; (7) REPRICE: dry-run 3 kandidáti — ⚠️ odchylka od hubu: 2026-11-05 měl na produkci už 7900/290 (CZK přeceněná, EUR ne), ostatní dva 6900/290 → --apply → všechny 3 na 7900/330, druhý běh 0 kandidátů; VÝSLEDEK: api.studio60.cz/api/course-dates + /api/courses 200, kontejner running/healthy restarts=0, SENTRY_ENVIRONMENT=prod, Invalid Sentry Dsn 0×; /api/health status=degraded = známý pre-existující emailIngest („žádná schránka neingestla >24 h", tasksTick ok) — NEsouvisí s deployem, dokumentováno už 2026-07-23; BYZNYS DOPAD: 6 budoucích termínů, které kancelář skryla a web je přesto nabízel jako prodejné, je od teď na produkci správně skrytých; 15 z 19 kurzů má po pěti měsících aktuální názvy a ceny (zmražené od 2026-02-15); GlitchTip badwolf eventy per prostředí: dev 3 / hub 2 / dev-probe 1 / production 1 ⇒ rozlišení prostředí funguje |
✅ | sentinel |
| 2026-07-30 | pulse | hub (dress rehearsal) — prod čeká | a79a35c (CR-217 obnova řemesla 8 metodik + DEC-018 + docs 1f65faf; pulse INFO T-20260730-006 = GO na 2. krok, DEPLOY OK pulse hub Libor „dress rehearsal"); kontext: 8 z 13 aktivních metodik přišlo 4.–6. 5. 2026 ve všech fázích o questions+systemPrompt → bot od té doby renderuje placeholder; zápisovou cestu zavřel CR-215 (prod od 23. 7.), obsah vrací tenhle release (128 otázek + 20 026 znaků fázových promptů); 8 data-only migrací 159–166 CR217*Restore (žádná změna schématu/sloupce/indexu; idempotentní, abort při neshodě počtu fází nebo slugu, funkční down(), nic se nemaže); BASELINE naměřen před deployem (sentinel, read-only přes pg-alfa SU): prod i hub → všech 8 metodik otazek=0, extractFields=0, fazi=4 ⇒ (a) poškození na produkci reálné, (b) hub-mirror z 18. 7. je pro tyhle migrace bit-reprezentativní ⇒ čerstvý prod→hub klon NENÍ potřeba (ušetřen scrub + prodové PII na hubu, runbook pulse-hub-dress-rehearsal.md v tomhle případě zbytečný); VERIFY hub: migrace se spustily při startu kontejneru (migrationsRun: true) → fáze [6.5] pak korektně „No migrations are pending", všech 8 záznamů CR217* v migrations; kontrolní SQL pulse: všech 8 slugů → otazek=16, extractFields=0, fazi=4 ✅ (verze ideal-customer v8, idea-to-sale v6, brand-guide v6, ostatní v4); boot log přesně 8 řádků [CR217] <slug>: v<N> aktivní — 4 fází, 16 otázek vč. ideal-customer … diakritika obnovena + brand-guide … (sloučeno ze 6 fází); doložená oprava klientem viditelného textu: ideal-customer fáze 1 prod „Reknete, co zakaznika trapi" → hub „Řeknete, co zákazníka trápí"; commit VERIFIED (source hash b7551fc3… local=remote), labely 1/1, QA gate PASS 15/15, health 200; ⚠️ build hash 639d841b… shodný s 8d29f72 = známá kosmetika deploy.sh, NE no-op (migrace proběhly + obsah DB se změnil, ověřeno jinak); současně propsán FREELO_ESCALATION=false (WRITE OK secrets pulse Libor, .env.hub, záloha *.bak-20260730-freelo-escalation) → v containeru potvrzeno false ⇒ hub přestal spamovat Freelo; PROD READINESS (pro rozhodnutí o 2. kroku — CR-217 se dotkne rozjetých konzultací, metodiky se načítají v onModuleInit, ne per-session): prod sessions = 215 completed / 77 active / 53 abandoned / 1 paused, ale jen 8 active dotčených za 48 h a poslední aktivita 2026-07-29 17:22 ⇒ v době měření žádná živá konzultace = ideální okno; ⚠️ token trap 2× (DEPLOY OK pulse hub, pak prod a DEPLOY OK pulse hub, dress rehearsal → user-prompt-capture.sh anchoruje celý řádek ⇒ token nevznikl, guard správně blokoval PŘED spuštěním) |
✅ | sentinel |
| 2026-07-26 | pulse | hub + prod | 8d29f72 + výměna Freelo účtu — pulse INFO T-20260725-025 = OPRAVA k T-...022: Freelo nemá jet pod Liborovým osobním admin klíčem (/root/dev/.env), ale pod agentím účtem info@studio60.cz (Freelo user 268855) — důvod: identita agenta na taskách, Liborův klíč mimo prod env, izolované odvolání; ⚠️ oprava dorazila 10:54:23Z, hub byl nasazen 10:48–10:52 → hub ~20 h běžel s Liborovým osobním klíčem; dopad ověřen = ŽÁDNÝ: Bug tasklist 1806459 0 tasků + hub pulse 0 ERROR/FATAL za celé okno ⇒ pod Liborovou identitou se do Freela nezapsalo nic; agentí účet ověřen read-only (WRITE OK secrets pulse Libor): GET /v1/project/584175 200 „S60 - Pulse", 7 workerů, 268855 mezi nimi ✅, GET /v1/tasklist/1806459 200 „Bug"; pulsova past potvrzena: GET /v1/projects vrací tomu účtu prázdné [] (vlastnost endpointu, NE chybějící přístup) → ověřovat detailem projektu; zápis netestován schválně (pulse ho protočil na devu task 31375492 create+delete); swap: sed -i v /root/secrets/pulse/.env.{hub,prod} (zálohy *.bak-20260726-freelo-agent), verify Liborův klíč 0× v obou aktivních souborech, nový klíč 1× (⚠️ dnešní zálohy ten osobní klíč z podstaty obsahují — ke smazání až Libor řekne); hub refresh --skip-build (DEPLOY OK pulse hub Libor): QA gate PASS 15/15, env v containeru FREELO_EMAIL=info@studio60.cz + key prefix 5JV55C1Z, boot self-report oba kanály pozitivní pod agentem: [freelo] HUB eskalace aktivní — projekt 584175 dosažitelný + [glitchtip] HUB monitoring aktivní — token ✓, poslední event před 1.1h (⚠️ ta 1.1h = sentinelův canary event, ne reálný provoz); čerstvý QA stamp → prod okno otevřené; PROD (DEPLOY OK pulse prod Libor, pin 8d29f72 kvůli bit-identitě s hubem; pulse mezitím posunul HEAD na 1f65faf = jen docs, sveze se příště): prod gate QA gate: PASS (07:16:14Z commit=8d29f72 qa=pass tier=PATCH) = čerstvý stamp se shodným commitem, Image Built + s60-pulse recreated, migrace „No migrations are pending" (db_change NONE), commit VERIFIED (source hash 41c83e69… local=remote + build hash 639d841b… identický s hubem), labely 1/1, :3100/health 200, pulselab.cz/api/version commit=8d29f72 buildTime 07:23:40Z, /app/ + /admin/ 200, env v containeru FREELO_EMAIL=info@studio60.cz + key prefix 5JV55C1Z (agentí účet, ne Liborův), boot self-report POZITIVNÍ: [freelo] PROD eskalace aktivní — projekt 584175 dosažitelný + [glitchtip] PROD monitoring aktivní — token ✓, poslední event před 1.3h ⇒ žádné FREELO_NOT_CONFIGURED (creds dorazily současně s kódem, jak pulse žádal); ⚠️ ta „1.3h" je pořád sentinelův canary event, ne reálný provoz → stale alert se vrátí ~24 h po smazání/vypršení kanárka, CR-216 to neřeší (viz řádek o diagnostice); CR-216 LIVE hub+prod, Freelo kanál po roce nefunkčnosti probuzen → první dny sledovat tasky v Bug listu 1806459 (5min throttle na stejnou zprávu) |
✅ | sentinel |
| 2026-07-26 | pulse | diagnostika (GlitchTip alert) | [PROD] glitchtip-heartbeat: poslední event před 24.0h → „Sentry SDK pravděpodobně rozbité — fix DSN" = PRAVDIVÝ FAKT, CHYBNÁ DIAGNÓZA (alert ze starého heartbeatu na produ, 165c3cc); měření: teď 2026-07-26 06:09Z, poslední event projektu pulse 2026-07-25 06:07:00Z = 24.04 h ✅ sedí; root cause: tím „posledním eventem" byl vlastní alert heartbeatu GLITCHTIP_API_TOKEN env var chybí (443×) — dev dostal CR-216 (chybějící token na devu už není error) → šum ustal → freshness čítač se sesypal; poslední SKUTEČNÁ chyba appky = 2026-07-23 10:11Z („COMMIT is not valid JSON") ⇒ 3 dny bez chyby na nízkoprovozní appce je normální stav, ne porucha; ingest ověřen aktivním kanárkem (sentinel → POST https://errors.studio60.cz/api/2/store/ s prod DSN klíčem a9802590… projektu 2): HTTP 200, event dosedl jako issue 68 2026-07-26 06:10:14Z ⇒ DSN i ingest v pořádku, prod má správný DSN a 0× Invalid Sentry Dsn v logu za 24 h; ⚠️ CR-216 tohle NEOPRAVÍ — dle pulsova popisu je nefunkční kanál (stale) error všude, takže po prod deployi bude alert chodit dál → patří to do logiky heartbeatu (aktivní self-ping místo odvozování ze stáří / per-env DSN+projekt+SENTRY_ENVIRONMENT / delší okno) = podklad pro samostatný CR, který pulse předvídal; ⚠️ vedlejší efekt: kanárek vynuloval čítač → alert bude ~24 h zticha, zase ze špatného důvodu (issue 68 ke smazání = návrat pravdivého stavu, čeká na Liborovo rozhodnutí); souvisí [[reference_pulse_glitchtip_heartbeat]] |
✅ | sentinel |
| 2026-07-26 | billit | secrets ops (hub + prod) | FLEXI creds zapsány (CR-069 aktivace, WRITE OK secrets billit Libor ×2) — hodnoty předal Libor přes /tmp/flexi (billit je odmítl poslat inline dle vlastní SECURITY.md, T-20260725-013/017); zapsány 3 proměnné FLEXI_BASE_URL+FLEXI_USER+FLEXI_PASSWORD do /root/secrets/billit/.env.{prod,hub} (zálohy *.bak-20260725-flexi / *.bak-20260726-flexi), FLEXI_COMPANY záměrně vynechán — Libor: dev pozůstatek, firma se bere per tenant ze settings.flexi.company (flexi-client.ts:61-63 čte jen 3); creds předem ověřeny read-only: GET /c.json 200, na serveru jediná agenda studio_60_s_r_o_ („Studio 60 s.r.o.", created 2026-07-23, ESTABLISHED), changes/status.json → „Changelog is enabled" (FR-2 readback má na čem jet), changes.json globalVersion=16 obsahuje billitův dev push faktura-prijata code:PF0001/2026 ext:BILLIT:EXP-40c7b9e7…; fázováno: nejdřív jen prod (sentinel flagnul riziko — jediná agenda + hub je prod-mirror ⇒ enabled tenant na hubu by tlačil do ostrého účetnictví), poté Libor: „agenda je na nečisto, klidně vymazat, zkoušíme/ladíme → hub může mířit na stejné místo" ⇒ hub dorovnán, parita obnovena (oba soubory 3 vars, shodný md5 f34891a0); /tmp/flexi (mode 644) po zápisu smazán; ⚠️ do kontejnerů se env dostane až příštím billit deployem (deploy.sh sync /opt/billit/.env ze secrets) — modul zůstává pasivní i tak, settings.flexi.enabled = 0 tenantů hub i prod (aktivace = Liborovo O4 rozhodnutí) |
✅ | sentinel |
| 2026-07-25 | pulse | hub (prod čeká) | 8d29f72 (CR-216 — hlásné kanály prostředí-vědomě + nativní Freelo klient; pulse TODO T-20260725-022, zadal Libor; DEPLOY OK pulse hub Libor (heads-up „měl bys mít release" ≠ příkaz); pinnut 8d29f72 = master HEAD, NE 3a7f099 — kód je bit-identický, ale DEPLOY.md je správně vyplněný teprve v HEAD (v 3a7f099 deklaruje ještě Current: 165c3cc → gate by čtl starou sekci) ⇒ /api/version vrací 8d29f72, ne 3a7f099 jak čeká pulsův checklist (nahlásit pulse); baseline: prod 165c3cc + hub 165c3cc (pulse hub neznal, „sentinel ověří" → ověřeno), delta = 4 commity / 1 funkční (3a7f099), 18 souborů +1777/−392; glitchtip-heartbeat.service.ts smazán → nahrazen alerting-heartbeat.service.ts + nový freelo.client.ts (dřív shelloval na /root/dev/s60-tools/freelo-agent.sh, který v kontejneru nikdy neexistoval = kanál rok mrtvý); db_change NONE (žádný migrations/ soubor v deltě → „No migrations are pending"); env_change: WRITE OK secrets pulse Libor → FREELO_EMAIL + FREELO_API_KEY (hodnoty od Libora přímo, billit-style inline relay odmítnut jinými agenty) zapsány do /root/secrets/pulse/.env.{hub,prod} (zálohy *.bak-20260725-freelo), creds předem ověřeny read-only proti Freelo API: GET /v1/projects 200, projekt 584175 „S60 - Pulse" ✅, tasklist 1806459 „Bug" dosažitelný a prázdný (potvrzuje mrtvý kanál) → žádné okno s FREELO_NOT_CONFIGURED; VERIFY hub: commit VERIFIED (source hash 41c83e69… local=remote, build hash 639d841b…), labely 1/1, :3100/health 200, QA gate PASS 15/15 (PATCH), /api/version commit=8d29f72 buildTime 10:48:49Z, env v containeru (FREELO_EMAIL ✓, key len 43, FREELO_ESCALATION neprázdný=default ON), boot self-report POZITIVNÍ pro oba kanály: [glitchtip] HUB monitoring aktivní — token ✓, poslední event před 4.7h + [freelo] HUB eskalace aktivní — projekt 584175 dosažitelný, route /api/debug/heartbeat mapped (GET → 403 „Debug mode is disabled" = DebugGuard funguje, endpoint živý; plná odpověď vyžaduje zapnutí debug mode v Admin UI — nedělal jsem); 🔴 ODPOVĚĎ NA PULSŮV „zajímavý bod" (GlitchTip zelený ze špatného důvodu — POTVRZENO, horší než čekali): .env.hub a .env.prod mají identický SENTRY_DSN + GLITCHTIP_API_TOKEN (shodný md5 9195f2ba) → všechna prostředí hlásí do JEDNOHO projektu a v environments_environmentproject je u projektu pulse navázané jediné environment = production ⇒ hub/dev chyby se v GlitchTipu jeví jako produkční; nejnovější „event", o který se heartbeat freshness opírá, je jeho VLASTNÍ alert: GLITCHTIP_API_TOKEN env var chybí — heartbeat nelze provést (443×, last_seen 2026-07-25 06:07Z = ta „4.7h") — tedy dev šum [[reference_pulse_glitchtip_heartbeat]], ne skutečný app event; premisa „DSN rozbité od 2026-04-28" neplatí (reálné app eventy přišly 06-18, 06-19, 06-20, 06-22, 06-29, 07-23 „COMMIT is not valid JSON"), ale staleness check je uspokojitelný vlastním šumem → kandidát na samostatný CR (per-env DSN/projekt + SENTRY_ENVIRONMENT); ⚠️ sentinel-side nález: s60-glitchtip-web je unhealthy s failing streak 301218 (~3 měsíce) — API přitom odpovídá (heartbeat token check prošel) → rozbitý healthcheck, moje domain, k opravě |
✅ | sentinel |
| 2026-07-25 | billit | hub ops (UFW) | cortex-bus na hubu OPRAVEN — hub UFW chyběl 6380 ALLOW IN 172.18.0.0/16 # cortex-redis local containers, který prod-alfa měl (nález při verifikaci deploye 28c5e6b); Liborův explicitní pokyn („oprav ten UFW řádek na hubu"); symptom: billit-api (172.18.0.7 na s60-network) loopoval ioredis connect ETIMEDOUT ~13/min na 100.68.138.14:6380, /var/log/ufw.log [UFW BLOCK] IN=br-c548ab708fc0 SRC=172.18.0.7 DST=100.68.138.14 DPT=6380, outbox_events 691 undispatched od 2026-07-20 15:00 (vše typ heartbeat, attempts=0 → žádné business eventy); pozor na subnet: billit_default je 172.21.0.0/16, ale kontejner žije na s60-network 172.18.0.0/16 (= shodné s prodem, proto prodovský tvar pravidla sedl 1:1); aplikováno ufw allow from 172.18.0.0/16 to any port 6380 (tcp+udp, bez proto — mirror prod tuple); VERIFY: iptables -L ufw-user-input -v -n counter na pravidle matchuje, ufw-not-local drops 0, nsenter … ss -tn → ESTAB 172.18.0.7 → 100.68.138.14:6380 (dřív SYN-SENT), 0× ETIMEDOUT/90 s, outbox_events 0 undispatched z 732 (backlog flushnut, max dispatched_at 10:30:20Z); per-env izolace zachována (hub publikuje do hub cortex-redis, prod bus nedotčen 0/786); ⚠️ latentní díra v deploy-guardu: SSH_WRITE_VERBS nezná ufw → UFW změna přes SSH nevyžaduje WRITE OK ssh hub (autorizace držela jen na Liborově pokynu, ne na hooku) → k opravě |
✅ | sentinel |
| 2026-07-25 | billit | hub + prod | 28c5e6b (CR-069 Flexi stínové účetnictví fáze 1+2 — readback FR-2 (@Cron 15 min Changes API, jediný writer flexibee_*), rekonciliace FR-3/3b (noční 2:00 + ruční run, findings/resolve, /health/deep check flexi_reconciliation), push vydaných FR-4 (faktura-vydana, kod = billit číslo), bugfix DPH sum z expense_lines; billit INFO T-20260725-006; delta 2694192→28c5e6b = 5 commitů (401636e, 3631935, dc5815d, ec438bc, 28c5e6b), 21 souborů +2269/−31, billit-api only (FE beze změny, ale full-stack recreate → labely 2/2 bez selective-recreate false-positive); DEPLOY OK billit hub Libor (release INFO ≠ příkaz → čekal jsem na explicitní OK); migrace 1773260000000-CR069FlexiInvoices = 9× ALTER TABLE invoices ADD COLUMN IF NOT EXISTS (aditivní/idempotentní/reverzibilní, žádná CREATE TABLE/SEQUENCE → netýká se SU-owner pasti [[feedback_su_created_seq_needs_owner]]; fáze 0 CR069FlexiIntegration1773140000000 už applied hub+prod, flexi_sync_state+flexi_reconciliation_findings owner = app user ✅); VERIFY hub: snapshot 20260725-0718-28c5e6b (56M, DB 4.8M), migrace executed successfully + zapsaná v migrations (ověřeno na pg-alfa: 6× flexibee_* + accounting_system/document_id/uploaded_at na invoices), commit VERIFIED (source hash 9a77a187… local=remote), labely 2/2 api+web rev=28c5e6b healthy, :3200/health+:3201/health 200, QA gate PASS 10/10 (PATCH), /health/deep status=ok + commit=28c5e6b (BUILD_COMMIT arg drží, FINDING 2 nevrátila) + nový check flexi_reconciliation=skip "No flexi-enabled tenants" → prod zůstane zelený; modul pasivní: FLEXI_* env nenasazen (hodnoty jen na cerebru /root/.billit-flexi.env, sentinel tam nemá SSH → čeká inline relay) + 0 tenantů s settings.flexi.enabled na hubu i produ; ⚠️ FINDING (pre-existing, hub-only, NEsouvisí s releasem): billit-api na hubu loopuje ioredis connect ETIMEDOUT (~13/min, ss → SYN-SENT na 100.68.138.14:6380 = cortex-bus) → outbox_events 661 undispatched od 2026-07-20 15:00 (všechny typ heartbeat, attempts=0, žádné business eventy); root cause = hub UFW nemá 6380 ALLOW 172.18.0.0/16, které prod má (ufw status diff) → klasický [[feedback_docker_ufw_routed_gotcha]]; prod bus zdravý (0 undispatched z 761, 0× ETIMEDOUT/h); fix čeká na Liborovo UFW schválení; ⚠️ kosmetika: DEPLOY.md migration_from: a804756 ≠ reálně live 2694192 (gate jen vypsal, nezablokoval) → flagnout billitovi; ⏸️ PROD ODLOŽEN ~4 h: DEPLOY OK billit prod přišel v 09:07 UTC, hub deploy z 05:21 UTC → prod gate BLOCKED "hub deploy starší než 2 hodiny (13575s)" = genuine, ne false-positive (ověřeno stamp mtime + /health/deep timestamp), stamp jsem NEtouchoval/neoverridoval; navíc DEPLOY OK billit hub, pak prod nevytvořil token — user-prompt-capture.sh anchoruje celý řádek (^DEPLOY OK <svc> (hub|prod)$), trailing , pak prod regex zabil → deploy-guard správně blokoval PŘED spuštěním (prod beze změny); vyřešeno DEPLOY OK billit hub+prod (dvojitý token) → hub refresh --skip-build (rsync+recreate, QA PASS 10/10, čerstvý stamp 09:33:33Z commit=28c5e6b) → PROD: prod gate QA gate: PASS (09:33:33Z commit=28c5e6b qa=pass tier=PATCH) na čerstvém stampu se shodným commitem (žádné stale-stamp decoupling), snapshot 20260725-1133-28c5e6b (56M, DB 4.8M), oba containery recreated + api Healthy, migrace executed successfully (6× flexibee_* na invoices ověřeno na pg-alfa + CR069FlexiInvoices1773260000000 poslední v migrations), commit VERIFIED (source hash 9a77a187… local=remote, identický s hubem), labely 2/2 rev=28c5e6b healthy, :3200+:3201 health 200, ucto.studio60.cz/health 200 (custom UA, žádný fail2ban re-ban), /health/deep status=ok commit=28c5e6b + flexi_reconciliation=skip → prod zelený, logy čisté (0× ETIMEDOUT, FlexiModule+3 controllery mapped, žádná exception), prod cortex-bus zdravý (0 undispatched z 786) → CR-069 fáze 1+2 LIVE hub+prod, Flexi kolej pasivní (bez env + 0 enabled tenantů)) |
✅ | sentinel |
| 2026-07-23 | pulse | hub + prod | 165c3cc (CR-214 recenze v adminu + CR-215 ochrana zápisu metodik + revert c46b347 fast-path předčasného dokončení; pulse INFO T-20260723-033; delta 9a92a2f→165c3cc = 70fec15 CR-214 (nové endpointy DELETE /api/admin/reviews/:id, GET .../image, POST /api/reviews/media/discard) + 165c3cc CR-215+revert; db_change NONE (158 už applied → typeorm „No migrations pending"), env žádný; DEPLOY OK pulse hub Libor (po mém flagnutí hub-before-prod — Libor dal prod OK první bez hubu → vyžádal jsem hub); Dockerfile repo == hub md5 a614c34e (3 bugy ZMERGOVANÉ: --legacy-peer-deps ×4 + admin-dist/client-dist COPY → KB poznámka stale, rsync bezpečný); VERIFY hub: commit VERIFIED (source hash 886572d… local=remote), QA gate PASS 15/15 (RELEASE tier: pulse-spec-session 12 + webhook 3), /api/version commit=165c3cc, CR-214 endpointy 401 (registered), /app/+/admin/ 200; revert c46b347 = zavírá živou past předčasného [SESSION_COMPLETE] (8/13 metodik); PROD (DEPLOY OK pulse prod Libor, po hub-first flagu; prod gate PASS na čerstvém hub stampu 165c3cc): commit VERIFIED (source+build hash 639d841b… = hub identický), typeorm „No migrations pending" (155–158 už applied, db_change NONE), labely 1/1, pulselab.cz/api/version commit=165c3cc, /app/+/admin/ 200; ⚠️ deploy.sh [3] MISSING AUTH_URL/AUTH_CLIENT_ID/AUTH_CLIENT_SECRET = FALSE-POSITIVE (pulse používá S60_AUTH_* prefix — S60_AUTH_URL/_CLIENT_ID/_CLIENT_SECRET/_CONSENT_API_KEY/_SYSTEM_ID v containeru; readiness check hledá neprefixované názvy → planý, OAuth intaktní, env beze změny); → CR-214+215+revert live hub+prod) |
✅ | sentinel |
| 2026-07-23 | venom | hub + prod | 4c64876 (REQ-031 UI — potvrzení + undo-toast + „Vrátit do fronty / Znovu otevřít"; venom TODO T-20260723-028 nahrazuje T-...007; delta 35c3fdf→4c64876 = 3 commity (9c6c398 spec approved, 016dd71 REQ-031 UI kód, 4c64876 spec implemented); DEPLOY OK venom hub Libor (heads-up „máš nový release" ≠ deploy); --build --skip-ci, čistý FE, žádná migrace/env; VERIFY hub: commit VERIFIED (source hash c9e9281c… local=remote), QA gate PASS (venom 4/4), served bundle index-DNbRSRze.js baked api.s60hub.cz+auth.s60hub.cz only (žádný prod cross-leak), :5174/health 200; BW REQ-030+031 kontrakt (c0eabd9) už na hub+prod → závislost splněna; VERIFY prod (DEPLOY OK venom prod Libor): commit VERIFIED (source hash local=remote), QA gate PASS, labely 1/1, served bundle index-CXzAosji.js (per-env, jiný než hub) baked api.studio60.cz+auth.studio60.cz only (žádný cross-leak), root 200; → REQ-031 chain KOMPLETNÍ na PRODU: BW c0eabd9 backend (wake+reopen) + venom 4c64876 UI (potvrzení+undo+znovuotevřít); BW nasazen před FE = žádné 400) |
✅ | sentinel |
| 2026-07-23 | badwolf | hub + prod | c0eabd9 (REQ-031 — event wake (návrat ze snoozu) + reopen na done; badwolf INFO T-20260723-025 nahrazuje 1b82e72; delta 1b82e72→c0eabd9 = 1 commit code-only feat(tasks) (task.dto.ts + tasks.service.ts, tasks module); žádná migrace (060–071 beze změny, 071 už applied), env beze změny (AUTH_DIRECTORY_); DEPLOY OK badwolf hub Libor (heads-up „máš nový release" ≠ deploy → čekal na explicitní OK); VERIFY hub: commit VERIFIED (source hash 09e19e02… local=remote; ⚠️ build hash e5e5b825… shodný s 1b82e72 = deploy.sh kosmetika, NE no-op — ověřeno jinak), QA gate PASS 4/4 (PATCH), /api/health version=c0eabd9, REQ-031 wake event přítomen v TaskEventDto/CreateTaskEventDto/BulkEventDto v /api-docs-json; PROD (DEPLOY OK badwolf prod Libor): prod gate QA PASS (hub stamp c0eabd9) + deep health PASS, commit VERIFIED* (source hash local=remote), labely 1/1, api.studio60.cz/api/health version=c0eabd9, CreateTaskEventDto obsahuje wake ✅; prod status=degraded = pre-existing emailIngest (nesouvisí)) |
✅ | sentinel |
| 2026-07-23 | venom | hub + prod | 35c3fdf (REQ-030 UI + task UI balík; venom TODO T-20260723-007; delta 7ea7c0e→35c3fdf = 5 commitů: 5f00706 Nový úkol z fronty/úkolů/kanbanu + výběr komu přidělit, 9abc3f8 REQ-030 approved (spec), a38ca7f AC1-4 výsledek úkolu→komunikace (atomicky), a964a13 AC5 agregovaná komunikace u klienta, 35c3fdf REQ-030 implemented; DEPLOY OK venom hub+prod Libor; --build --skip-ci, čistý FE, žádná migrace/env; discarded stale uncommitted DEPLOY.md (bd472fb cruft) před pin checkoutem = hygiena working tree; VERIFY hub: commit VERIFIED (source hash 2b5b5ea9… local=remote), QA gate PASS (venom 4/4 smoke), served bundle index-BdJVLQNJ.js baked api.s60hub.cz+auth.s60hub.cz only; VERIFY prod: prod gate QA PASS (hub stamp 35c3fdf) + deep health PASS, commit VERIFIED, labely 1/1, served bundle index-DqKmY0wJ.js (per-env, jiný než hub) baked api.studio60.cz+auth.studio60.cz only (žádný cross-leak), root 200; → REQ-030 chain KOMPLETNÍ na PRODU: BW 1b82e72 kontrakt (CommunicationAggregatedDto) + venom 35c3fdf UI (BW backend nasazen PŘED venom = kontrakt→FE, žádné 400); pozn.: post-deploy verifikace prod ze sentinelu narazila 2× na fail2ban s60-nginx-badbots re-ban sentinelovy IP (ban z DB re-aplikovaný fail2ban-client reload při ignoreip fixu) → vyřešeno: sentinel 49.13.168.234 přidán do effective ignoreip (jail.local:2, ne stíněný jail.d) + finální unban; ověřeno 5× default curl UA → 200 bez banu = ignoreip drží [[feedback_sentinel_fail2ban_ignoreip]]) |
✅ | sentinel |
| 2026-07-23 | badwolf | hub + prod | 1b82e72 (REQ-030 AC5 — CommunicationAggregatedDto skutečný superset ClientCommunication (email pole pro Venom panel); badwolf INFO T-20260723-006 nahrazuje fabe9b4/7b623ec; delta 4ebf6d4→1b82e72 = 4 commity code-only (75647c6 REQ-030 výsledek úkolu→komunikace + agregace, 7b623ec AC1 text povinný, fabe9b4 AC5 DTO v OpenAPI, 1b82e72 AC5 superset); žádná NOVÁ migrace — 071 user_prefs už na hub+prod applied; env beze změny (AUTH_DIRECTORY_ zachován); DEPLOY OK badwolf hub Libor (heads-up „nový release" ≠ deploy → čekal na explicitní OK); VERIFY hub: commit VERIFIED (source hash 0d87e98c… local=remote match, build hash přítomen), QA gate PASS 4/4 (PATCH tier), /api/health version=1b82e72 status=ok, CommunicationAggregatedDto přítomen v /api-docs-json, /api/user-prefs 401 (route registered za auth); pozn.: [1.5] migration-declaration WARN (migration_from c07d85c != last deployed 4ebf6d4) = kosmetické, žádná migrace reálně nespuštěna ([6.5] skip); npm audit high=10 non-blocking, lint WARN non-blocking; PROD (DEPLOY OK badwolf prod Libor; BW backend jde na prod PŘED venom = správné pořadí kontrakt→FE): prod gate QA PASS (hub stamp commit=1b82e72) + deep health PASS, commit VERIFIED (source+build hash e5e5b825… identické s hub → identický OpenAPI), labely 1/1, s60-badwolf Up healthy, Nest started clean; VERIFY prod public (z hub vantage): api.studio60.cz/api/health version=1b82e72 + CommunicationAggregatedDto v prod /api-docs-json ✅; prod status=degraded = pre-existing emailIngest (stale schránky, NEsouvisí s releasem); ⚠️ INCIDENT (non-prod): po deployi sentinelova egress IP 49.13.168.234 zabanována fail2ban jailem s60-nginx-badbots (curl UA z mých health probů → REJECT → „connection refused" z sentinelu; NE výpadek prod — nginx+badwolf zdravé, poslouchají 443, reální uživatelé neblokováni) → nutný unban + doporučen ignoreip whitelist sentinelu (čeká na WRITE OK ssh prod); venom prod NEnasazen* — čeká na DEPLOY OK venom prod (pár dorovná FE)) |
✅ | sentinel |
| 2026-07-22 | pulse | hub + prod | 9a92a2f (REQ-049 mobile video picker fix — 870d4d7 odstraněn capture="user" → výběr videa z knihovny na mobilu; pulse INFO T-20260722-129; delta d8a4ff8→9a92a2f = fix + DEPLOY.md; žádná NOVÁ migrace (158 už applied z d8a4ff8 → typeorm skip), žádný env; DEPLOY OK pulse hub+prod Libor; VERIFY hub+prod: commit VERIFIED, migrace no-op OK, QA PASS, pulselab.cz + pulse.s60hub.cz /health+/app/ 200) |
✅ | sentinel |
| 2026-07-22 | billit | hub + prod | 2694192 (🔴 HOTFIX JwtTenantGuard 22P02 na platform servisním klíči (REQ-061 regrese — tenant_id=NULL) → Cortex fraud gate 400 na GET expense; billit INFO T-20260722-115; delta e6a7084→2694192 = 8f5dbdf fix + DEPLOY.md; api-only, db_change NONE, žádná migrace/SQL; DEPLOY OK billit hub+prod Libor; VERIFY hub+prod: commit VERIFIED, QA PASS, billit-api recreated + :3200/health 200, ucto.studio60.cz/health 200; label 1/2 = selective-recreate (billit-web nezměněn na e6a7084) — deploy.sh nově „akceptováno" → čistý DEPLOYED (dřívější spurious „health check failed" z dc69754 je opravený)) |
✅ | sentinel |
| 2026-07-22 | pulse | hub + prod | d8a4ff8 (CR-213 recenze samoobsluhou + kreditové sazby + admin proklik (amenduje REQ-049) + force-complete/root-cause fixy; pulse INFO T-20260722-113; delta 30f9b80→d8a4ff8 = 2c7436f CR-213 + DEPLOY.md; migrace 158 ReviewInvitationCredits — typeorm auto přes deploy.sh [6.5] (npm run migration:run, app user); guarded data UPDATE email_templates review-invitation JEN updatedBy IS NULL (needitovaná seed, tenant-scoped) → NEpřepíše editorial změny; žádná schema změna; DEPLOY OK pulse hub+prod Libor; VERIFY hub+prod: commit VERIFIED, migrace 158 v migrations tabulce (prod), :3100/health 200, pulselab.cz + pulse.s60hub.cz /health+/app/+/admin/ 200) |
✅ | sentinel |
| 2026-07-22 | venom | hub + prod | 7ea7c0e (kanban sloupce cross-device + grid auto-fit fix; venom TODO T-20260722-112; delta d5000de→7ea7c0e = 8399484 kanban sloupce cross-device přes BW /api/user-prefs (BW 4ebf6d4) + 7ea7c0e grid auto-fit místo auto-fill (skryté sloupce nezaberou místo); DEPLOY OK venom hub+prod Libor; --build --skip-ci, čistý FE, žádná migrace/env; VERIFY hub+prod: commit VERIFIED, QA PASS, bundle per-env správně (hub index-DY1n4psG=api.s60hub.cz / prod index-BkVRRztg=api.studio60.cz), health 200) |
✅ | sentinel |
| 2026-07-22 | badwolf + venom | hub + prod | 4ebf6d4 + d5000de (user-prefs + kanban plné akce; badwolf 4ebf6d4 /api/user-prefs endpoint + migrace 071 user_prefs (manual-sql — deploy.sh badwolf migrace nespouští; sentinel aplikoval PŘED app na hub+prod: CREATE TABLE IF NOT EXISTS user_prefs PK(user_id,key) JSONB, aditivní/idempotentní; ⚠️ SU→ALTER OWNER na app user hub+prod, INSERT priv ověřeno [[feedback_su_created_seq_needs_owner]]) + venom d5000de kanban=plné akce (TaskCard v dialogu)+volitelné sloupce; DEPLOY OK + PG OK Libor; VERIFY hub+prod: badwolf commit VERIFIED + QA PASS + version=4ebf6d4 + /api/user-prefs 401 (za auth, ne 500 → migrace+owner OK) + AUTH_DIRECTORY zachován (degraded=pre-existing emailIngest), venom bundle per-env správně (hub index-jtwl51Lj / prod index-CF-ByI1n), health 200) |
✅ | sentinel |
| 2026-07-22 | badwolf + venom | hub + prod | a385825 + b350838 (task fronta iterace — pár; badwolf a385825 „moje fronta" scope=mine (převzaté+přiřazené+nepřevzaté mých skupin) + venom b350838 tlačítko „Pustit se do toho" (pickup) ve frontě i detailu; DEPLOY OK badwolf/venom hub+prod Libor; oba +1 commit code-only, žádná migrace/env; VERIFY hub+prod: badwolf commit VERIFIED + QA PASS + version=a385825 + AUTH_DIRECTORY zachován (degraded=pre-existing emailIngest), venom bundle per-env správně (hub index-CULagN3y=api.s60hub.cz / prod index-CKogfcfS=api.studio60.cz), health 200) |
✅ | sentinel |
| 2026-07-22 | billit | hub + prod | e6a7084 (REQ-061/062 platform layer — servisní klíče v adminu + registr ověřených účtů + CR-068 FR-4 completeness; billit INFO T-20260722-094 nahrazuje ccfbe08 T-054; ⚠️ billit psal „LIVE=21edc38" stale — prod reálně na ccfbe08 (migrations tabulka); DEPLOY OK billit hub+prod + PG OK Libor; delta ccfbe08→e6a7084 = 7 commitů; 2 nové migrace (REQ060 už applied → typeorm skip): REQ061PlatformServiceKeys (api_keys.tenant_id DROP NOT NULL + partial idx) + REQ062VerifiedAccounts (CREATE TABLE verified_accounts + seq + unique idx); FE+BE rebuild; VERIFY hub+prod: obě migrace executed, verified_accounts+seq owner=app user (typeorm CLI, žádný SU owner problém [[feedback_su_created_seq_needs_owner]]), tenant_id nullable, commit VERIFIED, label 2/2, health 200; req061-platform-keys.sql (PG OK, :5432 txn ON_ERROR_STOP): pg_dump api_keys pre-req061 → UPDATE 2 (cortex-banking-parity-REQ043 + cortex-write → tenant_id=NULL, platform-scoped DEC-018, hodnota/scopes/IP nezměněny → cs nepřegeneruje) → idempotence 0; dedup cleanup = už proběhl u ccfbe08 (0 v deltě)) |
✅ | sentinel |
| 2026-07-22 | venom | hub + prod | 700c7d3 (MyQueue „Rozpracované (držíte)" + assignable-members comba; venom TODO T-20260722-092; delta 23b37e8→700c7d3 = bd329b8 napojit comba na assignable-members (REQ-052 UI wiring) + 700c7d3 MyQueue převzaté tasky; DEPLOY OK venom hub+prod Libor; --build --skip-ci, čistý FE, žádná migrace/env; VERIFY hub+prod: commit VERIFIED, QA PASS, bundle per-env správně (hub index-4Bxar9GP=api.s60hub.cz / prod index-F70BnXuQ=api.studio60.cz), health 200; → pár s BW 36ece72 kompletní → kanban in_progress + převzaté tasky funkční na prod) |
✅ | sentinel |
| 2026-07-22 | badwolf | hub + prod | 36ece72 (PROD HOTFIX fix(auth): actor.id z user.id (JWT sub) — kanban in_progress na produ nefungoval (Libor test); badwolf URGENT T-20260722-089; delta 3809097→36ece72 = 1 commit code-only (actor.util + handoffs/task-suggestions/email-templates controllery, 162 testů), žádná migrace/env; DEPLOY OK badwolf hub+prod Libor; VERIFY hub+prod: commit VERIFIED (build hash), QA PASS, version=36ece72, AUTH_DIRECTORY env zachován (re-sync); prod status=degraded = pre-existing emailIngest, neblokuje) |
✅ | sentinel |
| 2026-07-22 | badwolf | prod | ops (env) — AUTH_DIRECTORY key install (REQ-052 aktivace) (badwolf T-20260722-074; WRITE OK secrets badwolf + DEPLOY OK badwolf prod Libor; AUTH_DIRECTORY_URL=https://auth.studio60.cz + AUTH_DIRECTORY_API_KEY (directory:read, od Libora) do secrets/badwolf/.env.prod; deploy.sh badwolf prod --skip-build recreate 3809097; 3. var AUTH_DIRECTORY_VENOM_CLIENT_ID má default s60-s60-venom-0958966f = volitelný; VERIFY: env v kontejneru, /tasks/assignable-members 401 (ne degraded/500), log AuthDirectoryModule initialized bez degraded warnu → REQ-052 END-TO-END live: auth directory 54e326e ← badwolf proxy 3809097+key ← venom 23b37e8; ⚠️ jen prod — hub bez klíče gracefully degraded (chce hub-scoped directory:read klíč) |
✅ | sentinel |
| 2026-07-22 | venom | hub + prod | 23b37e8 (task UI — kanban in_progress + forward pravidla, FE k BadWolf 3809097 task endpointům; venom TODO T-20260722-062; DEPLOY OK venom hub+prod Libor; --build --skip-ci, db_change none, žádná migrace/env; VERIFY hub+prod: commit VERIFIED, QA PASS, bundle per-env správně (hub index-DPDZn5mP=api.s60hub.cz / prod index-BXPbcjuI=api.studio60.cz), health 200; → REQ-052 řetězec kompletní: auth directory 54e326e + badwolf proxy 3809097 + venom UI 23b37e8) |
✅ | sentinel |
| 2026-07-22 | badwolf | hub + prod | 3809097 (REQ-052 assignable-members proxy + task fixy; badwolf INFO T-20260722-061; delta a378697→3809097 = 5 commitů code-only: c4655b8 GET /tasks/assignable-members proxy na S60Auth directory (REQ-052, propojení na auth 54e326e) + 7b3f829 fix findOne derived_column pickup→in_progress (Venom bug) + 6912d0c forward-preview + 3809097 AUTH_DIRECTORY_URL tolerantní; DEPLOY OK badwolf hub+prod Libor; žádná migrace; env AUTH_DIRECTORY_* = Libor do BW env, deploy safe i bez něj; VERIFY hub+prod: commit VERIFIED (build hash), QA PASS, health 200, version=3809097, /tasks/assignable-members 401 (proxy live za auth); prod status=degraded = pre-existing emailIngest, neblokuje) |
✅ | sentinel |
| 2026-07-22 | billit | hub + prod | ccfbe08 (banking dedup fix + REQ-060 předkontace + DEDUP CLEANUP SQL; billit INFO T-20260722-054 supersedes 650ac9e; DEPLOY OK billit hub+prod + PG OK Libor; delta 21edc38→ccfbe08 = inbound doména→in.studio60.cz + cross-channel dedup fix (findFuzzyMatch) + REQ-060 předkontace položek výpisu; migrace 1773230000000-REQ060StatementCoding = ALTER bank_transactions ADD 8 sloupců (accounting_status NOT NULL DEFAULT 'uncoded' + 7 nullable) + 2 idx (tenant_id,…), aditivní/idempotentní IF NOT EXISTS/reverzibilní; FE+BE rebuild; VERIFY hub+prod: migrace executed, 8 sloupců applied hub+prod, commit VERIFIED, QA PASS, label 2/2 (bez selective-recreate false-positive — oba containery změněny), ucto.studio60.cz + billit-api:3200 /health 200; DEDUP CLEANUP (2026-07-22-dedup-email-fio-merge.sql, :5432 direct, ON_ERROR_STOP=1, vlastní txn): pg_dump backup pre-cleanup pg-alfa 89KB → read-only count 72 skupin/30 matched (dle očekávání) → UPDATE 30 invoice_payments email→fio + UPDATE 30 fio→matched + DELETE 72 email dup → COMMIT → idempotence 0 zbývajících ✅; fio kanonický, faktury neodpojeny; cs notifikován (T-063) na statement backfill) |
✅ | sentinel |
| 2026-07-22 | s60-auth | hub + prod | 54e326e (REQ-052 directory endpoint — přiřaditelní členové systému, M2M pro BadWolf task assignment; auth INFO T-20260722-037; delta 686e879→54e326e = 0a7dca4 nový modul directory/ + scopes + guard; backend-only, žádná migrace/env; aktivace = superadmin vydá directory:read API klíč BadWolfu (ne sentinel); VERIFY hub+prod: commit VERIFIED, QA PASS, openid 200, TURNSTILE_ENABLED=true + TRUST_PROXY_HOPS=1 zachovány, čistý container) |
✅ | sentinel |
| 2026-07-22 | s60-auth | hub + prod | 686e879 (🔒 TURNSTILE ZAPNUT + REQ-051; auth INFO T-20260722-003; delta fd36ecf→686e879 = acd2433 REQ-049 L2 FE bake (frontend/.env.production s VEŘEJNÝM VITE_TURNSTILE_SITE_KEY, varianta B) + ac317fa REQ-051 IP/UA do zbylých audit eventů; žádná migrace; sentinel zapsal TURNSTILE_ENABLED=true+TURNSTILE_SECRET do secrets/auth/.env.{hub,prod} (WRITE OK secrets auth; site key↔secret pár od Libora, site key EXACT match); koordinovaně FE+BE spolu (jinak widget nerenderuje→400 na všech reg); VERIFY hub PAK prod: TURNSTILE_ENABLED=true v kontejneru, FE bundle baked site key, TRUST_PROXY_HOPS=1 zachován, openid 200; EMPIRICKÝ ENFORCEMENT PROOF hub+prod: register bez tokenu → HTTP 400 turnstile_failed = boti blokováni; bonus: hash-prefixed container b0c3454b909e_* z fd36ecf docker race uklizen (čistý /s60-auth-backend)) |
✅ | sentinel |
| 2026-07-21 | s60-auth | hub + prod | fd36ecf (23dad3d fix(frontend): geoApi import — crash v Audit tabu + obnovený tsc typecheck; auth INFO T-20260721-057; delta eafe8ff→fd36ecf = čistý FE fix, žádná migrace/env; TRUST_PROXY_HOPS=1 zachován; VERIFY: commit VERIFIED, QA PASS, openid 200, nový FE bundle; ⚠️ prod recreate narazil na docker race → dočasně hash-prefixed container b0c3454b909e_s60-auth-backend (healthy, real IP OK; uklizeno až deployem 686e879) — [[feedback_deploy_docker_race]]) |
✅ | sentinel |
| 2026-07-21 | pulse | hub + prod | 30f9b80 (c46b347 fix předčasné [SESSION_COMPLETE] — forward jump místo tichého hangu + DEPLOY.md chore; pulse origin/master +2 nad 793ac8e; DEPLOY OK pulse hub+prod Libor; db_change NONE, žádná migrace/env; VERIFY hub+prod: commit VERIFIED (source hash match), QA gate PASS, :3100/health 200, pulselab.cz + pulse.s60hub.cz /health+/app/+/admin/ 200) |
✅ | sentinel |
| 2026-07-21 | billit | hub + prod | dc69754 (fix(billit): GET /v1/accounts cross-tenant klíč → Cortex UUID→slug mapa; billit origin/master +1 nad 21edc38; DEPLOY OK billit hub+prod Libor; api-only, žádná migrace/env; VERIFY: hub QA 10/10 PASS, billit-api commit dc69754 VERIFIED (source hash match) + recreated 19:48 + :3200/health 200, ucto.studio60.cz/health 200 + /api/v1/accounts 401 (nový endpoint live za auth); ⚠️ prod label check FAIL 1/2 = známý selective-recreate false-positive — billit-web=f69936c nezměněn (dc69754 api-only) → "DEPLOYED (health check failed)" je spurious, api reálně zdravé+aktuální; billit.cz=301→ucto.studio60.cz DEC-014 rebrand; řeší i předchozí 21edc38 fail flag) |
✅ | sentinel |
| 2026-07-21 | s60-auth | hub + prod | eafe8ff (REQ-050 dodatek — čitelnost globálního audit logu; auth INFO T-20260721-052; delta 4fcc13a→eafe8ff = 242a768 feat + DEPLOY.md chore; žádná migrace/env, neutrální flagy off; TRUST_PROXY_HOPS=1 zachován; VERIFY hub+prod: commit VERIFIED, QA PASS, openid 200; real IP potvrzen z ORGANICKÉHO provozu — audit_log auth.login ip=46.135.85.219 / 185.51.251.239 / login_google 150.228.35.49 = reálné client IP místo ::ffff:172.18.0.1) |
✅ | sentinel |
| 2026-07-21 | venom | hub + prod | 2e19e6f (nahrazuje 2c150a1 — venom TODO T-20260721-053; feat(tasks): +libor.webster@gmail.com do TASK_ADMIN_EMAILS → Libor task-admin přístup k rules activation UI; DEPLOY OK venom hub+prod Libor; --build --skip-ci, žádná migrace/env; VERIFY: commit VERIFIED, QA PASS, bundle per-env správně (hub index-M6fDpATA=api.s60hub.cz / prod index-EcHNio2e=api.studio60.cz), health 200) |
✅ | sentinel |
| 2026-07-21 | venom | hub + prod | 2c150a1 (REQ-027 E — aktivační obrazovka pravidel = FE k badwolf a378697 toggle endpointu; venom origin/main +2: 30a7621 REQ-027 E + 2c150a1 config chore be.→api. v .env.example/deploy.yml; DEPLOY OK venom hub+prod Libor; --build --skip-ci self-contained build na cíli; žádná migrace/env; VERIFY hub+prod: commit VERIFIED (source hash 978ee51 match), QA gate PASS, served bundle baked API URL správně per-env (hub index-3JStJDKz = api.s60hub.cz / prod index-Dc5B-ipo = api.studio60.cz, žádný cross-leak), health 200; → rules toggle chain kompletní — badwolf endpoint + venom UI oba live, aktivace pravidel na Liborovi) |
✅ | sentinel |
| 2026-07-21 | s60-auth | hub + prod | 4fcc13a (REQ-049 A+B+C + REQ-050 + TRUST_PROXY_HOPS=1 → reálná client IP v auditu; auth TODO T-20260721-049, DEPLOY OK auth hub+prod Libor; delta 15ffa38→4fcc13a = 00dd547 REQ-050 rozšířená audit stopa (registered_ip/ua, last_login_at/ip/ua na users) + DEPLOY.md; migrace 1752200000000-UserAuditTrail = 5× ADD COLUMN IF NOT EXISTS nullable (aditivní/idempotentní/reverzibilní), migration_from 48e60de=předek 15ffa38, db_change:minor; + TRUST_PROXY_HOPS=1 do secrets/auth/.env.{hub,prod} (WRITE OK secrets auth) — 1 nginx hop (prod ne za CF, spoofing-safe: nginx přidává $remote_addr jako pravý XFF); VERIFY hub+prod: commit VERIFIED, QA gate PASS (auth-e2e-login 20/20 + error-format 6/6), 5 sloupců applied, TRUST_PROXY_HOPS=1 v containeru, openid 200; EMPIRICKÝ PROOF: test-login → audit_log.auth.login_failed ip_address=49.13.168.234 (sentinel egress) místo ::ffff:172.18.0.1 → real-IP capture LIVE; kontext: reakce na Tor spam registraci do Pulse/auth, dc-block Tor block nasazen paralelně) |
✅ | sentinel |
| 2026-07-21 | badwolf | hub + prod | a378697 (REQ-026 toggle pravidel endpoint pro Venom; badwolf T-20260721-038, DEPLOY OK badwolf hub+prod Libor; delta dc62671→a378697 = 3 commity code-only: e48224f POST /tasks/rules/:code/activate\|deactivate toggle z Venomu + 7e82385 DTO shape fix (TaskRuleDto, DEC-002) + a378697 docs; žádné migrace/env; VERIFY hub+prod: commit VERIFIED (source hash b7eab06 match, build hash přítomen = reálný build, ne no-op), health 200, /api/health version=a378697, hub QA gate 4/4 PASS; pravidla zůstávají na prod VYPNUTÁ — aktivaci udělá Libor z Venomu (nový endpoint), deploy sám nic nespustí; pozn.: prod health.status=degraded = pre-existing emailIngest (5 schránek neingestlo >24h, NEsouvisí s releasem; deploy QA gate qa-gate.sh:103 kontroluje jen HTTP 200, ne body.status); hub-freshness dance: 1. prod pokus BLOCKED (hub stamp 2,6h > 2h limit — Libor pauza mezi hub↔prod) → hub refresh --skip-build (čerstvý stamp) → prod OK) |
✅ | sentinel |
| 2026-07-21 | Resend keys | mail hub+prod · n8n hub+prod · vaultwarden prod · reporting | ROTACE Resend API klíčů (Libor rotoval sdílený re_XSxhvi… → 4 dedikované per-service klíče; WRITE OK secrets mail/n8n/vaultwarden/monitoring + DEPLOY OK per env; secrets: mail re_aF7r (secrets/mail/.env.{prod,hub} RESEND_API_KEY; admin re_Mfqv8t NErotovaný nedotčen), n8n re_etxq (N8N_SMTP_PASS .env.{prod,hub}), vaultwarden re_H9dJ (SMTP_PASSWORD .env.prod), reporting re_5oGo (nový secrets/monitoring/reporting.env, attack-report.py přepnut z mail/.env.prod → oddělen od mail služby); propagace deploy.sh --skip-build (scp secret→/opt + force-recreate, bez pull → verze se nemění): mail hub 36a41f6+prod, n8n hub+prod (N8N_ENCRYPTION_KEY match ověřen před každým env, secret=nadmnožina /opt), vaultwarden prod (single-env, ADMIN_TOKEN intact); VERIFY: 4 klíče 422-probe PLATNÉ + starý 401 mrtvý; kontejnery recreated s novým klíčem (docker inspect maskovaně); health 200 (mail :3010, n8n :5678/healthz, pass.studio60.cz/alive); reporting reálný test-mail ODESLÁN (id); fix pipeline: n8n DEPLOY.md doplněn (non-git gate REJECT), capture allowlist +vaultwarden (byl silently ignorován jako neznámá služba), n8n manual qa-pass stamp (no-QA-config služba = designed manual override pro prod)) |
✅ | sentinel |
| 2026-07-16 | BadWolf | hub + prod | b42b1fa (CATCH-UP APP DEPLOY — span c07d85c→HEAD; badwolf TODO T-20260716-020, DEPLOY OK badwolf hub+prod Libor; = cc4a98a search fix + DEPLOY.md; obsah: REQ-022 settings store (/api/internal/settings), REQ-024 application_number (API+search), REQ-025 email link (PATCH /clients/:id/communications/:commId/application, timeline vrací přiřazené emaily) + CS proxy, REQ-021 sendAccessEmail, search digit-pollution fix (606→1) — looksLikePhone (phone-match jen tokeny bez písmen/@, ≥4 číslic) → odblokuje Ivanu ve Venom searchi; DRIFT vysvětlen: prod app uvázl na c07d85c protože Libor 16.7. ZÁMĚRNĚ parkoval afb104f/REQ-025 (venom users aktivní) — ne rollback/failed deploy; db_change: migration/manual_sql (053+059 aplikovány předem SQL-only, migration_from c07d85c = last deployed → cross-check OK, [6.5] skip); VERIFY hub+prod: CI test OK, commit VERIFIED (source hash c19a33d… match), health version=b42b1fa (public api.s60hub.cz + api.studio60.cz), QA gate PASS 4/4; worker: prod má REDIS_BUS_URL+CS_API → email-ingest aktivní, hub bez → clean boot; hub 11:10 → prod 11:17 (gate <2h); E2E (settings 200, search exact, app_number, timeline emaily) = badwolf/venom authenticated) |
✅ | sentinel |
| 2026-07-16 | BadWolf | hub + prod | SQL-only b42b1fa — migrace 053+059 (catch-up prep) (badwolf TODO T-20260716-020, Liborovo ok + backup první; ŽÁDNÝ DEPLOY [DB část], jen manuální SQL PŘED app; 053 internal_settings (REQ-022 KV settings store + seed venom dashboard barvy): na HUB i PROD už existovala (owner=app_user) → CREATE IF NOT EXISTS skipped, seed ON CONFLICT no-op — badwolf RO check „053 CHYBÍ na prod" byl stale; ALTER OWNER pro jistotu spuštěn (no-op); 059 client_communications.application_id (REQ-025, additivní): ADD COLUMN + partial index + konzervativní backfill „jediná přihláška v okně" (HAVING count=1), bez ALTER OWNER (kolona/index dědí owner); backfill: HUB UPDATE 0 (0 řádků), PROD UPDATE 954 (z 2898 cortex emailů); combined stream ON_ERROR_STOP, backup pg_dump client_communications -Fc na pg-alfa /var/lib/postgresql/backups/badwolf-053-059/; VERIFY hub+prod: internal_settings owner=app_user + privs true, application_id kolona ANO, seed key present; ⚠️ ENV: hub secrets nemají REDIS_BUS_URL+CS_API_* (worker aktivní jen prod) → b42b1fa na hubu nabootuje čistě bez email workeru (ne blocker); app deploy b42b1fa čeká na DEPLOY OK) |
✅ | sentinel |
| 2026-07-16 | BadWolf sync | hub + prod | APPLIER RUN — propagace 9 klientů + kaskáda po resetu (navazuje na sync reset T-012; badwolf TODO T-20260716-014, Liborovo „spusť applier"; žádný deploy — manuální off-cycle běh sentinel applieru jenkins-sync/applier.ts --env={hub,prod} (jinak cron :20 prod / :25 hub hourly); DEV applier (badwolf, cerebro) přidělil na dev → status_dev=applied, hub/prod=pending → sentinel dotlačil na hub+prod; hub: pass 1 upsert 9 klientů, kaskáda deferred na FK ordering (task order není závislostně seřazený → adresy defnou), pass 4 po ~3min backoffu upsert 7 (2 addresses, 2 applications, 2 attachments, 1 communication); prod: pass 1 upsert 9, pass 2 (background sleep do backoff expiry 05:57:28Z) upsert 7; VERIFY hub+prod: Ivana ivanadvorakova.15@seznam.cz=1, app 8144/invoiced + 8146/proforma, dev outbox 17 entit status_prod=applied; deferred nedotčeno: enrollments 26898/26899 (stale online_course UUID, samostatný problém); NÁLEZ: klient 26925 = 10. uvázlý MIMO reset (created_at null, hash≠null → nerozjede se sám, applier ho defne) → flagnuto badwolfovi T-015/T-017 na doplnění resetu) |
✅ | sentinel |
| 2026-07-16 | BadWolf sync | dev (SRC) | SQL RESET — uvázlé sync tasky po CR-009 created_at bugu (badwolf TODO T-20260716-012, Liborovo PG OK napřímo, varianta (b) atomicita; ŽÁDNÝ DEPLOY — detektor fix 53bb0ce běží živě na Cerebru, jen ruční reset stavu 9 už-uvázlých klientů; root cause: CR-009 přidal projectClients created_at, ale detektor SELECT na Jenkins users.created nebral → created_at:null → clients NOT NULL violation (23502) → 10× defer → needs_review; blokovalo KAŽDÉHO nového klienta z Jenkinse od ~14.7. (Ivana 26914 / přihláška 8144 — Libor nahlásil); DB: s60_badwolf_dev (SRC, vyřešeno empiricky — badwolf nepojmenoval); reset (atomicky BEGIN/COMMIT, ON_ERROR_STOP): UPDATE 9 sync_state jenkins_source_hash=NULL (9 explicit jenkins_id) + DELETE 9 sync_outbox stuck clients + UPDATE 7 kaskáda→pending (apps/addresses/attachments/comms FK-blocked; enrollmenty vynechány); backup pg_dump sync_outbox(139021)+sync_state(131670) -Fc na pg-alfa /var/lib/postgresql/backups/badwolf-sync-reset/; verify okamžitý: 9/9 source_hash NULL, 0 stuck outbox, kaskáda pending; koncový stav (prod naskočení Ivana/8144) po 2-3 sync-tickcích — badwolf hlídá; flock: detektor NEpauzován (sentinel nemá SSH na cerebro), spoléháno na atomicitu jednoho commitu) |
✅ | sentinel |
| 2026-07-16 | BadWolf | hub + prod | SQL HOTFIX — ALTER SEQUENCE applications_number_seq OWNER (PROD OUTAGE fix; badwolf URGENT T-20260716-004, Liborovo PG OK napřímo; ŽÁDNÝ DEPLOY/MIGRACE, 2 řádky SQL bez restartu/backupu; root cause: migrace 055 (REQ-024) vytvořila applications_number_seq jako SU → owned by postgres, app user neměl USAGE; sloupec má DEFAULT nextval(...) + entita insert:false → Venom POST /api/applications spustil nextval → permission denied for sequence → 500 (Jenkins sync jel — posílá číslo explicitně, nextval se nespustí); potvrzeno RO před fixem: applications_number_seq owner=postgres USAGE=false vs orders_order_number_seq (mig 038) owner=app_user USAGE=true; fix: ALTER SEQUENCE … OWNER TO s60_badwolf_{hub,prod}_user; VERIFY hub+prod: owner=app_user, has_sequence_privilege(…,'USAGE')=true, prod last_value=10031 (další nextval=10032); lekce: SU-created CREATE SEQUENCE potřebuje ALTER OWNER stejně jako CREATE TABLE — 055 DEPLOY.md „bez ALTER OWNER" bylo mylné) |
✅ | sentinel |
| 2026-07-16 | S60Venom | hub + prod | 0eb0a7e (RE-DEPLOY — REQ-021 B checkbox „poslat e-mail s přístupy"; venom INFO T-20260714-099, DEPLOY OK venom hub+prod Libor; oprava: předchozí deploy (T-074) nasadil e50c73e = 0eb0a7e~1 (o commit zpět, build z checkoutu před fetch) → chyběl ClientOnlineCoursesPanel.tsx checkbox; fix = pin --commit 0eb0a7e (deploy.sh checkoutne přesně ten commit); clean FE, db_change: none, žádné deps; BW dependency sendAccessEmail live z badwolf c07d85c → checkbox funkční; prod gate: hub stamp 0eb0a7e byl ~38h starý (deploy 07-14) → prod BLOCKED (<2h limit) → hub refresh identického obsahu (DEPLOY OK venom hub 2×) → stamp fresh → prod; VERIFY hub+prod: commit VERIFIED (source hash 0a237cc… match), served bundle per-env baked API URL (hub api.s60hub.cz / prod api.studio60.cz, žádný leak), 0eb0a7e obsah („přístupov…") v bundlu, QA gate PASS; BONUS finding (ne blocker, předáno venom T-102): bundle 2.32 MB vs local ~1.7 MB — NODE_ENV=development v Dockerfile (ř.13) se neresetuje před npm run build (ř.30) → vite dev-mode → dev buildy knihoven; fix na venom straně) |
✅ | sentinel |
| 2026-07-14 | BadWolf | hub + prod | c07d85c (APP DEPLOY — REQ-021 sendAccessEmail + CR-009 test fix + FLIP; badwolf TODO T-20260714-078 → retarget T-085, DEPLOY OK badwolf hub+prod + flip OK Libor; kód = 2cf7dec (test fix) + ea96223 (058); REQ-021: sendAccessEmail v CreateEnrollmentDto (Venom checkbox u ručního přidělení → access mail, notifyManualEnrollment, idempotentní stamp); test fix 2cf7dec (řeší CI block bbaed2d, sentinel nález): invariant projekce == allow-list ∪ {created_at} — created_at zdokumentován jako immutable Jenkins metadata mimo hash (volba (b), (a) by spustila re-hash vlnu); db_change: migration/manual_sql (056+057+058 aplikovány předem SQL-only, migration_from de28964 = last deployed → cross-check OK, [6.5] skip); ⚠️ ENV FLIP ENROLLMENT_NOTIFY_ENABLED=true na hub+prod (WRITE OK secrets badwolf, do /root/secrets/badwolf/.env.{hub,prod} + backup, aktivováno env-syncem [5/8] při deployi) — od teď reálné access maily zákazníkům (auto po Moodle push order + manuál checkbox); BLOCKED-then-fixed: 1. pokus bbaed2d padl na Pre-build CI (test project.spec.ts created_at ∉ ALLOW_LISTS.clients) → NEobejito --skip-ci, TODO badwolf T-084 → retarget; VERIFY hub+prod: Pre-build CI test OK (136/136), commit VERIFIED (source hash 714dd53a… match), health version=c07d85c (vč. public api.studio60.cz), QA gate PASS 4/4, flip =true v containeru i /opt/.env; hub 07:40 → prod 07:48 (gate <2h OK)) |
✅ | sentinel |
| 2026-07-14 | BadWolf | hub + prod | SQL-only c07d85c / ea96223 (migrace 058 — CR-009 korekce sloučených klientů; ŽÁDNÝ DEPLOY, jen manuální SQL, bez app restartu; badwolf INFO T-20260714-085, Liborovo ok + backup první; řeší sentinel dup-uuid nález z 057 — sloučení klienti (identity resolution, víc Jenkins users → 1 BW klient) měli v 057 exportu duplicitní uuid → vyhrála poslední hodnota v souboru (nedeterministické); 058 = UPDATE clients created_at = min(created) (nejstarší registrace), unikátní VALUES; jen UPDATE clients, žádný DELETE/DROP/ALTER, 1× BEGIN/COMMIT, ON_ERROR_STOP=1, STRIKTNĚ idempotentní; backup před oběma (pg_dump clients -Fc + CSV id,created_at) na pg-alfa /var/lib/postgresql/backups/badwolf-058/; HUB+PROD: RUN1 UPDATE 1664, RUN2 (idempotence) UPDATE 0 ✅ (žádný flip-flop na rozdíl od 057), rows 23644/23645 beze změny, 0 NULL, year dist posun k dřívějším letům; badwolf potvrdil „poslední v souboru" nebyla zamýšlená sémantika — nález uzavřen; app deploy c07d85c + flip čeká na DEPLOY OK) |
✅ | sentinel |
| 2026-07-14 | BadWolf | hub + prod | SQL-only bwtip bbaed2d (migrace 057 — CR-009 created_at backfill; ŽÁDNÝ DEPLOY [DB část T-078], jen manuální SQL, bez app restartu; badwolf TODO T-20260714-078, Liborovo ok + backup první; řeší Liborův „gap 29.6→6.7" — created_at byl klon/apply-time artefakt (vše 2026-06-29), backfill SKUTEČNÝCH dat vzniku z Jenkinse (rubicon export 14.7.) přes UPDATE created_at dle uuid párů; jen UPDATE, žádný DELETE/DROP/ALTER, 9 chunků BEGIN/COMMIT po ~5000, ON_ERROR_STOP=1, idempotentní (IS DISTINCT FROM), BW-native netknuté, mimo hash allow-listy; backup před oběma (pg_dump applications+orders+clients -Fc + CSV id,created_at) na pg-alfa /var/lib/postgresql/backups/badwolf-057/; VERIFY hub+prod (0 NULL, počty = row count): applications 2018–2026 (7229/7230), orders 2019–2026 (4315/4340), clients 2016–2026 (23644/23645); NÁLEZ (ne blocker, data ověřeně správná): export má 2230 duplicitních uuid → ~810 clients updatlo ve 2 chuncích (accounting součet 24454 > row count), finální hodnota = poslední chunk, strict re-run≠0 → flagnuto badwolfovi (T-083) na dedup zdroje; app deploy bbaed2d + flip ENROLLMENT_NOTIFY_ENABLED čeká na DEPLOY OK) |
✅ | sentinel |
| 2026-07-14 | BadWolf | hub + prod | SQL-only 502ecce (migrace 056 — oprava application_number po 055; ŽÁDNÝ DEPLOY, jen manuální SQL, bez app restartu/env; badwolf TODO T-20260714-065, Liborovo ok + backup první; root cause: 055 číslovala dle LOKÁLNÍ migration_id_mappings, na hub/prod je to stale baseline z klonu 29.6. → 35 přihlášek synced po klonu dostalo 10000+ místo Jenkins 8107–8142; 056 = cílený UPDATE applications dle 35 explicitních uuid→jenkins_id párů + setval; idempotentní (IS DISTINCT FROM guard), atomický BEGIN/COMMIT, ON_ERROR_STOP=1, piped z gitu; backup před oběma (pg_dump applications -Fc + CSV id,application_number) na pg-alfa /var/lib/postgresql/backups/badwolf-056/; HUB: UPDATE 35, setval 9999, verify ge10000=0 / 8107–8142=35 / 8110 chybí / 0 NULL / max 8142; PROD: UPDATE 35, setval 10031, verify ge10000=1 (jen 766aa9b3…=10031 libor native, NETKNUTÝ) / 8107–8142=35 / 8110 chybí / 0 NULL / max 10031; přesně dle badwolf očekávání) |
✅ | sentinel |
| 2026-07-14 | S60Venom | hub + prod | 8239135 (REQ-024 lidská čísla přihlášek — #8142 místo #uuid: první sloupec v seznamu + detail + popovery + storno + CSV, fallback uuid prefix dokud BW migrace 055 není live; venom INFO T-20260714-051, DEPLOY OK venom hub+prod Libor, FE-only clean forward nad 1e37120, žádné deps/migrace; BW dependency splněna — badwolf de28964 (migrace 055 application_number, 7193 jenkins + 36 BW-native) live PŘED venom → zobrazuje reálná čísla ne fallback; hub bundle index-DIUt_CNe.js, prod index-B8E86eq1.js, per-env API + DSN ověřeno) |
✅ | sentinel |
| 2026-07-14 | BadWolf | hub + prod | de28964 (=e5a48e9 REQ-024 + DEPLOY.md bump; REQ-024 application_number — lidské číslo přihlášky (DEC-002 vzor): applicationNumber v API + filtr ?number= + fulltext číselný token + sync applier posílá jenkins_id; badwolf TODO T-20260714-039, DEPLOY OK badwolf hub+prod Libor; db_change: migrace 055 manual_sql (hub i prod přes pg-alfa SU PŘED app, plný pg_dump backup applications /var/lib/postgresql/badwolf-mig055-{hub,prod}-<TS>/, ON_ERROR_STOP) — ADD COLUMN application_number + applications_number_seq START 10000 + DATA BACKFILL: jenkins přihlášky ← původní jenkins_id z migration_id_mappings (coverage 7193/7229), BW-native (~36) dočíslování od 10000 dle created_at + setval + UNIQUE partial index + DEFAULT nextval; idempotentní (WHERE NULL / IF NOT EXISTS), bez ALTER OWNER (app-owned), mimo sync hash (žádná re-hash vlna); jenkins max 8106 < BW-native 10000 → žádná kolize; verify hub+prod: NULL count 0, duplicity 0, jenkins 7193 (43–8106) + BW-native 35/36 (10000–10034/35), total 7229; clean forward nad live 721a788; app VERIFIED health 200 version=de28964, QA hub 4/4; env/flagy beze změny, email-ingest worker běží dál (REDIS_BUS_URL zachovaný, 0 ETIMEDOUT)) |
✅ | sentinel |
| 2026-07-14 | BadWolf | hub + prod | 721a788 (=a8e71b6 REQ-023 matching bugfix + DEPLOY.md bump; email-ingest matching fix — RFC adresy „Jméno \<email>" se nematchovaly → backfill skipnul 756 mailů od 314 reálných klientů (sentinel match-rate 25 % postřeh → badwolf našel root cause: extrakce adresy z <> před matchem v email-ingest.service.ts); badwolf TODO T-20260714-025, DEPLOY OK badwolf hub+prod Libor; db_change none, žádná migrace, žádná env (app-only); deploy tip 721a788 (ne a8e71b6 — ten měl stale DEPLOY.md Current=aa48acf; 721a788 = docs-only bump s Current=a8e71b6/db_change:none); clean forward nad live 5027a87; hub QA 4/4, prod VERIFIED health 200 version=721a788; worker po recreate běží dál (REDIS_BUS_URL zachovaný v containeru, žádné ETIMEDOUT); NEXT: cs replay (reset crm_pushed_at + full replay 8391, idempotentní přes external_ref → 2130 existujících dedupe, ~756 nových insert → cíl source=cortex ~2886)) |
✅ | sentinel |
| 2026-07-13 | BadWolf | hub + prod | 5027a87 (=aa48acf REQ-023 v1 + 5027a87 DEPLOY.md fix; REQ-023 v1 email ingest — BullMQ konzument fronty cs-to-badwolf na cortex-redis (dedikovaný Redis co jsem nasadil) + CS content proxy + PATCH /communications; badwolf TODO T-20260713-081, DEPLOY OK badwolf hub+prod Libor; db_change: migrace 054 manual_sql (hub i prod přes pg-alfa SU PŘED app, backup /var/lib/postgresql/badwolf-mig054-{hub,prod}-<TS>/, ON_ERROR_STOP) — client_communications +6 sloupců (source/direction/occurred_at/account/external_ref/thread_ref) + uq_client_comm_external_ref (idempotence ingestu) + idx_client_comm_thread, additivní, BEZ ALTER OWNER (tabulka app-owned); DEPLOY BLOCK zachycen: badwolf DEPLOY.md byla stale (Current d791823/db_change: none, ale target má migraci 054) → deploy.sh REJECT (migration declaration check funguje), TODO badwolf T-090 → badwolf pushnul fix 5027a87 (db_change: migration) → re-deploy OK; clean forward nad live ae51969; app VERIFIED health 200 version=5027a87, QA hub 4/4; worker DORMANT → AKTIVOVÁN 2026-07-14 (REQ-023 approved + cs ready, Libor): WRITE OK secrets badwolf → REDIS_BUS_URL (prod cortex-redis) + CS_API_URL http://100.120.98.59:8080 + CS_API_KEY (z Cortexu /opt/s60-cs/.env API_KEY_BW) do /root/secrets/badwolf/.env.prod (backup .bak-req023-*) → DEPLOY OK badwolf prod recreate; prod-gate hub-freshness block (hub stamp >2h) → refresh deploy.sh badwolf hub --skip-build (QA 4/4, nový stamp) → prod recreate OK; poslední konektivita fix: badwolf container (s60-network 172.18.0.6) → host TS IP 100.78.87.88:6380 = ETIMEDOUT (UFW allow byl jen Cortex) → ufw allow from 172.18.0.0/16 to any port 6380 (WRITE OK ssh prod); BACKFILL DOJEL end-to-end: fronta cs-to-badwolf 8391 → 0 (wait+active), failed 0, 2130 client_communications řádků source=cortex vč. thread_ref, ~6261 skip (no CRM client match — expected, flagnuto badwolfovi jako jeho matching); worker běží kontinuálně; flagy FULFILLMENT_PUBLISH_ENABLED=true / ENROLLMENT_NOTIFY OFF; párový venom 1e37120 REQ-022 timeline live → ožil) |
✅ | sentinel |
| 2026-07-13 | S60Venom | hub + prod | 1e37120 (Button asChild přes Radix Slot (konec React warningu chyceného GlitchTipem + nevalidní <button><a> DOM) + REQ-022 email komunikace v timeline klienta (Cortex→BW→Venom, v1 read; graceful degradace — UI aktivní až BW ingest posílá data, do té doby beze změny); venom INFO T-20260713-084, DEPLOY OK venom hub+prod Libor, FE-only clean forward nad 66ea9b4, žádné deps/migrace; hub bundle index-BMXsj4Wo.js, prod index-DEGDRdnD.js, per-env API + DSN ověřeno; párový BW protějšek = aa48acf REQ-023 (zatím blokován stale DEPLOY.md — venom degraduje bez něj)) |
✅ | sentinel |
| 2026-07-13 | cortex-redis | hub + prod ops (nová infra) | Dedikovaný Redis pro Cortex↔badwolf BullMQ fronty (Libor pokyn) — cross-host komunikace CS pipeline (Cortex 100.120.98.59) ↔ badwolf přes fronty (DEC-005 vzor: eventy=fronta, sync=REST). Dedikovaný místo sdíleného s60-redis — izolace (Cortex nevidí auth token blacklist/ostatní fronty) + vlastní silné heslo per-env místo exponovaného changeme123 + žádný blip na s60-redis (ověřeno Up 4 months healthy netknutý). cortex-redis container (redis:alpine, AOF, volume cortex-redis-data) na hub-alfa (100.68.138.14:6380) + prod-alfa (100.78.87.88:6380), spuštěno docker run (deploy-guard tvrdě blokuje docker compose na hub/prod; cortex-redis nemá deploy.sh manifest = standalone infra jako s60-redis/n8n); bind jen na Tailscale IP (ne 0.0.0.0 → veřejně zavřeno), UFW allow jen Cortex 100.120.98.59→6380; hesla /root/secrets/cortex-redis/{hub,prod}.env (WRITE OK secrets cortex-redis); ověřeno oba: PING→PONG (auth), port bind TS-only, s60-redis netknutý; connstringy inline relay → badwolf T-062 (konzument) + cs T-063 (producent); fronta spec/DLQ/idempotence = badwolf+cs (jobId bez : — BullMQ), dev Redis na Cerebru = infra (T-058, ne sentinel); doc services/redis/INDEX.md; KONEKTIVITA SAGA (cs timeout → 3 vrstvy): (1) původní -p published port → Tailscale ts-forward DROP un-DNAT-ované odpovědi (source=TS IP out tailscale0) → fix --network host + bind na TS IP (recreate hub+prod, WRITE OK ssh); (2) mezikrok ufw route allow byl slepá ulička (ufw chainy ve FORWARD za ts-forward, 0 pkts) — a UFW je pro tailscale zdroje celkově no-op (ts-input ACCEPT all in=tailscale0 před ufw); (3) skutečný zbývající filtr = Tailnet ACL — 4zdrojová izolace (sentinel/hub/prod OK vč. AUTH+PONG, cortex+cerebro TIMEOUT) ukázala per-source split user-owned (autogroup:member→*) vs tagged; cortex=tag:cortex bez grantu, dropnut uvnitř tailscaled před tailscale0; Liborova první rule mířila na neexistující tag:hub/prod (stroje netagované — tag-scheme v policy rozdělaný, whois ověřeno) → finální grant tag:cortex → [100.68.138.14, 100.78.87.88] : tcp:6380 (admin console, Libor); cerebro→hub/prod timeout = by design ([[feedback_cerebro_no_ssh]] — ACL správně vynucuje security model); OVĚŘENO OSTRÝM PROVOZEM: cs probe 50 + plný backfill 8390 emailů → fronta cs-to-badwolf wait 5018+ rostoucí, failed 0, job email.observed, ~2KB/job, worker dormant akumuluje dle plánu) |
✅ | sentinel |
| 2026-07-13 | S60Venom | hub + prod | 66ea9b4 (mazání záznamu komunikace v timeline (jen venom-authored, DELETE endpoint už live) + úklid konzolových errorů: DetailPanel sr-only SheetTitle (Radix a11y) + error-logger nePOSTuje na mrtvý /logs/errors + console.error teče do GlitchTipu (captureConsoleIntegration → venom reportuje i konzolové chyby, navazuje na DSN fix); venom INFO T-20260713-039, DEPLOY OK venom hub+prod Libor, FE-only clean forward nad 1eb510e, žádné deps/migrace; hub bundle index-Bd3krQDh.js, prod index-CWUPk6yb.js, per-env API + DSN ověřeno) |
✅ | sentinel |
| 2026-07-13 | S60Venom | hub + prod | 1eb510e (dashboard barevná mapa v2 — dvě okna (0-3M pozadí, 3-6M text, pilulky vždy barevné) + settings-driven škály z internal_settings klíč venom.dashboard.confirmedScales (fallback default v kódu); venom INFO T-20260713-031 (supersedes f7a33df), DEPLOY OK venom hub+prod Libor, FE-only clean forward nad f7a33df, žádné deps/migrace; BW dependency splněna — badwolf ae51969 + internal_settings seed live PŘED venom deployem; hub bundle index-DEEWSNgs.js, prod index-CLOWKeK1.js (jiné hashe = build proběhl), per-env API + DSN 40da428f=1 ověřeno) |
✅ | sentinel |
| 2026-07-13 | BadWolf | hub + prod | ae51969 (kumulativní — REQ-022 internal settings + urgent PROD-500 fix (052) + REQ-015 E2E/jobId fix (ee98a24); badwolf TODO T-20260713-020 (supersedes d5a6ad3/ee98a24), DEPLOY OK badwolf hub+prod Libor; db_change: 2 MIGRACE manual_sql aplikované RUČNĚ přes pg-alfa SU PŘED app deployem (hub i prod, backup /var/lib/postgresql/badwolf-mig0523-{hub,prod}-<TS>/, ON_ERROR_STOP): 052 communications.created_by UUID FK→VARCHAR(255) (DROP FK + ALTER TYPE, data safe=NULL všude, mimo sync hash) → opravuje prod 500 na POST /communications = GlitchTip venom #44 (chybu zachytil čerstvě opravený venom error reporting — fix DSN se hned vyplatil); 053 CREATE TABLE internal_settings + seed venom.dashboard.confirmedScales + ALTER OWNER → s60_badwolf_{hub,prod}_user (jako 051); clean forward nad live d5a6ad3; app VERIFIED health 200 version=ae51969, QA hub 4/4 (MAJOR), boot čistý 0 permission denied; 🔴 flag nesoulad zachycen: badwolf tvrdil „FULFILLMENT_PUBLISH_ENABLED zůstává OFF", ale fakt-check ukázal =true (živý pilot od aktivace) → ee98a24 jobId colon→pomlčka fix opravoval živý producer (ne prep na budoucí flip); ENROLLMENT_NOTIFY_ENABLED zůstává OFF (access maily dormant), FULFILLMENT_PUBLISH_ENABLED=true zachován recreate) |
✅ | sentinel |
| 2026-07-13 | S60Venom | hub + prod | f7a33df (dashboard barevná mapa řádků widgetu Budoucí termíny dle počtu potvrzených, per-kurz škály, okno 0d–6M; venom INFO T-20260713-016, DEPLOY OK venom hub+prod Libor, FE-only clean forward nad b4f006f, žádné deps/BE; hub bundle index-CM4PUxVE.js, prod index-C9iOt9IJ.js, per-env API + DSN 40da428f=1 ověřeno; nasazeno paralelně s Fess DB rebrandem) |
✅ | sentinel |
| 2026-07-13 | S60Venom | hub + prod | b4f006f (dashboard widget kompaktní/flexibilní (w-fit, ikony+tooltip, kurz=kód) + 🔧 ERROR REPORTING FIX; venom INFO T-20260713-005, DEPLOY OK venom hub+prod Libor, FE-only clean forward nad live 2965a23; root cause GlitchTip venom 0 událostí/90d: VITE_SENTRY_DSN chyběl v build env → compose arg ${VITE_SENTRY_DSN:-} prázdný fallback → Sentry.init no-op → bundle bez DSN; venom tipoval /root/s60/.env, ale reálný zdroj VITE_ hodnot = /root/secrets/venom/.env.<env> (deploy.sh sync → /opt/venom/.env) — tam DSN chyběl; fix (WRITE OK secrets venom): přidán VITE_SENTRY_DSN=https://40da428f…@errors.studio60.cz/4 (projekt venom=4, veřejný v bundlu ale drženo v secrets u ostatních VITE_) do .env.hub+.env.prod (backup .bak-sentrydsn-*) → --build --skip-ci zapekl; ověřeno served bundle: 40da428f 0→1 + errors.studio60.cz 1 na hub (index-D0YspAPx.js) i prod (index-7eyQDFZu.js), per-env API URL OK → chyby se teď reportují do GlitchTip; navazuje na venom-agent read token 2026-07-13 (teď má co číst); QA hub 4/4) |
✅ | sentinel |
| 2026-07-12 | S60Venom | hub + prod | 2965a23 (= 8316d68 velký release + 2965a23 UX refinement: dashboard widget proklik ?course=&term= + editor šablon highlighting lang-html/oneDark + tlačítko Formátovat (js-beautify); nové npm deps @codemirror/lang-html+js-beautify → build stáhl, bundle změněn hub index-DpAZI_n5.js/prod index-BbcKuiDb.js (per-env baked URL ověřeno); venom INFO T-20260712-195, DEPLOY OK venom hub+prod Libor; velký release — Dashboard REQ-020 + header počty REQ-019A + presence filtr REQ-019B + orders multi-select + editor e-mail šablon REQ-021 (/email-templates) + fulfillment resolve checkbox; venom INFO T-20260712-181 (nahradil ffadb04/d0f19bd), DEPLOY OK venom hub+prod Libor; db_change none, FE-only, clean forward nad live d0f19bd (3 commity vč. ffadb04 orders 400 fix → vráceno na multi-select bo BW už umí status pole); DEPENDENCY splněna: venom volá nové BW endpointy → ověřeno BW protistrana live na hub+prod = d5a6ad3 (email-templates GET/PUT/preview + stats/by-course-date registrované) PŘED venom deployem → Dashboard/Šablony nehlásí chybu; self-contained --build --skip-ci; hub: QA 4/4, bundle index-D9Tgwto2.js (api.s60hub.cz ✓, email-templates 94×, by-course-date 2×); prod: VERIFIED, health 200, bundle index-m5ldJeCl.js (api.studio60.cz ✓ / api.s60hub.cz 0×, email-templates+by-course-date 96×); řeší i živý prod orders 400 (ffadb04 v balíku); editor /email-templates edituje seed šablonu enrollment-access na BW) |
✅ | sentinel |
| 2026-07-12 | BadWolf | hub + prod | d5a6ad3 (REQ-015 access mail + venom REQ-019/020 stats/orders + BullMQ root refactor; badwolf TODO T-20260712-173, DEPLOY OK badwolf hub+prod Libor; db_change: MIGRACE 051 (manual_sql) — deploy.yml migration_command: null → aplikováno RUČNĚ přes pg-alfa SU PŘED app deployem (hub i prod identicky, backup /var/lib/postgresql/badwolf-mig051-{hub,prod}-<TS>/, ON_ERROR_STOP, BEGIN/COMMIT): A. online_courses.content_type ADD COLUMN + backfill (course=19/ebook=1/music=14), B. online_course_enrollments + moodle_pushed_at/access_notified_at + partial index idx_oce_order_notify, C. CREATE TABLE email_templates + seed enrollment-access (1 řádek, WHERE NOT EXISTS); ⚠️ ALTER TABLE email_templates OWNER TO s60_badwolf_{hub,prod}_user (můj nález 2026-07-03 [[feedback_deploy_migration_check_dir]] kontext — SU-created tabulka jinak app user bez INSERT/UPDATE → Venom editor by nezapisoval) → boot čistý, 0 permission denied ověřeno; clean forward nad live 292798e; app: Image Built (CR-008), VERIFIED, health 200 version=d5a6ad3, QA hub 4/4 PASS (tier MAJOR); flag ENROLLMENT_NOTIFY_ENABLED default OFF → access maily DORMANT (flip koordinovat zvlášť); FULFILLMENT_PUBLISH_ENABLED=true zachován (fulfillment pilot běží dál, recreate secret nesmazal); Venom REQ-019/020 endpointy live; seed šablona enrollment-access na BW → Libor doladí copy ve Venom editoru) |
✅ | sentinel |
| 2026-07-12 | S60Venom | hub + prod | d0f19bd (= 7f1a791 REQ-018 + d0f19bd UI refinement; REQ-018 „Nepřidělené kurzy" (/fulfillment) — venom UI volá BW fulfillment endpointy GET/POST /api/internal/fulfillment/failures[/:id/resolve] přes JWT (zapadá na BW guard fix 292798e=JwtOrApiKeyGuard) + fix panel klienta (taby flex-wrap) + authorId jen když UUID (jinak BW @IsUUID() 400 → tiché pády audit zápisů); venom TODO T-20260712-119, DEPLOY OK venom hub+prod Libor; db_change none, čistě frontend, clean forward nad live 9785be1 (2 commity); self-contained build deploy.sh venom --build --skip-ci (compose build sekce, vitest×PW misconfig → skip-ci); hub: QA 4/4 PASS (title „Venom Admin", bundled assets), served bundle index-uQKt8PYV.js ověřen: baked api.s60hub.cz ✓ / api.studio60.cz 0× ✓ / /fulfillment 63× ✓; prod: Image Built, VERIFIED, health 200, served bundle index-BGrctGzb.js: baked api.studio60.cz ✓ / api.s60hub.cz 0× ✓ / /fulfillment 63× ✓ (per-env build správně); 2. deploy d0f19bd (venom TODO T-20260712-135, nahradil 7f1a791) — search kurzů v modalu přiřazení + čitelný důvod selhání v „Nepřidělené kurzy"; hub bundle index-CgX72xc2.js (api.s60hub.cz ✓), prod bundle index-B1YjchfD.js (api.studio60.cz ✓), QA 4/4) |
✅ | sentinel |
| 2026-07-12 | BillIt | hub + prod | b38ea76 (= 92cd66c CR-063 consumer + 45b3d74 CR-064 přehled expedice + b38ea76 CR-065 expedice fyz. produktu; billit INFO T-20260712-157 (supersedes T-142), DEPLOY OK billit hub+prod Libor; CR-065 = UI dialog vytvoření zásilky (nad REQ-046 shipments) + order_shipped mail (best-effort, default-on přes autoEmails===false, LIVE na prod → reálný e-mail zákazníkovi při expedici) + fix hlášky mazání objednávky; CR-064 = read-only přehled expedice/plnění (per-řádek fulfillment stav odvozený na čtení findAll/findOne, žádný DB zápis + FE sloupec „Plnění" + filtr „Čeká na expedici"), BEZ migrace; baseline korekce: billit psal „delta od abd4531" ale reálný live byl už 92cd66c → net delta = jen 45b3d74 (CR-064), cross-check proti 92cd66c čistě; migrace No pending (CR063 už applied z 92cd66c ověřeno v migrations); hub (prod-mirror): QA 10/10 PASS; prod: oba containery Healthy, VERIFIED, ucto.studio60.cz health 200, fronta bull:badwolf-to-billit žije (consumer sleduje); CR-063 fulfillment consumer (protikus DEC-005 badwolf produceru; — protikus DEC-005 badwolf produceru; billit odebírá z BullMQ fronty badwolf-to-billit na sdíleném s60-redis, per-řádek fulfillment_status/detail + order rollup + FE badge „zaplaceno/nedoručeno"; billit INFO T-20260712-111, DEPLOY OK billit hub+prod Libor; db_change MINOR: 1 migrace 1773070000000-CR063FulfillmentStatus — ADD COLUMN IF NOT EXISTS fulfillment_status varchar(20) + fulfillment_detail jsonb na order_lines + partial index idx_order_lines_fulfillment_status WHERE NOT NULL, additivní/idempotentní, žádná datová transformace, down()=rollback; clean forward nad live abd4531; hub = prod-mirror → migrace validována na reálných datech (built-in rehearsal), QA 10/10 PASS; prod: pre-deploy DB dump snapshot 20260712-1045-92cd66c (rollback), migrace executed successfully COMMIT, VERIFIED, ucto.studio60.cz health 200, sloupce fulfillment_status/detail + index ověřeny na prod; consumer DORMANT — naslouchá frontě (prázdná dokud badwolf nepustí FULFILLMENT_PUBLISH_ENABLED); OBĚ STRANY PILOTU NASAZENY (BW producer fc8a27d flag OFF + billit consumer 92cd66c listening) → aktivace = koordinovaný flag flip) |
✅ | sentinel |
| 2026-07-12 | BadWolf | hub + prod | 292798e (= ed219fd producer + fc8a27d resolve + 292798e guard fix JwtOrApiKeyGuard pro Venom; DEC-005 fáze 1 — BW producer fulfillment eventů do sdílené BullMQ fronty badwolf-to-billit na s60-redis; navazuje na sentinel infra analýzu → DEC-005 approved (spec badwolf/specs/DEC-005.md), billit píše consumer; badwolf INFO T-20260712-100, DEPLOY OK badwolf hub+prod Libor; db_change none, žádná migrace, žádná env změna; clean forward nad live 57a6d0a (1 commit); producer za flagem FULFILLMENT_PUBLISH_ENABLED (default OFF) → deploy = kód na místě DORMANT, žádné publikování, žádná změna chování — ověřeno flag absent v /opt/badwolf/.env hub i prod; hub: VERIFIED, health 200, QA 4/4 PASS (tier RELEASE); prod: snapshot 20260712-1014-ed219fd, Image Built (CR-008), VERIFIED, health 200 version=ed219fd, npm audit 0 crit/8 high (preexisting); 2. deploy fc8a27d (badwolf TODO T-20260712-103, DEPLOY OK badwolf hub+prod Libor) přidal manuální resolve endpointy GET /api/internal/fulfillment/failures + POST .../resolve/:conflictId (ApiKeyGuard, always-on, ale no-op publish dokud flag OFF) — hub QA 4/4, prod snapshot 20260712-1019-fc8a27d VERIFIED health 200 version=fc8a27d, flag stále absent = dormant, endpointy registrované (RouterExplorer); AKTIVACE PROVEDENA 2026-07-12 (Libor go): WRITE OK secrets badwolf → FULFILLMENT_PUBLISH_ENABLED=true do /root/secrets/badwolf/.env.prod (backup .bak-fulfillment-20260712-111556) → DEPLOY OK badwolf prod → deploy.sh badwolf prod --skip-build (sync + recreate); flag ON ověřen v containeru, health 200, fronta bull:badwolf-to-billit na prod s60-redis existuje (:meta+:stalled-check → billit consumer aktivně sleduje) → event-bus LIVE, při 1. reálném order.paid s online kurzem BW publikuje → fronta → billit odbaví; billit+badwolf signalizováni (T-122/123); heslo changeme123 [[feedback_no_shared_password_rotation]] NErotovat)) |
✅ | sentinel |
| 2026-07-12 | BillIt | hub (dress rehearsal) + prod | abd4531 (CR-061 fáze 1+2 — per-vendor fan-out finálních faktur po platbě multi-vendor objednávky (místo 1 platformní faktury → N vendor faktur, každý vendor svá řada/IČO/účet, rovnou PAID) + vendor ledger/dávkové vyúčtování + křížové odkazy dokladů 9844481; billit INFO T-20260712-030, DEPLOY OK billit hub + „dress rehearsal" Libor; db_change none, žádná migrace; clean forward nad live 087ea51; 🔴 PROD HARD-GATED: CR-061 mění tvar/počet webhooků (invoice.created, order.paid snapshot nese N faktur) → dopad na badwolf konzument → prod AŽ po D5 koordinaci (badwolf T-007 + WP/Learnia T-008) + živém ověření multi-vendor toku; DRESS REHEARSAL (runbook pulse-hub-dress-rehearsal + billit precedent): backup hub billit-dr-20260712-062125Z/hub-rollback.dump → prod→hub klon (pg_dump --no-owner --no-privileges → DROP SCHEMA → pg_restore, 19587 faktur/11 tenantů/73 migrací) → ALTER OWNER → s60_billit_hub_user (still_postgres=0) → SECURITY SCRUB (hub-mirror, prod NEDOTČEN): bank_accounts.fio_api_token 11× + inbound_email_token 1× + tenants.stripe_secret_key/stripe_payment_webhook_secret 2× → NULL, webhook_configs 4× → active=false+dummy secret+blackhole URL (hub nepošle fan-out webhooky na prod api.studio60.cz); ⚠️ scrub v1 rollbacknul (webhook_configs.secret NOT NULL → =NULL spadlo → ON_ERROR_STOP zrušil celou tx → hub měl krátce živé prod secrets, ale unscrubbed okno čisté: žádný Fio/webhook fire, poslední Fio cron 06:20 = PŘED mirrorem) → scrub v2 (dummy secret) OK, verify fio/stripe/inbound/webhook-active = 0; deploy abd4531 na mirror VERIFIED, migrace No pending, health 200 api+web, QA 10/10 PASS, 8 aktivních vendor links → fan-out testovatelný; hub drží prod PII po dobu rehearsalu (UFW-locked) → po D5 vrátit hub na vlastní data (hub-rollback.dump); PROD NASAZEN (DEPLOY OK billit prod Libor + explicitní gate confirm „D5 ověřeno + badwolf ready" — sentinel držel prod, dokud Libor gate nepotvrdil): snapshot 20260712-0841-abd4531 (DB 4.7M), oba containery recreated + api Healthy, migrace No pending (db_change none → prod DB beze změny), VERIFIED source hash, ucto.studio60.cz/health 200 uptime 69s, žádný race/false-positive; prod DB rehearsalem nedotčena ověřeno (prod webhook active=4 + fio tokeny 11 = reálné intact, scrub byl jen hub); follow-up: Libor rozhodl NErestorovat — billit hub ZŮSTÁVÁ prod-mirror (scrubnutý: bez fio/stripe/webhook-to-prod, UFW-locked); budoucí billit hub QA/deploy pojede proti prod-mirror datům; hub-rollback.dump zachován pro případný pozdější restore) |
✅ | sentinel |
| 2026-07-11 | BillIt | hub + prod | 087ea51 (billit-api + billit-web — order.completed webhook (WP/WC parita — WC digitální objednávky visely na „processing") + PDF názvy <slug>-<číslo>.pdf + z paid proformy VŽDY faktura, žádné DDP (Liborovo definitivní rozhodnutí, incident DDP2026-0002) + default řazení faktur issuedOn DESC (FE); billit INFO T-20260711-235 (supersedes T-126), DEPLOY OK billit hub+prod Libor agile; db_change none, žádná migrace (SQL skripty v scripts/ ne migrations/ → gate netripne); baseline korekce: billit psal „delta od LIVE 3c4047c", ale živě běželo už 50cba9c → net delta = 642db77+087ea51, cross-check jel proti reálnému 50cba9c ze snapshot manifestu; DEPLOY.md Current stale: „billit-api only (FE beze změny)" ale 642db77 FE MĚNÍ → ověřen served bundle; hub: oba containery recreated + api Healthy, VERIFIED source hash, health 200 api+web, QA 10/10 PASS; prod: snapshot 20260711-2328-087ea51 (DB 4.7M), oba recreated, migrace No pending, VERIFIED, ucto.studio60.cz/health 200 uptime 74s (billit.cz=301 rebrand DEC-014), served bundle index-BEEVgaUc.js; žádný selective_recreate false-positive ani docker race; POST-DEPLOY OPS: (1) SQL fix HOTOVO (EXEC OK billit prod Libor) — scripts/2026-07-11-fix-ddp0002-to-invoice.sql pod pre-check (collision 2026-0181=0, řádek byl DDP2026-0002/tax_document) + pg_dump backup + transakčně ON_ERROR_STOP: doklad 6b018521 DDP2026-0002→faktura 2026-0181 (invoice/paid/VS 120260002 zachován), setval _invoice_2026→182/f + _tax_document_2026→2/f, UPDATE=1, sanity DDP=0/2026-0181=1; (2) BullMQ job removal = MOOT — billitova premisa „s60-mail stojí → job čeká" byla MYLNÁ: s60-mail Up 2 weeks healthy aktivně posílá, queue email-outbound 0 waiting/100 completed, s60-mail log potvrzuje odeslání starého DDP v 19:40:44 (Email sent to=levandulenkaul@gmail.com ... DDP2026-0002 id=60549775) ~4h PŘED fixem → zákaznice starý DDP UŽ DOSTALA, není co mazat (WRITE OK ssh prod spotřebován na abort-safe inspect, match=0); Liborův ruční resend faktury 2026-0181 = korekce k už odeslanému DDP; FYI bug: email_logs 7c2f8674 zůstal queued/sent_at NULL i po reálném odeslání (mail→billit status callback neaktualizuje; 110 queued logů vs 0 waiting = stejný decoupling)) |
✅ | sentinel |
| 2026-07-11 | S60Auth | hub + prod | b1fcd2c (kód 48e60de — FE Login.tsx toast fix [no-spec bugfix] — race: dvojí souběžný doOAuthRedirect (onLogin + useEffect po flipu isAuthenticated) → navigace z 1. callu abortovala 2. → falešný červený toast „Chyba při přesměrování do aplikace" těsně před redirectem, hlášeno z Learnia prod loginu; auth TODO T-20260711-231 (nahradil původní cíl 98a4d9b), DEPLOY OK auth hub+prod Libor agile (jeden OK, oba tokeny); db_change none, žádná migrace, jen FE rebuild; clean forward nad live e519cdf (+48e60de +b1fcd2c DEPLOY.md); cíl tip b1fcd2c (=48e60de kód + DEPLOY.md Current 48e60de); hub: VERIFIED source+backend-build hash (backend beze změny → build hash 2872cca identický s e519cdf, změna jen ve frontend containeru), health 200 BE+FE, QA 4/4 PASS (auth-e2e-login 20/0 + auth-error-format 6/0); prod: snapshot 20260711-2311-b1fcd2c (DB 124K), oba images rebuilt+recreated, migrace No pending, VERIFIED, openid issuer auth.studio60.cz OK, /api/health 200 (0.02s), FE root 200, served bundle index-CMQu6TpA.js; REQ-048 e2e OVĚŘENA na prod (auth T-20260711-232): libor@webster.zone BW lookup→bcrypt verify→auto-provisioning→audit auth.provisioned_from_bw→argon2, opakované loginy lokální; původní selhání = špatný hash v BW importu (opraveno password-refresh, viz řádek legacy_credentials 1-row transfer); tasky T-168/169 tímto hotové; Cerebro /root/secrets/auth-bw-legacy-prod.env OK smazat (secret žije v prod env)) |
✅ | sentinel |
| 2026-07-11 | BadWolf | hub + prod | 57a6d0a (kód bd067f5 — REQ-018 autolink fix — navazuje na 56fbfba; URGENT badwolf TODO T-20260711-208, „krize"; kontext = můj batch total:0 nález: post-deploy ensure-users/batch vrátil {total:0} → odhalilo hlubší díru: user_client_links na produ nikdo neplní (auth /migrated nese jen email, ne sub) → ensure-user neměl clientId k doenrollování a batch neměl koho iterovat; fix bd067f5: ensure-user založí vazbu autolinkem přes email-match (idempotentní, uq_clients_email_active), dev 136/136; KLÍČ oprava předchozího záznamu: api_keys.key je PLAINTEXT (ne hash, jak jsem u 56fbfba chybně napsal) — Liborův původní klíč s60_wp_5dbdf664… (49 zn) NESEDĚL (401), živý aktivní klíč „WP Plugin s60-badwolf-wp" = s60_wp_9678599… (55 zn) dal 200; klíč badwolf potvrdil + batch pouští sám z Cerebra; db_change none, žádná migrace, žádné env, clean forward nad live 56fbfba (+bd067f5 +57a6d0a DEPLOY.md); hub-before-prod DODRŽENO: Libor nejdřív zvažoval prod-first crisis-override, pak potvrdil hub first (prod-gate by jinak blokoval na stampu 56fbfba); gotcha: DEPLOY OK badwolf hub přišel jako mid-turn zpráva → token se nezachytil ([[feedback_deploy_guard_gotchas]]) → resend; hub: VERIFIED, health 200, QA 4/4 PASS, čerstvý stamp commit=57a6d0a → prod-gate čistě bez override; prod: VERIFIED, health version=57a6d0a, snapshot 20260711-2233, npm audit 0 critical/8 high (preexisting), routes registrované; BATCH + plošné uzdravení = badwolf strana (ensure-on-login: každý migrovaný user se opraví při loginu na learnia.cz, wp opravuje consumer Bearer→X-Api-Key); ⚠️ hub-prod parity: full hub deploy proběhl PŘED prod, parity OK) |
✅ | sentinel |
| 2026-07-11 | BadWolf | hub + prod | 56fbfba (kód 4565b76 — REQ-018 Moodle ensure-user — poslední článek legacy-login řetězu: migrovaní useři neviděli kurzy „/moje-kurzy → Moodle účet nenalezen"; nové POST /api/moodle/ensure-user + /api/moodle/ensure-users/batch (ApiKeyGuard); URGENT badwolf TODO T-20260711-198, DEPLOY OK badwolf hub+prod Libor interaktivní session; db_change none, žádná migrace, žádné env změny (MOODLE_URL/TOKEN + MOODLE_PUSH_ENABLED=true už na produ); clean forward nad live 10b3ca6 (+0ead5e6 spec drafty +4565b76); cíl tip 56fbfba (=4565b76 kód + DEPLOY.md); CR-008 self-contained Docker build ZABRAL — Image s60-badwolf:latest Built přes deploy.sh, žádný ruční build (past [[feedback_deploy_build_command_dead]] opravena, ověřeno compose build: context . na hub i prod); hub: snapshot 20260711-2205-56fbfba, VERIFIED source+build hash, health 200, QA gate 4/4 PASS (auth-guard + error-format), REQ-018 routes registrované (RouterExplorer); prod: migration cross-check Last deployed=10b3ca6 clean forward, snapshot 20260711-2208, npm audit 0 critical/8 high (preexisting, non-block), VERIFIED, health version=56fbfba, routes registrované; POST-DEPLOY BATCH PENDING: POST /api/moodle/ensure-users/batch (pre-provisioning Moodle účtů migrovaným userům) čeká na WP plugin X-Api-Key — není v sentinel secrets (jen WP/cms strana), api_keys DB hashovaná → plaintext nejde vytáhnout → vyžádán od Libora/badwolfa) |
✅ | sentinel |
| 2026-07-11 | BadWolf | prod ops (DB import) | legacy_credentials import 7676 řádků (REQ-048 druhá polovina — root cause legacy/Jenkins login incidentu: prod tabulka legacy_credentials (migrace 042) byla PRÁZDNÁ, import nikdy neproběhl; auth strana e519cdf řeší M2M kanál, tohle dodává data; badwolf TODO T-20260711-175, IMPORT OK badwolf prod Libor interaktivní session; varianta B = dev→prod copy na téže pg-alfa instanci (100.125.3.121) pod SU, jeden pipe, hashe nikdy na disk/do logu; dev zdroj čerstvý z dnešního bw importu z živého Jenkinse; recon před: dev+prod stejná instance, prod 0 řádků (TRUNCATE no-op), schema 14 sloupců sedí s COPY listem, id je IDENTITY (auto), dev source='jenkins_migration'=7676 (+2 synthetic_test jid -1/-2 správně vynechány filtrem), verifikační řádek libor@webster.zone OK; exekuce pod [[feedback_destructive_wipe_discipline]]: pre-import pg_dump backup /var/lib/postgresql/badwolf-legacy-import-20260711-211830/ + transakčně BEGIN/TRUNCATE/COPY(dev jenkins_migration→prod, client_id+migrated_at ZÁMĚRNĚ NULL)/COMMIT s ON_ERROR_STOP=1, pipe status 0 0; verify: prod 0→7676, 100% jenkins_migration, libor@webster.zone t\|f\|t\|$2y$13$\|bcrypt = přesně bw očekávání, žádná jiná tabulka netknuta, app restart netřeba (bez schema změny); FYI badwolfu: synthetics nebyly v jenkins_migration jak psal, ale v samostatném source — bez dopadu; NEXT e2e: auth M2M kanál armed+aktivní (BW_LEGACY_LOOKUP_ENABLED=true) + prod data přítomná → připraven prod happy-path libor@webster.zone login → provisioning → audit auth.provisioned_from_bw (koordinace auth/badwolf/Libor)) |
✅ | sentinel |
| 2026-07-11 | S60Auth | hub + prod | e519cdf (kód 98a4d9b — REQ-048 M2M kanál auth→BW pro lazy legacy migraci; incident: po prod cutoveru se legacy/Jenkins uživatelé nemohli přihlásit; DEPLOY OK Libor interaktivní session, auth TODO T-20260711-168; pure code + config, db_change none, žádná migrace — client_credentials tokeny nově nesou standardní scope claim (additivní), LegacyMigrationService dynamický M2M token místo statického (cache+401 retry), notifyMigrated() fire-and-forget fail-open; BENIGNÍ DIVERGENCE VYŘEŠENA před deployem: auth zpráva žádala 98a4d9b ale lokál byl v detached HEAD na 77b0d12 a DEPLOY.md Current ukazoval 2360458 (CR-018) → recon: historie LINEÁRNÍ, live hub = 77b0d12 (CR-018 už baseline, image 06:38, health 200), merge-base --is-ancestor 77b0d12 98a4d9b=YES → 98a4d9b = live + jen REQ-048, žádný CR-018 rollback ani cizí scope; cíl = tip e519cdf (=98a4d9b kód + správný DEPLOY.md Current 98a4d9b/migration_from 77b0d12); migrace match jen legacy-migration.service.ts = service soubor ne migrations/ dir → gate netripne, „No pending"; compose má reálné build: sekce (backend+frontend) → čistý rebuild; snapshot 20260711-2057-e519cdf (DB 148K), oba containery VERIFIED labely 2/2 healthy, .deploy-commit=e519cdf source+build hash match, /api/health 200 BE+FE, QA gate hub PASSED (auth-e2e-login 20/0 + auth-error-format 6/0 = 4/4); AKTIVACE = prod-only krok Libora PO prod deployi (flag default OFF → hub bez aktivace beze změny chování): 5 env řádků z /root/secrets/auth-bw-legacy-prod.env na Cerebru + restart, M2M klient s60-bw-legacy-integration-2042b97b už na prod auth vytvořen; ⚠️ env AŽ PO deployi jinak starý kód bez scope claimu → BW 403; PROD nasazen (DEPLOY OK auth prod, Libor interaktivní session): migration cross-check Last deployed=77b0d12 (prod baseline = hub → clean forward), snapshot 20260711-2102-e519cdf (DB 124K), migrace No pending, oba containery VERIFIED labely 2/2 healthy, .deploy-commit=e519cdf source+build hash match, prod gate prošel na čerstvém sentinel-local qa-pass z hub běhu; nezávislá verifikace: public auth.studio60.cz openid issuer OK + /api/health 200 (0.07s) + 0 error v post-deploy logu; AKTIVACE HOTOVA (Libor předal 5 env hodnot v ric session): vloženo do /root/secrets/auth/.env.prod (backup .bak-20260711-210657) → synced přes --skip-build recreate (2. prod token — deploy-guard blokoval recreate na spotřebovaný jednorázový token, Libor re-issue; guard chytl i send-message tělo s literálem příkazu = přeformulováno) do /opt/auth/backend/.env; ověřeno uvnitř běžícího s60-auth-backend: BW_LEGACY_LOOKUP_ENABLED=true + všech 5 klíčů (secret 64 hex), health 200 BE+FE, .deploy-commit=e519cdf VERIFIED, 0 error v post-recreate logu; M2M klient s60-bw-legacy-integration-2042b97b; definitivní funkční důkaz = první reálný legacy/Jenkins login → audit auth.provisioned_from_bw (auth/Libor trigger/watch, kanál armed bez traffiku)) |
✅ | sentinel |
| 2026-07-03 | BadWolf | hub + prod | 21da0db (app kód 90762dc — CR-004 sync hardening (CAS guard, kill-switch, mass-delete threshold, GDPR suppressions, conflict dedup) + DES-004 §4–§7 Learnia enrollment řetěz (navazuje na billit CR-050 fulfillmentRef) + fix compose healthcheck /health→/api/health; delta 619c55b→90762dc 40 souborů +1718/−960; migrace 044 (manual_sql, PŘED app deployem, hub i prod): webhook_deliveries tabulka (DB idempotence webhooků) + sync_conflicts.type CHECK +enrollment_unresolved — additivní/idempotentní, aplikováno přes pg-alfa SU s ALTER OWNER na app usera (SU-created tabulka by app INSERTy odmítala), pre-mig dumpy /var/lib/postgresql/badwolf-mig044-20260703-132830/; REDIS_URL ověřen v obou env, nové moduly za flagy default OFF (env je nemá → chování beze změny); healthcheck fix ZABRAL: oba kontejnery poprvé od 6/29 healthy R=0 (předtím trvale unhealthy → i „fail" záznamy v deploys.log 6/29), /api/health 200 na api.s60hub.cz i api.studio60.cz; oba env VERIFIED labely 1/1; QA gate hub FAILED 2/5 = vše test-side, ne kód: badwolf-auth-guard.sh + badwolf-error-format.sh probují starý /health (identický FAIL spamuje QA_RESULT od 2.7. proti starému kódu) + deploy-audit false-positive na manual_sql migrace (nezná scripts/migrate-jenkins/migrations/ path) → TODO qa T-20260703-037; prod gate stamp override autorizoval Libor (ric session, audit trail ve stampu); Fáze D wiring (prod-baseline.ts D0 seed) = SAMOSTATNÁ akce mimo tento deploy (CR-004 B6, čeká koordinaci); uzavírá i AUTONOMOUS_BLOCKED thread T-20260702-029) |
✅ | sentinel |
| 2026-07-05 | S60 Pulse | hub + prod | 0b81dac (CR-210 admin správa speciálních nabídek — nová admin stránka Speciální nabídky (list/toggle/editor s preview/statistiky/duplikace/guarded delete) + BE Zod strict validace admin CRUD (dřív body:any), audit offer.created/updated/deleted, GET /stats, DELETE 409 guard + CR-145 tenant tx; db_change none, klientský flow nedotčen; kontext incident: seedovaná offer „Super hrdina" nebyla v adminu vidět; DRESS REHEARSAL (Libor vyžádal — data-visibility fix → ověřit admin proti reálným offers): clone prod→hub (runbook pulse-hub-dress-rehearsal), mirror věrný (special_offers 1=1, migrations 151=151, sessions 233=233, ownership fix still_postgres=0), deploy 0b81dac na prod-mirror → boot healthy R=0, admin /api/admin/offers živý+guarded (401 no-auth), reálná offer „Super hrdina · 15 kreditů" (active, 15kr/900) na mirroru přítomná = CR-210 ji admin zpřístupní, QA hub 15/15 PASS; prod VERIFIED labely 1/1 healthy R=0, pulselab.cz+/admin 200, offers guarded, Super hrdina na prod present → v prod adminu editovatelná; prod-gate fix: hub deploy zapsal čerstvý pulse-qa-pass commit=0b81dac, prod gate na něm prošel; po prod restore hub na vlastní staging data (sessions 226) + ALTER OWNER, hub healthy; rehearsal dumpy /tmp/pulse-dr-20260705/; hub držel prod PII jen po dobu rehearsalu (UFW-locked)) |
✅ | sentinel |
| 2026-07-05 | BadWolf | hub + prod | 832fc08 (sync fix — billit-sync.service.ts katalogový push type digital→online_course (DEC-001 enum canon + DES-004 §5): Účto je pass-through, type se vrací ve fulfillmentRef a enrollment handler matchuje PŘESNĚ online_course → s digital by zaplacený online kurz enrollment tiše přeskočil; relevantní teď když je webhook řetěz live (inner-sense); 4řádkový fix, žádná migrace (migration_command null → phase 6.5 skip; DEPLOY.md stale db_change=migration z 90762dc = neškodí); 1 container VERIFIED labely 1/1 healthy R=0, api.studio60.cz/api/health 200, jediný log „Invalid Sentry Dsn" (známý benigní); ✅ badwolf QA teď GENUINE PASS 4/4 — qa fix /health→/api/health (T-20260703-037) zabral, žádné stale test failures jako u 21da0db; ✅ prod-gate fix eliminoval override: hub deploy zapsal čerstvý sentinel-local badwolf-qa-pass commit=832fc08, prod gate na něm prošel BEZ manuálního override (na rozdíl od 21da0db kde override nutný byl); flag badwolf: bumpnout DEPLOY.md Current na 832fc08) |
✅ | sentinel |
| 2026-07-05 | BillIt | hub + prod | 50fabda (provize per-link fix 1c056d4 — getVendors přilepí commissionRate z linku na vendor tenanta (per-platforma) → platforma vidí i edituje per-vendor provizi (dřív vždy undefined, jen při pozvání); FE PlatformSettings VendorRow editovatelné pole provize + Uložit (PATCH /vendors/:slug) + ConfirmDialog; BE+FE 2 soubory +413 (zbytek docs/specs DEC-017/REQ-056 draft — REQ-056 impl odložena, priorita Learnia); žádná migrace (delta 77ee095..50fabda bez migration files); autorizace bezpečná — čte z už-scopnutých active links, žádná nová plocha; DEPLOY.md STALE (značí 77ee095 jako DEPLOYED, db_change parse=messy „MAJOR" z inc5 sekce, migration_from=9fa75ce) → neškodí: migration:run No pending; oba env VERIFIED labely 2/2 healthy R=0, ucto/health 200, QA hub 4/4 + prod 3/3 PASS; prod-gate fix aktivní i pro billit: hub deploy zapsal čerstvý sentinel-local billit-qa-pass commit=50fabda, prod gate na něm prošel; flag billit: bumpnout DEPLOY.md na Current: 50fabda / db_change: none) |
✅ | sentinel |
| 2026-07-05 | S60Auth | hub + prod (2. release dne) | d14901d (kód 8881031 — FE UX nad nasazeným a9f2388: CR-016 UX copy-to-clipboard klíče + scope picker v adminu (Liborova zpětná vazba) + REQ-004 UX login „Přihlásit e-mailem" jako 3. tlačítko vedle Google/FB; FE-only 2 soubory (Admin.tsx+Login.tsx), db_change none, žádný backend/security dopad (CR-016 guard už live); oba env VERIFIED labely 2/2 healthy R=0, openid 200, served FE bundle ověřen hash změnou (CPn71RIQ→DrrHSJPS hub, →DrrHSJPS prod); ✅ VALIDACE prod-gate fixu v ostrém provozu: prod gate hlásil QA gate: PASS (commit=d14901d qa=pass tier=PATCH) = dnešní čerstvý sentinel-local stamp správného commitu (ne stale jako u a9f2388 kde byl 25.4.) → fix funguje end-to-end bez manuálního lokálního qa-gate; DEPLOY.md migration_from hygiene stále pending u auth) |
✅ | sentinel |
| 2026-07-05 | deploy.sh | oprava pipeline (prod QA gate) | FIX prod QA gate na stale stampu (odhaleno při auth a9f2388 — prod gate prošel na auth-qa-pass z 25.4.; root cause 2 vrstvy: (1) hub qa-gate běží přes SSH NA hub-alfa → stamp landne tam, sentinel prod gate ho nikdy nevidí; (2) qa-gate pojmenuje stamp podle deploy.yml service/normalized s60-auth-qa-pass, prod gate čte ${PROJECT}-qa-pass=auth-qa-pass → mismatch u služeb kde dir-name≠service-name; fix: hub deploy nově zapisuje ${PROJECT}-qa-pass LOKÁLNĚ na sentinel (jako už hub-ok/deep-ok), jen na QA_RESULT==pass → prod gate vidí výsledek téhož hub běhu; SKIP no-QA služby dál vyžadují manuální override (žádné auto-pass); unit-test PASS-zapíše/SKIP-nezapíše ✓, bash -n ✓, end-to-end přes re-deploy auth hub; stale auth-qa-pass odstraněn, ostatní služby self-heal příštím hub deployem; commit v s60-sentinel repo) |
✅ | sentinel |
| 2026-07-05 | S60Auth | hub + prod | a9f2388 (CR-016 — dočasný admin API přístup pro agenta; JwtAuthGuard nově přijme admin-scoped API klíč X-Api-Key/Bearer s60_ (scope admin + vlastník enabled superadmin + neexpirovaný) jako plný superadmin, admin UI tlačítko „Povolit agentovi (1h)" vydá 1h klíč; bezpečnostní review sentinel: delta = přesně 4 soubory (guard+admin UI+2 spec) nad prod 4cb9df6, db_change none, no migration; guard trojitá pojistka; revokace = hard delete (entita nemá soft-delete → revoked klíč zmizí z DB → null → 401, funkčně ověřeno); zbytková by-design rizika: guard přijme JAKÝKOLI admin superadmin klíč (ne jen 1h → reálná kontrola = provozní disciplína krátké TTL/smazat) + admin klíč umí razit další klíče (chaining); hub+prod oba VERIFIED labely 2/2 (backend+frontend), healthy R=0, openid issuer OK, /api/health 200, CR-016 guard funkčně ověřen hub i prod (bogus s60_ klíč + no-auth → oba 401); 🔴 NÁLEZ gate plumbing: prod QA gate prošel na STALE stampu z 2026-04-25 — deploy.sh prod gate čte ${PROJECT}-qa-pass=auth-qa-pass (CLI název auth), ale hub QA zapisuje s60-auth-qa-pass (deploy.yml service name) → name mismatch, prod gate nikdy nevidí dnešní čerstvý stamp; tady bez škody (dnešní hub QA genuine 2/2 + nezávisle ověřen prod), ale je to díra pro služby kde CLI-název≠service-name; DEPLOY.md hygiene: Current sekce bez vlastního migration_from → deploy.sh vzal stale 09ecbea) |
✅ | sentinel |
| 2026-07-05 | S60AI (nový) | pg-alfa ops (DB onboarding) | s60_ai_prod založena (nový dev agent s60ai, marketing AI → ai.studio60.cz, REQ-001 draft; Libor schválil konvenci s60_ai_prod+s60_ai_prod_user místo navrhovaného s60_ai/s60ai_app; role LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE owner jen své DB; pgvector 0.8.2 CREATE EXTENSION superuserem (untrusted), otestován vector sloupec + <-> operátor; síť beze změny — UFW i pg_hba už kryjí celý Tailscale rozsah, pgBouncer wildcard → nová VPS (Hetzner, vzniká) se připojí rovnou, 6432 i 5432 end-to-end otestováno ze sentinelu; backup: přidána do s60-backup.sh (denní 04:30, retence 14d, backup skriptu .bak-20260705), testovací pg_dump jako s60admin OK, PITR kryje automaticky; db-mapping.md doplněn; credentials handover BLOKOVÁN — Runner API nezná s60ai jako příjemce (HTTP 400) → TODO kaizen T-20260705-009, pošlu inline po registraci) |
✅ | sentinel |
| 2026-07-04 | BillIt+BadWolf | prod ops (změna platformy) | Learnia řetěz přepnut na tenant INNER-SENSE (Liborův pokyn + nový ops klíč blt_c194... → /root/secrets/billit/webhook-ops-key-inner-sense.txt; starý studio-60 webhook fd6ce843 DELETE 204 — Pulse orders už badwolfu nechodí; nový webhook 440f4e40-6312-4d3a-a1bc-7f95cf14a20b tenant inner-sense, order.paid+order.created → api.studio60.cz/api/webhooks/billit; nový whsec vyměněn v badwolf prod env (backup .env.prod.bak-20260704-whsec2) + recreate hub-refresh→prod --skip-build, healthy R=0, env prefix ověřen; secrets agentům poslány INLINE relay zprávou (badwolf T-20260704-061) dle nového pravidla; Learnia WC webhook až po cms potvrzení pluginu — pak POD INNER-SENSE) |
✅ | sentinel |
| 2026-07-04 | BillIt | hub + prod (3. release dne) | 77ee095 (kód 6e1be2b — admin Systém health fix (stránka mířila na /admin/debug/status přes raw fetch s mrtvými ForwardAuth headers + double /v1 → api=error; nový BE GET /v1/admin/debug/health superadmin ping DB+Redis, FE přes api-client) + admin accept/reject pozvánky vendora z detailu účtu + CR-052 doplněk select-all scopes; BE+FE delta 6 souborů +117/−13, žádná migrace (billitova zpráva zase popisovala batch vůči stavu před mým deployem — mig 1772990000000 už live, „No pending"); hub: VERIFIED labely 2/2 napoprvé (BE+FE rebuild), QA 4/4 PASS; prod: čistý průběh bez race/workaroundu, VERIFIED labely 2/2, healthy R=0, QA 3/3 PASS, health 200) |
✅ | sentinel |
| 2026-07-04 | BillIt+BadWolf | prod ops (webhook wiring) | DES-004 Účto→BadWolf webhook LIVE (Learnia ops část 1 — Liborův pokyn + jeho ops klíč z CR-052 UI: /root/secrets/billit/webhook-ops-key.txt; starý HS256 runbook mrtvý po CR-021 → credential gap vyřešen CR-052 scope-pickerem; registrace: webhook id fd6ce843-04cf-4b3b-8a2e-07d0a727e3a3 tenant studio-60, events order.paid+order.created → api.studio60.cz/api/webhooks/billit (URL ověřena z badwolf kódu i živě); BILLIT_WEBHOOK_SECRET nasazen do badwolf prod containeru (env append + backup .env.prod.bak-20260704-whsec, recreate přes deploy.sh hub-refresh→prod --skip-build, healthy R=0, VERIFIED, badwolf QA nyní 4/4 i inline — qa syncnul testy) → HMAC verifikace aktivní, WEBHOOKS_FAIL_CLOSED ponechán open (flip = badwolf); pre-check: Pulse orders na studio-60 potečou badwolfu taky — handler items bez fulfillmentRef/type!=online_course ověřeně skipuje (žádný conflict spam); hub bez secretu (hub billit DB webhook řádek nemá); Learnia WC webhook záměrně NEregistrován — /wp-json/billit/v1/webhook na learnia.cz mrtvá (Express Cannot POST), DTO nemá is_active → deliveries z Pulse plateb by padaly; čeká cms plugin aktivace T-20260704-004, pak registrace + secret do /root/dev/.secrets/) |
✅ | sentinel |
| 2026-07-04 | BillIt | hub + prod (2. release dne) | 464ab01 (BUG-003 — Safari „The string did not match the expected pattern" toast u void endpointů (accept/reject/leave-platform), který Libor našel testem na produ; root cause api-client.ts volal resp.json() na prázdném těle (NestJS void POST = 201 empty) → fix číst text() + parsovat podmíněně, cross-browser; FE-only delta api-client +14/−4 + test + specs, žádná migrace („No pending", 67 zůstává); hub i prod: známý selective_recreate label false-positive (jen billit-web v selective → api držel 4bc882f) → --skip-build re-run → labely 2/2 VERIFIED, healthy R=0; served FE bundle ověřen hash změnou (hub v9ODT5QL→Ccde_UxT, prod →BqdtwWcQ), QA hub 4/4 + prod 3/3 PASS, ucto/health 200) |
✅ | sentinel |
| 2026-07-04 | BillIt | hub + prod | 4bc882f (REQ-055 inc5 + CR-052 — inc5 DROP deprecated (role odvozené z platform_vendor_links; api-keys guard; FE menu gating fix) + CR-052 FE api-keys form: výběr scopes + IP allowlist (odblokuje sentinel webhook ops) + CR-021 doklizení .env.example; migrace 1772990000000 DESTRUKTIVNÍ: DROP TABLE platform_invites CASCADE + DROP COLUMN tenants.type/platform_id/commission_rate, down()=best-effort → rollback = pre-upgrade dump; noční kontext: billitův SUPERSEDE T-20260704-002 („f734d52 by spadl — platform_invites chybí") byl PLANÝ POPLACH, sám odvolán T-20260704-006 (můj table list prokázal, že platform_invites na prod existuje) — f734d52 nasazen správně, nechán; paranoidní pre-check před DROPem: platform_invites na prod 0 řádků (drop ničí nic), links 8 (4→8 overnight, feature žije), tenants.default_commission_rate (fallback nového kódu) existuje; DRESS REHEARSAL (3. billit clone, fresh prod→hub 04:05 + scrub 9): DROP čistě, migrations 66→67, invites+3 sloupce pryč, 8 links intact, boot healthy, QA hub 4/4 PASS; prod: 1. běh ABORTED na známé docker race (Conflict container name billit-web hash-prefix, [[feedback_deploy_docker_race]]) PŘED migrací — kontejnery se samy zvedly, DB netknutá → re-run --skip-build čistě: migrace na živém produ, 67 migrací / invites 0 / sloupce 0 / 8 links = 1:1 s rehearsalem, labely 2/2 VERIFIED, healthy R=0, ucto/health 200, QA prod 3/3 PASS; pre-upgrade dump billit-dr3-20260704-040547/; NEXT: webhook ops odblokováno — Libor vytvoří v UI klíč read/write:webhooks + IP allowlist (sentinel), pak registrace Learnia WC + BadWolf webhooků (T-20260704-003/004)) |
✅ | sentinel |
| 2026-07-03 | BillIt | hub + prod (2. release dne) | f734d52 (batch 99ae78c — REQ-055 multi-platforma M:N (DEC-016, inc1-4: platform_vendor_links jako kanonická membership tabulka, commission per link, FE UI) + CR-051 webhook kontrakt (event vždy v těle payloadu — DES-004 Learnia; billit-wc jinak order.paid ignoroval, + odstranění dvojího doručení); 1 migrace 1772980000000 additivní + backfill; 🔍 PRE-DEPLOY RECON CHYTIL RELEASE BLOCKER: tabulka platform_vendor_links na hub+prod FYZICKY neexistovala, ale AddPlatformVendorLinks1772380000000 měla záznam v migrations (DB drift — tabulka někdy zmizela, záznam zůstal; archeologie = billit) → původní migrace 2113153 by spadla na ALTER TABLE … relation does not exist; Libor rozhodl variantu B = defenzivní migrace (billit 881e4d2: CREATE TABLE IF NOT EXISTS blok 1:1 se starou migrací vč. uq_platform_vendor UNIQUE nutného pro ON CONFLICT, před ALTER/backfill); DRESS REHEARSAL (2. dnes, fresh clone prod→hub 20:55 + scrub 9+1 tokenů): drift věrně nasimulován → migrace čistě, migrations 65→66, backfill přesně 4 linky status=active z tenants.platform_id, vendor_api_key NULL, commission NULL = věrné zdroji (0/4 tenantů má provizi), ownership app user, QA hub 4/4 PASS; prod identický s rehearsalem (66 migrací, 4 linky, constraint, ownership), oba containery VERIFIED healthy R=0, ucto/health 200, QA prod 3/3 PASS; pre-upgrade dump billit-dr2-20260703-205529/; staré sloupce (tenants.platform_id/platform_invites) ZŮSTÁVAJÍ jako rollback (DROP až REQ-055 inc5); Learnia ops (webhook config studio-60 → learnia.cz + Účto→BadWolf + secret handover) = samostatná akce, čeká Liborův pokyn + potvrzení URL od wp/cms a badwolf) |
✅ | sentinel |
| 2026-07-03 | S60 Pulse | hub + prod | 4c9bcb6 (release b81750b — CR-024 admin „Smazat klienta" v DETAILU klienta (type-to-confirm → existující DELETE /clients/:id), reálná delta = 1 soubor admin/src/pages/ClientDetail.tsx +41/−1; pulse baseline korekce: T-20260703-010 tvrdil „prod LIVE 3cc218c → b81750b" s mig 154 jako novou — REALITA: hub+prod běžely d8af612 (bundle CR-187+CR-209 vč. mig 154 CR209OrderGaClientId) od mého deploye 2026-06-30, ověřeno labely + migrations table (151, mig 154 applied) + orders.gaClientId existuje → žádná migrace nepoběžela („No pending" hub i prod), žádný nový env (GA4 klíče = Liborův krok, fail-soft od 6/30); dress rehearsal netřeba (čistá admin FE delta); hub: VERIFIED, labely 1/1, healthy R=0, QA gate 15/15 PASS (smoke 2 + regression 13), served admin bundle obsahuje CR-024 string 2× (Trvale smazat klienta), log erory = jen QA /error-tracking/* cesty (benigní); prod: VERIFIED, labely 1/1, healthy R=0, No pending, CR-024 string 2× v bundlu, 0 err v logu (10m), pulselab.cz 200 + /admin/ 200; pulse INFO s baseline korekcí T-20260703-024 (příští migration_from = d8af612/4c9bcb6, ne 3cc218c)) |
✅ | sentinel |
| 2026-07-03 | BillIt | hub + prod | 4c9b500 (batch HEAD e82af6e — BUG-001 platební race (tx + SELECT..FOR UPDATE + catch 23505 + becamePaid gate) + CR-050 fulfillmentRef (order_lines pass-through, DES-004) + auto-email URL fix (publicInvoiceUrl, řeší prod bug dev-URL v mailech) + BUG-002 split allocation (1 platba → N faktur, Σ ≤ tx.amount, stav partially_matched bez migrace, FE MatchingDialog split); 2 migrace 1772960000000 BUG001 dedup pre-step + partial unique index invoice_payments(invoice_id, external_id) WHERE external_id NOT NULL + 1772970000000 CR050 fulfillment_ref jsonb; DRESS REHEARSAL (clone prod→hub per pg-alfa-db-clone runbook): mirror bit-identický (19526 invoices / 61 payments / 63→65 migrations, ownership 44/44), dedup na reálných prod datech = 0 řádků (duplicity re-ověřeny 0 na čerstvém dumpu), index + sloupec ověřeny, boot healthy R=0; SECURITY scrub na hub clonu: 9× fio_api_token + 1× inbound_email_token → NULL (hub nesmí syncovat reálné bank tx / mailovat zákazníky; prod netknut); dumpy /var/lib/postgresql/billit-dr-20260703-055544/ (hub-pre-clone + prod); nasazeno 2 kroky: bb6e0cd (batch 41cde2c, BE-only → známý selective_recreate label false-positive billit-web → fix re-run --skip-build force-recreate, labely 2/2) → 4c9b500 (+BUG-002, FE+BE → labely 2/2 napoprvé), oba VERIFIED source-hash, migrace „No pending" na 2. běhu; QA gate: první běh FAILED 3× = stale fixtures, ne kód (.error→REQ-052 .code — prod starý kód vrací identický tvar; test tenant jen hub seed; X-User backdoor mrtvý od CR-033) → TODO qa T-20260703-011 → qa fix 1294c46 + sync stale hub kopií → genuine sentinel-local gate 4/4 PASS, STATUS OK, stamp zapsán (api-keys čistý SKIP do provisioningu QA klíče); FE served bundle ověřen (partially_matched v lazy chuncích constants+BankingPage, ne v index-.js — Vite route splitting); post-mirror dopady hlášeny billit T-20260703-012 (hub api_keys = prod hashe → pulse-hub integrace potřebuje re-provision, test tenant chybí); hub = prod-mirror + batch → prod deploy = identický efekt; PROD deploy (DEPLOY OK Libor ~07:38 UTC): pre-flight duplicity re-check 0 těsně před deployem + pre-upgrade dump prod-pre-upgrade-073729Z.dump (pg-alfa billit-dr-20260703-055544/), unannounced 1dfce1c na origin/master ověřen docs-only → nasazen rehearsovaný 4c9b500; prod gate OK (hub 06:29 v 2h okně + QA stamp 4/4), obě migrace na živém produ výsledek identický s rehearsalem: migrations 63→65, dedup 0 řádků (61→61 payments), unique index + fulfillment_ref jsonb ✓, oba containery VERIFIED 4c9b500 healthy R=0, FE chunky partially_matched ✓, ucto.studio60.cz/health 200 (0.046s), QA gate prod 3/3 PASS + 1 SKIP (api-keys čeká QA klíč) stamp zapsán; APP_URL stopgap ODSTRANĚN z .env.prod (Liborův pokyn ~07:50 UTC, backup .env.prod.bak-20260703-appurl) + redeploy --skip-build → container env bez APP_URL, APP_BASE_URL intact, healthy R=0, health 200 — thread T-20260702-023 uzavřen; follow-up deploy 6c5f966* (DEPLOY OK Libor hub+prod ~08:20 UTC): docs-only HEAD sync (5 commitů, 27 souborů vše docs/modules/*SPEC.md, kód identický s e82af6e) — hub QA 4/4 PASS → prod, oba env labely 2/2 VERIFIED healthy R=0, „No pending" migrace, QA prod 3/3 PASS, ucto/health 200 — repo HEAD = deployed commit srovnán) |
✅ | sentinel |
| 2026-06-18 | BillIt | prod nginx | DEC-014 301 ACTIVATED (billit.cz → ucto.studio60.cz path-preserving 301, na pokyn Libora — ostatní systémy pulse/badwolf/wp se dořeší zvlášť; swap billit.cz.redirect-DISABLED → sites-enabled/billit.cz, rollback originál v sites-available/billit.cz + /root/billit.cz.preredirect.bak; ⚠️ gotcha: backup omylem dán do sites-enabled → duplicitní server_name billit.cz, starý app blok přebíral / a /i/ (403/200 místo 301) → fix = přesun backupu MIMO sites-enabled; ověřeno /, /i/:token, /api/, hluboké cesty vše 301 → ucto, ucto cíl 200 bez smyčky; billit.cz/api teď taky 301 → integrace pulse/badwolf/wp na billit.cz/api se přesměrují (POST riziko) dokud se nepřepnou — Libor řeší; LP block billit.cz [[project_billit_lp_block]] tím superseded; fáze 2 (drop billit.cz DNS) = forge později na signál) |
✅ | sentinel |
| 2026-06-18 | BillIt | hub + prod | 53a9b79 (DEC-014 fáze B — env flip na ucto + space-fix; forward nad db5dec5 = +66739d0 docs +01ff63d kompletní odstranění public názvu BillIt→Studio60 Účto +53a9b79 brand name s mezerou; db_change none, žádné migrace; ENV FLIP hub+prod v secrets: APP_BASE_URL=https://ucto.studio60.cz (prod) / https://ucto.s60hub.cz (hub), MAIL_FROM=Studio 60 Účto <ucto@studio60.cz>, MAIL_REPLY_TO=ucto@studio60.cz, INBOUND_EMAIL_DOMAIN=in.billit.cz (dual-accept ponecháno) — Resend studio60.cz potvrzen Liborem, sender nově ucto@; space-fix title Studio 60 Účto — Fakturace jednoduše (s mezerou, předtím bez); hub VERIFIED labely 2/2 + QA gate PASSED 4/4, prod VERIFIED labely 2/2; title+/api/v1/config ověřeno hub+prod; billit.cz stále servíruje, 301 NEAKTIVNÍ (čeká na pulse/badwolf/wp base URL switch → pak forge 301 na pokyn); MAIL_FROM dán s diakritikou (brand forma); pozn. DEPLOY.md u commitu stále „fáze A" — db_change=none platí; qa upozorněn na title asserci „Studio 60 Účto" s mezerou) |
✅ | sentinel |
| 2026-06-18 | Vaultwarden | prod (single-env) | vaultwarden/server:latest (REQ-002 — nový interní password manager pass.studio60.cz na prod-alfa; oficiální image, non-git config projekt /root/projects/vaultwarden/; DB s60_vault_prod na pg-alfa 5432 direct (ne 6432 — Diesel prepared statements vs pgBouncer, jako n8n), schema public ownership na vault user (Diesel boot migrace → 29 tabulek); auth nativní per-user master heslo + Organization, SIGNUPS_ALLOWED=false invite-only, ORG_GROUPS_ENABLED=true, žádné SSO (REQ-002 Zamítnuto); SMTP přes Resend (smtp.resend.com:587, from vault@studio60.cz — studio60.cz verified) pro pozvánky; ADMIN_TOKEN plain v secrets (argon2 follow-up); nginx vhost + WS proxy (/notifications/hub) + LE cert HTTP-01 (do 2026-09-16); backup zapojen — DB do s60-backup.sh, volume vaultwarden-data do docker-volume-backup.sh (dump ověřen 29 tabulek); deploy.sh rozšířen (ADR-009): single-env služby (bez domains.staging) přeskakují hub-before-prod gate + non-git/official-image projekty přeskakují git pull a commit-hash verifikaci; akceptační kritéria REQ-002 1-9 ✅, #10 (klient) = Liborův test) |
✅ | sentinel |
| 2026-06-18 | BillIt | hub + prod | db5dec5 (DEC-014 fáze A — kódová příprava rebrandu billit.cz → ucto.studio60.cz: env-driven URL/domény + branding „Studio60 Účto" + dual-accept inbound; forward bundle nad deployed 96f04b1 = +f488f4f (CR-029 export sjednocení) +db5dec5 (DEC-014); db_change none, žádné migrace (No migrations pending); KRITICKÝ mail override nastaven hub+prod v secrets .env.{hub,prod}: MAIL_FROM=BillIt <fakturace@billit.cz> + MAIL_REPLY_TO=fakturace@billit.cz + INBOUND_EMAIL_DOMAIN=in.billit.cz (APP_BASE_URL ponechán billit.cz/billit.s60hub.cz) — dokud mail neověří Resend studio60.cz, jinak nový default sender ucto@studio60.cz → spam; hub VERIFIED commit+source hash, labely 2/2, QA gate PASSED 4/4 (api-keys regression), /api/v1/config inboundEmailDomain:in.billit.cz + signupMode:invite (CR-028 intact), container env override ověřen; prod VERIFIED labely 2/2, container env override potvrzen (žádný ucto@ leak), /api/v1/config OK, billit.cz API 200 (/ 403 = záměrný LP block); 301 redirect billit.cz→ucto PŘIPRAVEN ale NEAKTIVNÍ (billit.cz.redirect-DISABLED na prod-alfa, není v sites-enabled; čeká na Resend verify + billit env switch + Liborův pokyn; schválený plán: přechodný 301 → pak full retirement billit.cz)) |
✅ | sentinel |
| 2026-06-10 | S60 Pulse | hub + prod | cb34d99 (5596adc CR-187 GTM robust — app si bere GTM ID z backendu za běhu místo build-argu, robustnější + cb34d99 project filter fix — "Vše" tlačítko vždy zobrazené + reset stale filtru co skrýval výstupy; žádná migrace, code-only → bez dress rehearsal; hub→verify-boot→prod, oba env boot healthy Restart=0 (po 2aa51da DI crashi boot verifikace i u code-only), VERIFIED no race, health ok, LP 200, GTM render 2×; prod deploy po čekání na hub full completion (deploys.log zaznamenán → prod gate OK)) |
✅ | sentinel |
| 2026-06-08 | S60 Pulse | hub + prod | 46ef634 (abandonSession guard — completed session už nelze abandonovat (code prevence) + migrace 136 RepairAbandonedCompletedSessions data-repair: UPDATE sessions SET status='completed' WHERE status='abandoned' AND completedAt IS NOT NULL (sessions co byly dokončené ale omylem abandonované → vráceny na completed), RLS SET LOCAL, idempotentní; DRESS REHEARSAL (clone prod→hub): before-state na prod-mirroru = 6 sessions v nevalidním stavu (přesně co pulse hlásil) → mig 136 log "6 sessions completed→abandoned vráceno na completed" → after 0, scope sedí (přesně 6, nic navíc); boot healthy Restart=0 worker ACTIVE; prod deploy 46ef634 VERIFIED no race, boot healthy, mig 136 opravila 6→0 živých prod sessions, health ok; po prod restore hub na vlastní data; CI test OK) |
✅ | sentinel |
| 2026-06-08 | S60 Pulse | hub + prod | c45f1f2 (akumulovaný batch 2856441..c45f1f2, 6 commitů — CR-185 dynamický version footer (commit+build time; compose build.args GIT_COMMIT + nově BUILD_TIME správně), CR-187 GTM Consent Mode v2 + GTM v aplikaci + funkční purchase event (navazuje REQ-035 consent), backlog native dialogy styled+guard + QR mail SPD + footer migrace, error-review chat 413 hláška + rerender legacy→auto full regen; migrace 135 FixPricingFooterLogo = data migrace UPDATE page_templates SET template = REPLACE(template, OLD_FOOTER, NEW_FOOTER) (footer logo fix), RLS SET LOCAL, idempotentní (po replace OLD pryč → no-op); DRESS REHEARSAL (clone prod→hub, Libor vyžádal kvůli data migraci + po 2aa51da boot crashi): mig 135 na reálných prod templatech → log "footer → logo nahrazen v 1 stránkách: pricing", NEW logo /app/pulse-logo.png renderuje 3× na /p/pricing; KRITICKÉ boot ověření (po 2aa51da DI crashi): hub State=running Health=healthy Restart=0 worker ACTIVE bez "can't resolve"; prod deploy c45f1f2 VERIFIED no race, boot healthy (Restart=0, worker ACTIVE), mig 135 applied na s60_pulse_prod (footer nahrazen 1 stránka pricing), NEW logo 3×, /p/pricing 200, health ok; po prod restore hub na vlastní data → parity; CI test OK) |
✅ | sentinel |
| 2026-06-05 | S60 Pulse | hub + prod | 2856441 (CR-184 circular DI hotfix — nahrazuje crashed 2aa51da; obsahuje REQ-038 Phase 2 (consultation_feedback + non-charging isDemo) + CR-184 (worker failures → error_events); fix: TelegramQueue ↔ ErrorTrackingService circular dependency (CR-184 zavedl cyklus) rozbita přes ModuleRef lazy resolve — NEinjektuje ErrorTrackingService do konstruktoru, ale this.moduleRef.get(ErrorTrackingService, {strict:false}) v onModuleInit (po sestavení modulů); diff malý telegram.module +3 / telegram.queue +18, žádná migrace, code-only; KRITICKÉ ověření boot (CI DI crash nechytá): hub+prod oba State=running Health=healthy Restart=0 (žádný restart loop jako u 2aa51da), worker ACTIVE bez "can't resolve", VERIFIED, health ok, /p/pricing 200; hub-before-prod + boot verifikace na hubu PŘED prod = bezpečné; tím uzavřen incident 2aa51da boot crash) |
✅ | sentinel |
| 2026-06-05 | S60 Pulse | hub (ROLLBACK) | 2aa51da FAILED → rollback 51cc971 (REQ-038 Phase 2 consultation_feedback + non-charging isDemo + CR-184 worker failures→error_events; code-only no migrace; BOOT CRASH na hubu: container restart loop (502), NestJS DI error Nest can't resolve dependencies of the TelegramQueue (ConfigService, TelegramService, ?) — argument at index [2] not available in TelegramModule context — CR-184 přidal do TelegramQueue 3. závislost ale neimportoval/neregistroval modul co ji exportuje; CI gate to NECHYTL — unit testy s mock moduly nevalidují DI graf, chyba se projeví až za runtime NestFactory boot (návrh pulse: bootstrap/e2e smoke test app.init() do CI); hub-before-prod + čekání na hub FULL completion zabránilo prod výpadku — prod NEDOTČEN (zůstal 51cc971/CR-183 fix); recovery: deploy.sh pulse hub --commit 51cc971 (poslední funkční, 2aa51da bez migrace → DB čistá → rollback bezpečný) → hub VERIFIED health 200 obnoven; URGENT TODO pulse s přesným DI errorem + fixem; deploy 2aa51da držen blokovaný do opravy TelegramModule) |
❌→✅ rollback | sentinel |
| 2026-06-04 | S60 Pulse | hub + prod | 51cc971 (CR-183 PROD-CRITICAL FIX — generation worker pulse-output-gen padal na RLS [TenantScopedSubscriber] Refusing operation on tenant-scoped entity Output without tenant context → 41 failed jobů, zákazníci NEDOSTÁVALI výstupy (Lucie Bártová); worker běžel mimo HTTP request bez tenant kontextu (stejný RLS vzorec jako CR-177 v4 ale background worker); fix: tenantId do job dat (enqueue zachytí z request kontextu) + processJob wrap v runWithTenant; + REQ-038 MCP drive konzultace Phase 1 (agent jako klient) → migrace 134 REQ038SessionDriver (ALTER TABLE sessions ADD COLUMN IF NOT EXISTS driver TEXT NULL, schema-only idempotentní → dress rehearsal netřeba); batch NEbyl dev-deploynut (jen unit testy 1144/1144 + reviewer) → hub verify důležitější; hub deploy VERIFIED + mig 134 + worker ACTIVE bez RLS refusal na startu ověřeno PŘED prod; prod-gate hiccup: prod deploy poprvé BLOCKED ("Hub deploy je starší než 2 hodiny") — pustil jsem prod zatímco hub deploy ještě doběhával QA gate (nezaznamenán) → prod gate viděl starý hub timestamp; nic se nerozbilo (starý container běžel dál); po dokončení hub deploye re-run prod prošel; prod 51cc971 VERIFIED fresh container, mig 134 applied na s60_pulse_prod (sessions.driver), worker ACTIVE bez RLS, health ok; recovery 41 failed jobů + queue-clean = pulse doména (netriggeruju jejich debug API); baseline prod reálně bdc7d3c (mig 132+133 z mých deployů) → jen mig 134 nová) |
✅ | sentinel |
| 2026-06-04 | S60 Pulse | hub + prod | bdc7d3c (REQ-037 — editovatelné transakční email šablony, Phase 1 + DEC-012 + 7215b1b reopen prompt dialog UX fix; migrace 133 REQ037EmailTemplates = CREATE TABLE email_templates + RLS policy (vzor content_blocks/mig 098), DDL-only idempotentní, žádný data carry-over; seed 6 šablon (_layout + welcome/session-complete/order-created/payment-received/reopen-invitation) běží na app boot onModuleInit (create-only, RLS-safe); ZMĚNA CHOVÁNÍ: transakční maily teď přes editovatelné šablony, chybějící/disabled šablona → sendTemplated zaloguje+přeskočí (nespadne) ale mail nedojde → customer-facing riziko; DRESS REHEARSAL (Libor explicitně vyžádal kvůli mailům, i když migrace schema-only): clone prod→hub → mig 133 + boot seed na reálných prod datech → 6 šablon všech enabled (žádná missing/disabled → žádný tichý výpadek mailů); /p/pricing 200; Libor verify admin Maily na hubu PŘED prod; prod deploy bdc7d3c VERIFIED no race, mig 133 applied na s60_pulse_prod, 6 šablon všech 6 enabled (stejný výsledek jako rehearsal), /p/pricing 200, health ok; po prod restore hub na vlastní data; baseline korekce: prod reálně a84dfc2 (mig 132 z 2.6.), ne c636afe jak pulse psal → poběžela jen mig 133 (132 už applied — ověřeno na prod-mirroru); Ecomail provider Phase 1 GATED (Phase 2 = s60-mail integrace); CI 1135/1135) |
✅ | sentinel |
| 2026-06-02 | S60 Pulse | hub + prod | a84dfc2 (DEC-011 — sjednocení úložiště dat stránek do content_blocks (SSoT) + CR-179/180/181/182 + email fix + 619bc0f /auth/me vrací client.email pro /p/pricing checkout prefill; migrace 132 CR180PageDataToContentBlocks = data migrace carry-over page_templates.data → content_blocks (pricing 2 + metodiky 6 = 8 klíčů), UPSERT ON CONFLICT DO UPDATE (živá page.data → použij ji, jinak default), RLS SESSION-level SET pulse."tenantId" (NE SET LOCAL — incident mig 106); DRESS REHEARSAL (clone prod→hub, runbook pulse-hub-dress-rehearsal): migrace 132 na reálných prod datech → 8/8 klíčů carry-over + 🔴 kritický pricing_subtitle ruční prod fix ZACHOVÁN ("Kredity uplatníte na kteroukoli metodiku...") — to byla hlavní obava pulse že se nesmí ztratit; /p/pricing + /metodiky 200; Libor verify na hubu PŘED prod; prod deploy a84dfc2 VERIFIED no race, migrace 132 applied na s60_pulse_prod, 8/8 klíčů + pricing_subtitle zachován na produ (stejný výsledek jako rehearsal), /p/pricing + /metodiky 200, health ok; po prod restore hub na vlastní staging data + re-run migrace 132 → hub-prod parity; prod baseline byl reálně c2ec67e (můj předchozí deploy, pulse myslel c636afe; migrace ≤131 stejně → jen 132 nová); CI test OK 1130/1130) |
✅ | sentinel |
| 2026-06-01 | S60 Pulse | hub + prod | c2ec67e (CR-178 — systémová prevence RLS opakování v non-/api/ controllerech, 4 vrstvy: nový @TenantWrapped() decorator (tenant/tenant-wrapped.decorator.ts) auto-wrapne handler v runWithTenant + audit script audit-non-api-tenant-wrap.sh; hardening po CR-177 v4 (client_upsert RLS), ať se RLS context bug neopakuje v dalších non-/api/ routes (/auth/callback, /auth/me); CI gate incident: první pokus d9f1c0b BLOKOVÁN deploy.sh pre-build CI — 9 testů test/regression/req019-auth-me.spec.ts padalo, protože @TenantWrapped na me() vyžaduje injektovaný TenantContextService a test TestingModule ho neposkytoval (test-only, reálný controller injektuje na řádku 50 → runtime OK) → NEbypassoval jsem --skip-ci → TODO pulse → fix c2ec67e doplnil TenantContextService mock do testu; žádná migrace, code-only; hub+prod oba clean (žádný race), test... OK (CI zelené), c2ec67e VERIFIED, labely 1/1, health ok, /auth/error 200; deploy.sh CI gate prokázal hodnotu — chytil rozbitý test PŘED nasazením (i když runtime byl OK, zelené testy chci hlavně u /auth/me uprostřed auth incidentu)) |
✅ | sentinel |
| 2026-06-01 | S60 Pulse | hub + prod | c636afe (CR-177 v4 — root cause #2 registrační smyčky: po v3 (form-urlencoded) token exchange prošel, ale /auth/callback padal na client_upsert kvůli RLS — chyběl tenant context (klasický pulse SET LOCAL pulse."tenantId" vzorec); fix: wrap client_upsert v tenant contextu; žádná migrace, code-only; hub deploy clean VERIFIED; prod deploy hit docker race (removal already in progress → abort line 794, container hash-prefixed 45ba499302aa_s60-pulse Up healthy + alias OK ale ~7s starting + chybělo VERIFIED) → re-run --skip-build srovnal na čisté s60-pulse + VERIFIED + labely 1/1; oba env health ok /auth/error 200; incident registrační smyčky = 5 fixů celkem nasazeno (auth CR-004 cookie + pulse CR-177 v1 circuit breaker + v2 diagnostics + v3 form-urlencoded + v4 tenant context); finální repro auth/pulse v anon okně) |
✅ | sentinel |
| 2026-06-01 | S60 Pulse | hub + prod | 86f7ba7 (CR-177 v3 — ROOT CAUSE FIX registrační smyčky: exchangeCode v auth.service.ts posílal Content-Type: application/json + JSON body na POST /api/auth/token, ale S60Auth token endpoint (RFC 6749 §4.1.3, client_secret_post form parser) očekává application/x-www-form-urlencoded → dostával JSON → 400 invalid_request / 401 invalid_client → reason=auth_failed; fix: URLSearchParams form-urlencoded body; root cause potvrzen auth teamem (T-20260601-029 hypotéza) + pulse per-phase diagnostikou (CR-177 v2); žádná migrace, code-only (auth.service.ts 27 řádků); hub+prod oba clean (žádný docker race), s60-pulse VERIFIED, labely 1/1, health ok, /auth/error 200; incident registrační smyčky Pulse vyřešen kompletně: auth CR-004 (httpOnly cookie) + pulse CR-177 v1 (circuit breaker) + v2 (diagnostics) + v3 (form-urlencoded token exchange = root cause); finální potvrzení = auth/pulse repro registrace v anon okně) |
✅ | sentinel |
| 2026-06-01 | S60 Pulse | hub + prod | 1cf6edf (CR-177 v2 — per-phase error diagnostics v /auth/callback; po CR-177 v1 (3ffa282) prod registrace stále padá na reason=auth_failed (generický fallback) → v2 přidává per-fáze logging do callbacku, aby auth/pulse viděli KDE přesně exchange/login selhává; žádná migrace, code-only diagnostic; hub+prod deploy oba clean (žádný docker race tentokrát), s60-pulse VERIFIED source hash match, labely 1/1, health ok, /auth/error 200; incident registrační smyčky pořád otevřený — smyčka zastavená (CR-177 circuit breaker), ale samotný login flow stále failuje, root cause se diagnostikuje přes tyto logy) |
✅ | sentinel |
| 2026-06-01 | S60 Pulse | hub + prod | 3ffa282 (bundle b4e0f97..3ffa282 — CR-177 /auth/callback defense-in-depth = pulse-side companion k auth CR-004 (společně opravují Pulse registrační redirect smyčku): circuit breaker — nová @Get('error') route, při exchangeCode fail redirect na /auth/error?reason=<code> (NE /auth/login co re-inicializuje OAuth → smyčka), 5 reason kódů s CS texty, "Zkusit znovu" = manual click (user-initiated restart); idempotence Redis SET NX 60s TTL na oauth code → duplicitní code → error page; structured logging; + REQ-035 (48c6e43) dataLayer CookieScriptCategory- events + 4. functionality kategorie + app SPA consent banner (nová CookieConsentBanner.tsx pro /app); žádná migrace, code-only + client-dist rebuild; HUB DOCKER RACE incident: první hub deploy hit removal of container already in progress → deploy.sh abort exit 1 (ERR trap line 794) → container naběhl pod hash-prefixed jménem 11c1a05cd306_s60-pulse (Up healthy, network alias s60-pulse správně, /health ok po ~40s boot) ale ~40s 502 okno + chybělo VERIFIED/labely → re-run --skip-build přejmenoval na čistý s60-pulse + VERIFIED + labely 1/1 (znamý deploy.sh race z 2026-05-16, kandidát na fix); prod deploy clean* (žádný race) container s60-pulse VERIFIED, /auth/error 200 branded, health ok; oba env ověřeno /auth/error route + circuit breaker funguje) |
✅ | sentinel |
| 2026-06-01 | S60Auth | hub + prod | 76efeee (HEAD f601ca7; bundle 6c03148..76efeee — CR-004 CRITICAL httpOnly access_token cookie → OAuth authorize vidí SPA session → fix Pulse registrační redirect smyčky (aktivní incident, víc lidí hlásilo); REQ-041 GTM container per systém → migrace 1748000000000-AddGtmContainerId (ALTER TABLE systems ADD COLUMN gtm_container_id VARCHAR(20) NULL, forward-only, zero breaking, má down() DROP IF EXISTS); DES-001 admin rychlý přístup na dashboardu; GET /api/version (commit/buildTime/nodeEnv/uptime); Pulse theming; hub deploy VERIFIED + migrace executed (sloupec gtm_container_id v systems) + openid auth.s60hub.cz + backend/frontend health 200, prod deploy VERIFIED + migrace executed na s60_auth_prod + openid auth.studio60.cz + health 200; TypeORM migration:run přes deploy.sh; drobnost non-blocking: /api/version ukazuje commit:"unknown" — auth Dockerfile má ARG GIT_COMMIT=unknown ale docker-compose.yml nedeklaruje build.args:[GIT_COMMIT,BUILD_TIME] → deploy.sh env vars se do buildu nepropíšou; TODO auth doplnit build.args (observability, neblokuje CR-004); auth post-deploy repro registrace Pulse v anon okně) |
✅ | sentinel |
| 2026-06-01 | S60 Pulse | hub + prod | b4e0f97 (REQ-035 F1 CSS override fix — follow-up k 4593301 po Liborově visual review: banner titulky „Cookies ať Pulse pulzuje" + „Nastavení cookies" neviditelné (stejná barva jako podklad); root cause: inline <style> Pulse :root overrides byly PŘED CDN <link> cookieconsent.css → CDN defaults přepsaly přes cascade source order; fix: přesun style PO CDN link + !important na 30+ vars + explicit color:#ffffff!important na .cm__title/.pm__title/.pm__section-title; žádná migrace, čistě template; pulse ověřil na dev přes Puppeteer; hub+prod ověřeno: override style řádek 305 > CDN css 299 (PO CDN ✓), cm__title white 6×, oba VERIFIED health ok) |
✅ | sentinel |
| 2026-05-31 | S60 Pulse | hub + prod | 4593301 (REQ-035 F1 GDPR cookie consent banner — target 23dd1f7 base + 4593301 link fix; žádná migrace, čistě template change landing-page-template.ts; orestbida/cookieconsent v3.1.0 z jsDelivr CDN, Pulse orange brand styling, CS texty „Cookies ať Pulse pulzuje"/„Souhlasím se vším"; GDPR gating: GTM-5GJN6XLJ + Clarity (CR-173) přepnuty <script> → <script type="text/plain" data-category="analytics"> → CookieConsent aktivuje až po souhlasu, AutoClear regex _ga|_gid|_clck|...; dress rehearsal pattern (hub→verify) chytil bug PŘED prod: consent banner privacy link /p/privacy-policy = 404 (ten route prefix neexistuje), reálná stránka /legal/privacy (CR-164) → TODO pulse → fix 4593301 /p/privacy-policy→/legal/privacy; ověřeno hub i prod: banner→/legal/privacy 2× (200), /p/privacy-policy 0×, GTM gated 2×, ungated GTM 0×, consent 4×, health ok; hub+prod deploy VERIFIED source hash match; QA migration-audit false-positive (DEPLOY.md db_change=migration carryover, žádné nové migrace v bundlu) non-blocking) |
✅ | sentinel |
| 2026-05-31 | BillIt | hub + prod | c1a6d8d (bundle 5dc4b0b..c1a6d8d = 2 code commity, žádné nové migrace: 725ab47 CR-026 findAll subjectId filter (Faktury klienta v detailu vracely nic) + c1a6d8d REQ-029 self-vendor guard — createVendorSplitsFromIco přeskočí split když vendor.id === platform.id (platforma neprefakturuje sama sobě = DPH problém; quantum-academy bude platform i vendor); 793/793 testů zelená; selective_recreate label false-positive (memory feedback_selective_recreate_label_check) na obou env: bundle změnil jen billit-api → web container skipnut → drží starý 5dc4b0b label → sentinel label check FAIL 1/2 → workaround relabel re-run --skip-build (.deploy-commit==COMMIT → selective logika přeskočena → full recreate → labels 2/2 carry c1a6d8d); finální stav: oba env c1a6d8d VERIFIED source hash match, billit-api+web health 200, labels 2/2; QA hub smoke 2/2 + regression 2/2 PASS, jediný fail = migration-audit false-positive (DEPLOY.md db_change=migration ale 3 REQ-045 migrace už applied 24.5., žádné nové v bundlu); BillIt CR-001 onboarding kroky 2-3 zůstávají OTEVŘENÉ — tenant fibonacciproduction create + 5 API klíčů (innersense/betrue/ahaefekt/quantumflow/fibonacciproduction), čekají na Liborův explicit pokyn + proceduru od billitu) |
✅ | sentinel |
| 2026-05-31 | S60 Pulse | hub + prod | c509bbe (bundle 916b4b5..c509bbe — CR-172/173/174/175/176, migrace 124–131; iterativní release přes 6 dress rehearsalů na prod-mirroru, každá iterace chytila bug PŘED prod: 85523a9 base (CR-172 bypass-aware credit hold Helena overcharge, CR-173 GTM-5GJN6XLJ+Clarity wzk03k4whk runtime ENV v page.service, CR-174 hero_levels rename migrace 124, CR-175 LP CTAs migrace 125, CR-176 completion modal migrace 126) → d93dcc2 (CR-175 url fix) REHEARSAL CHYTIL: migrace 125 ON CONFLICT DO NOTHING na pre-existující klíč landing.outputs_more_cta_url (od 05-16, migrace 106) → url fix no-op → 6fcc33c migrace 127 cílená force-UPDATE (varianta A, Libor potvrdil target = YT playlist ...WQYon, ne pulse.s60hub.cz) → 39fe4a2 (CR-175 expand shorts+recenze migrace 128/129) REHEARSAL CHYTIL: migrace 129 append guard 6r2BEyfs-1I collision (Michaelin MCP obsah měl jiné youtube_id než pulse předpokládal: 04MqFr_iSzs/6r2BEyfs-1I/M5lBkE71piU ne WGujQYjL1L8/...) → append no-op + 2 duplicity → acf1334 migrace 130 REPLACE recenze na finálních 5 (spárováno s Michaelinými texty z debug API, Helena M5lBkE71piU→RGNiL4yZAHw nový kanál) → c509bbe CR-175 v3 (Libor hub review): outputs jen YT shorts 1:1 (smazán HTML web grid pl-outputs), migrace 131 REPLACE output_videos_items 3→5 + CLEAR outputs_description, server-side Fisher-Yates shuffle 3-z-N per request pro shorts i recenze; migrace 129 zůstává v repu jako no-op historie (guard collision, žádné poškození); hub deploy (6× iterace na prod-mirror) + prod deploy c509bbe VERIFIED (source hash match), health 200, oba env; PROD DB ověřeno: migrace 124-131 (8/8), outputs_cta=YT playlist, shorts=5, recenze=5, outputs_description="", brand-guide v5/10, completion=12, GTM render 2×, rotace per-request funguje; ENV GTM_CONTAINER_ID+CLARITY_PROJECT_ID přidány do .env.hub+.env.prod (runtime, non-blocking, default ''); po prod restore hub na vlastní staging data (185 sessions ≠ prod 192) + re-aplikace migrací → hub-prod parity; QA gate hub MAJOR 40/43 = chronicky pre-existing (pulse-outputs htmlPath/publicUrl + pulse-spec-output 404 + deploy-audit migration false-positive), žádná nová regrese napříč všemi iteracemi; dress rehearsal pattern prokázal hodnotu — 2× chytil migrace-vs-reálná-data bug který by na produ selhal tiše) |
✅ | sentinel |
| 2026-05-30 | S60 Pulse | hub + prod | 916b4b5 (bundle c8d40f3..916b4b5 = 4 commity — bb982b7 CR-167 hotfix #3 colorPalette.preferredColors[] by-index fallback v output.service (aditivní defensive), 72085c4 CR-170 brand-guide restore migrace 123 CR170BrandGuideRestore (merge v5 = v3 base + 10 YAML outputSections + outputTemplate, idempotent SET LOCAL pulse."tenantId" CR-141 RLS, archivuje active → aktivuje v5, má down()), d09941e DEPLOY.md bump, 916b4b5 CR-171 loosen STRICT validace persona-card required 7→['name','role'] + traits/pains/motivations minItems 1→0 + risk-summary/table/matrix/card-loop itemRequired→['name'], hex check zůstává STRICT — companion fix k CR-170 ať persona-typology sekce projde; CR-170+171 coupled: deploy jen 72085c4 by dal 9/10 sekcí, plný 916b4b5 → 10/10; bug: Anita brand-guide na produ vracela jen 2 sekce (prod v3 active = 2 sec), root cause commit b91fae4 2026-05-14 smazal YAML brand-guide (10 sekcí) → DB jako single source měla jen 2; DRESS REHEARSAL (runbook pulse-hub-dress-rehearsal.md): clone prod→hub (192 sessions/7067 msg/37 clients faithful, counts match) + migrace 123 na prod-mirror datech → v5 active/10 sec ověřeno, Libor ověřil Anita brand-guide regen 10/10 na hubu PŘED prod; hub deploy 06:52 UTC ✓ + prod deploy 07:05 UTC ✓ oba commit VERIFIED (source hash 6240ef5 match), sentinel label 1/1, /health 200, migrace 123 na boot (migrationsRun → explicitní migration:run "No pending"); DB ověřeno oba env: brand-guide v5 active sections=10, v1-v4 archived, CR170BrandGuideRestore1710000000123 v migrations table (hub 120, prod 120 rows); po prod deployi hub restored z rollback dumpu zpět na vlastní staging data (dump pořízen 07:00 po hub deployi → už obsahuje fix, v5/10 zachováno), hub-prod parity OK; deploy.sh WARN migration_from=bb982b7 ≠ last deployed c8d40f3 (pulse napsal špatný migration_from v DEPLOY.md, non-blocking, rozsah migraci pokrývá — TODO pulse fix); QA gate hub PATCH 13/16 = 2 chronicky pre-existing (pulse-outputs htmlPath/publicUrl + pulse-spec-output html/md 404, identicky FAILuje 05-25..05-29, nesouvisí s CR-170/171) + 1 deploy-audit migration false-positive (db_change=migration heuristic; migrace reálně v DB) non-blocking; rollback dumpy /tmp/dress-rehearsal-20260530/ na pg-alfa) |
✅ | sentinel |
| 2026-05-29 | S60 Pulse | hub + prod | c8d40f3 (code f548004; CR-167 hotfix #1+#2 + Bug C MD renderer; Bug A queue-stats 504 timeout fix (cae97c0): post-deploy verifikace CR-167 odhalila že nasazený new Queue() v debug.service vytvořil BullMQ connection BEZ REDIS_URL passwordu → 2min connection timeout → nginx 504; fix ioredis direct read llen/zcard/hgetall + bull:"jsonToMarkdown: Unknown block type: risk-matrix — falling back to placeholder", přidán renderer pro risk-matrix + risk-summary block (risks: name/type/probability/impact/description/prevention/contingencyPlan); 0 migrací, 0 env, 0 breaking, admin-only debug; hub deploy 04:02 UTC ✓ + verify (queue-stats response 51ms = no 504, queue-clean route 401 auth, no regression legal/LP), prod deploy 04:04 UTC ✓ container rev=c8d40f3 healthy, queue-stats 65ms na produ (Bug A confirmed gone), worker startup log "ACTIVE, concurrency=5, queue=pulse-output-gen" + AiQueueService "concurrency: 15"; smoke 401 learning: 401 auth challenge na endpoint pouze potvrzuje route registration ne handler funkčnost — Bug A v CR-167 byl maskovaný protože jsem unauth'd dostal 401 (auth middleware blokovala před handlerem), full validation vyžaduje auth'd call nebo dev agent post-deploy test (pulse plánuje GET queue-stats + POST queue-clean status=failed se svým debug key); QA gate hub PATCH 13/15 = známé pre-existing downstream (pulse-outputs htmlPath/publicUrl + pulse-spec-output 404) non-blocking; deploy proběhl s explicitním --commit c8d40f3 flagem (po včerejším learningu o positional arg); Bug D Anita risk-radar partial root cause = separate CR-169 návrh (AI občas vygeneruje risk bez type field → STRICT schema reject → partial), čeká Liborovo rozhodnutí, NENÍ v tomto deployi) |
✅ | sentinel |
| 2026-05-28 | S60 Pulse | hub + prod | 34acb76 (CR-167 c03d9a7 + CR-168 dev tooling 437e3e1/34acb76 — sync skript v scripts/sync-prod-to-dev.sh na prod neutrální, nevolá se; CR-167 motivace: prod 14 dní stats 10 completed / 5 failed_permanent (31% failure rate!) / 1 partial, všech 5 = "Watchdog stuck queued after 3 attempts" pattern: BullMQ job queued ale worker NIKDY nezpracoval (generationStartedAt=NULL, ai_events=0), force-regen sync path uspěl 5/6 → bug v queue worker flow ne v datech; 3 strukturální fixy: (A) Debug health monitoroval špatnou queue ai-conversation místo pulse-output-gen → vždy waiting:0,active:0 falešně OK, fix správný queue + counts via bullmq_output; (B) Background queue jobs nedělaly Sentry capture (žijí mimo HTTP request scope → GlobalExceptionFilter je nezachytí, GlitchTip 30 dní = 1 issue noise), fix worker.on('failed') + watchdog catch → Sentry.captureException, watchdog liveness → Sentry.captureMessage při worker DEAD; (C) Watchdog re-enqueue posílal collectedData: {} (self-defeating recovery), fix sessionRepo injection → load session.collectedData; nový endpoint GET /api/debug/queue-stats?queue=pulse-output-gen vrací posledních 20 failed jobs s reason + stacktrace + workerInfo; worker liveness cron 5min check waiting>5 + active=0 → Telegram + Sentry + logger.error "Worker DEAD"; worker startup log "ACTIVE" string verified na obou env ("worker ACTIVE, concurrency=5, queue=pulse-output-gen"); 0 migrací, 0 env změn, 0 breaking pro klienty; hub deploy 04:58 UTC ✓, prod deploy 05:03 UTC ✓ container rev=34acb76 healthy oba env, /health {status:ok,db:ok}, /api/debug/health + /api/debug/queue-stats 401 auth challenge na obou env (CR-167 routes registered), no regression na /legal/ ani LP /; deploy.sh arg-parsing finding*: pozičně 3. arg pro commit pin je IGNOROVÁN (deploy vždy HEAD), správně přes --commit <hash> flag — předchozí deploye fungovaly náhodou protože HEAD se shodoval; QA gate hub PATCH 13/15 pulse-outputs htmlPath/publicUrl + pulse-spec-output 404 = známé pre-existing downstream, non-blocking; out of scope CR-167: root cause proč worker nezpracoval (BullMQ/Redis bug) zůstává otevřený, řeší se po pozorování s novou viditelností) |
✅ | sentinel |
| 2026-05-28 | S60 Pulse | hub + prod | 902a9f2 (code 2b254a9; CR-165 — MD export fix + ClientDetail project grouping; Bug A user-facing: Helena prod měla 11/18 outputů MD = 263-422 B = jen nadpisy, root cause OutputService.jsonToMarkdown ignoroval section.blocks[] z CR-098 block-based skills; fix nová blockToMarkdown() zpracuje 22 block types (paragraph, persona-card, tone-comparison, table, color-wheel-v2, funnel-diagram, …) s fail-soft placeholder pro unknown, backward compat pro legacy CR-033 zachován; Bug B admin UI: ClientDetail Outputs tab teď grupuje per projekt přes SQL JOIN sessions→projects (projectId+projectName), FE OutputsTab groupBy projectId + per-project card s header, fallback "Bez projektu"; nový debug endpoint POST /api/debug/outputs/backfill-markdown?onlyBroken=true[&clientId= |
✅ | sentinel |
| 2026-05-25 | S60 Pulse | hub + prod | 7fca4e6 (code 074a5cf; bundle 0afd88a..074a5cf = 3 funkční commity + DEPLOY.md update — d809263 fix auth getAuthorizeUrl chyběl /api/auth/ prefix (REQ-039 register flow byl na prod DOA), a798c6e CR-163 LP Mísa redesign (orange brand, nové sekce Gift banner + FAQ, video reviews Katka/Zuzka/Helena 1:1 letterbox YT nocookie, pricing anchor boxy, mid-CTA "Za 30 minut máš plán", Fraunces italic accent), 074a5cf CR-164 legal pages /legal/privacy + /legal/terms MCP-editable + LP footer link visibility fix; 2 nové migrace 1710000000121-CR163LpMisaRedesign (UPSERT 58 landing. keys) + 1710000000122-CR164LegalPages (cleanup orphan section='legal' + INSERT 10 legal-privacy + 10 legal-terms keys), obě SET LOCAL pulse."tenantId" CR-141 RLS pattern idempotent, na obou env applied id 791/792 (běžely při bootstrap migrationsRun → deploy.sh migration:run hlásil "no pending"); prod byl na 0afd88a (před oběma CR) → obě migrace pending a applied; hub deploy 12:34 UTC ✓ + verify (legal 200/200/404, LP CR-163 sekce gift/faq/Fraunces/Mísa video all present, footer legal links visible), prod deploy 13:06 UTC ✓ container rev=7fca4e6 healthy, /health {status:ok,db:ok} oba env, legal routes + CR-163 LP sekce verified na prod; legal default content je GDPR Draft scaffold — vyžaduje právní revizi PŘED publish* (admin nahradí přes MCP/admin UI); architektonický invariant CR-164: section name MUSÍ matchnout page slug (2 sekce legal-privacy + legal-terms, ne jedna 'legal'); d809263 auth fix je client-side OAuth URL — nasazený, plně ověřitelný jen v prohlížeči; QA gate hub PATCH 13/16 (pulse-outputs htmlPath/publicUrl + pulse-spec-output 404 = známé pre-existing downstream, deploy-audit migration heuristic false-fail — ne regrese, non-blocking); npm audit 0 critical 2 high pre-existing; deploy.yml required-vars WARN AUTH_URL/CLIENT_ID/SECRET = stale var názvy, health OK) |
✅ | sentinel |
| 2026-05-24 | BillIt | hub + prod | 5dc4b0b (CR-026 follow-up — Money XML Druh/wrapper per documentType; ÚČETNÍ BUG nahlášený po předchozím deployi 12f72df: VŠECHNY faktury v Money S3 XML generovány jako Druh=F + SeznamZalPolozek + TypCeny → Money S3 interpretoval každou normální fakturu jako zálohovou; fix per-documentType matrix: invoice/tax_document → Druh=N + SeznamPolozek + CenaTyp + Doklad=number + per-line KodDPH, proforma → Druh=F + SeznamZalPolozek + TypCeny + Doklad=VS, correction → Druh=D + Dobropis=1; 3 nové unit testy v exports.service.spec.ts (suite 790/790), 0 nových migrací, selective_recreate jen billit-api; hub deploy 10:47 UTC primární běh label-mismatch false-positive (web container retained 12f72df labels protože selective_recreate ho přeskočil) → force-recreate billit-web override DEPLOY_ID billit-5dc4b0b-1779619651 + re-run hub deploy 10:52 UTC clean labels 2/2 ✓ → prod deploy 10:53 UTC stejný cycle → force-recreate prod web DEPLOY_ID billit-5dc4b0b-1779619984 → labels OK; /api/health 200 OK hub i prod, routes 401 auth challenge, no DB changes; deploy.sh selective_recreate vs sentinel label verification je known false-positive — workaround force-recreate skipped container po hlavním deployi, kandidát na patch v deploy.sh ať skip-by-design containers nevyhazují HEALTH_OK=false) |
✅ | sentinel |
| 2026-05-24 | BillIt | hub + prod | ff5c1a9 (DEPLOY.md commit 12f72df; bundle 9fa75ce..ff5c1a9 = 7 funkčních commitů + DEPLOY.md update — 3730b04 theme hard-lock na light, 4f57ab7 fakturoid emulator race fix custom_id idempotence, d895467 REQ-045 GAPs 1/2/4 dual-write interface (subjects/upsert + Idempotency-Key header + /message.json proxy), 2a2e901+ff5c1a9 CR-026 period exports + Fakturoid XML + Money S3 XML přepis + bank account join + Exporty v MobileTabBar; 3 nové TypeORM migrace 1772710000000-AddCustomIdUniqueIndex + 1772720000000-REQ045SubjectsUniqueIndexes + 1772730000000-REQ045InvoiceIdempotencyKey (všechny partial UNIQUE indexes), aplikovány na obou env (hub migrace id 94/95/96, prod id 81/82/83); pre-flight dup-check na obou DB → 0 duplicates na subjects.external_id / registration_no / custom_id i invoices.custom_id; hub deploy 07:57 UTC ✓, prod deploy 08:03 UTC ✓, oba clean recreate api+web, container healthy, .deploy-commit=12f72df verified, /api/health 200 OK, new routes (subjects/upsert, fakturoid/.../message.json, exports/invoices) registered → 401 auth challenge; BREAKING: Money S3 XML export schema přepsán na native Fakturoid Money (MoneyData/SeznamFaktVyd/FaktVyd) bez backward-compat shim, downstream consumers starého formátu se zlomí — Pulse nepoužívá; QA gate hub PATCH tier 4/5 (deploy-audit migration files heuristic false-fail — migrace v DB ✓, ne blocking); /api/health/deep na obou env degraded jen kvůli pre-existing config gaps (stripe placeholder, s60auth JWKS 404, no DO_SPACES_KEY, hub Redis WRONGPASS pre-existing) — NENÍ regrese z tohoto deploye; T-20260524-010 výtka billit agentovi za zastaralou DEPLOY.md → fix v 12f72df) |
✅ | sentinel |
| 2026-05-16 | S60 Pulse | hub + prod | d3b3387 (CR-148 docs: MCP overview help stránka 327 řádků pro Mísu+Radku — 13 kategorií ~50 MCP tools, copy-paste prompty pro typické edity LP; oprava landing-editor help text 4c19bb7 — odstraněno matoucí "dva storage backendy" tvrzení; client/public/help/admin/mcp-overview.md + landing-editor.md + Help.tsx route; bez migrací; deploy 10:30/34 UTC, oba env clean recreate) |
✅ | sentinel |
| 2026-05-16 | S60 Pulse | hub + prod | e4419b4 (DEPLOY.md sync 4c19bb7 po 3 hotfixes — CR-148 LP help "Jak to funguje" descriptions + outputs gap fix + URL routing chain; bez kódových změn vůči obsahu fbe4897, jen sync metadat; deploy 10:12/17 UTC, oba env clean) |
✅ | sentinel |
| 2026-05-16 | S60 Pulse | hub + prod | fbe4897 (3 URL routing hotfixy bez migrací: 0bd1b2c navigate()+Link to= /app/X → /X bug fix v bd4af36 — template literals zůstaly s starým prefixem; 5767f05 logo v app headeru vede na public LP /, ne /app; f84cd28 @ai-guide headers + dead code cleanup po URL uklidu — Landing.tsx 500 řádků odstraněn jako dead post SSR LP přechodu; deploy 09:00/05 UTC, oba env clean) |
✅ | sentinel |
| 2026-05-16 | S60 Pulse | hub + prod | e378fed (CR-148 URGENT URL uklid: 3c54bff /app/app → /app/ redirects + /m public + footer správné fakturační údaje + auth-aware CTAs na public LP / (LP for everyone); migrace 109 FooterCompanyInfo seed 4 footer.* keys s SET LOCAL pattern; client/src/App.tsx 44 řádků delta + page-seed/page.service/page.controller refactor; deploy 08:11/17 UTC, oba env clean) |
✅ | sentinel |
| 2026-05-16 | S60 Pulse | hub + prod | 7eadc05 (CR-148 LP fix: 72c2200 "Jak to funguje" step descriptions + outputs gap layout; migrace 108 LandingStepsDescriptionField seed 12 landing.steps_* keys s SET LOCAL pattern; client landing CSS + landing.steps content seed delta; deploy 07:28/55 UTC, hub clean run, prod docker race "removal already in progress" → ERR trap line 794 exit 1 — container Up healthy s hash-prefixed name d376166609a4_s60-pulse, container.RestartCount=0, image rebuilt 07:55, migrace 108 v migrations table 778; výsledek na obou env correct přes deploy.sh exit non-zero) |
✅ | sentinel |
| 2026-05-16 | S60 Pulse | hub + prod | 9b4dd17 (CR-148 Landing redesign mockup v2 plně MCP-editable + Baťa pricing 1/200, 6/900, 20/1900; migrace 106 LandingMcpEditableBlocks seed 70 landing. klíčů do content_blocks + 107 BataPriceUpdate UPDATE landing.pricing_packages / pricing.tiers / hero_price_label / price_per_credit; hub 502 ~30 min při migraci 106 RLS bugu — 148e41b mělo komentář ale chybělo SET LOCAL pulse."tenantId" před INSERT, fix v 6cfe392; deploy.sh silent-fail bug v selective-deploy detekci* — set -e + pipefail + grep-no-match exit 1 v ROOT_OR_COMPOSE=$(... | grep ... | head), fix || true + ERR trap pro loud failure; prod přeskok bez mezi-deployů z 8a7b7e5 → 9b4dd17, container Up 47s healthy, migrace 106+107 OK na obou env, 70 landing rows seed, Baťa pricing live; QA gate 13/16 (pulse-outputs htmlPath/publicUrl + pulse-spec-output 404 — downstream, ne deploy) → SKIP non-blocking) |
✅ | sentinel |
| 2026-05-15 | S60 Pulse | hub + prod | 8a7b7e5 (7bb8191 pool cascade fix save()→update(id) + findOne(sessionId) guard, dcdaf38 DEPLOY.md sync, c457a92 AiCostLogger RLS fix — TenantContext inject + SET LOCAL pulse.tenantId + tenantId column, 8a7b7e5 WELCOME_MESSAGES_SQL markdown trailing-comma + updatedAt column fix; kompletní dress rehearsal clone prod→hub→deploy→SQL→QA před prod chain, validoval že WELCOME_MESSAGES_SQL v původní verzi by selhal kvůli ne-existujícímu sloupci updatedAt v methodology_versions; SQL backfill v2 prod: pre_missing=4 → INSERT 0 4 chybějících greetings + UPDATE 3194 timestamps shift (assistant před first user msg), still_misordered=0; PRICING_UPDATE 4× UPDATE; WELCOME_MESSAGES 12× UPDATE; QA RELEASE 8/8 PASS, 0 FAIL na obou env; 0 výpadek; runbook docs/runbooks/pulse-hub-dress-rehearsal.md) |
✅ | sentinel |
| 2026-05-15 | S60 Pulse | hub | c457a92 (4 commits ahead 8570be5: 7bb8191 pool cascade fix save()→update(id) + findOne(sessionId) guard, dcdaf38 DEPLOY.md sync, c457a92 AiCostLogger RLS fix — TenantContext inject + SET LOCAL pulse.tenantId + tenantId column; SQL backfill v2 hub DB via SELECT set_config('pulse.tenantId', (SELECT id FROM tenants WHERE slug='pulse-marketing-lab'), false) workaround pro RLS — INSERT 3 chybějící greetings + UPDATE 3152 assistant timestamps posunuto před první user msg, still_misordered=0; první deploy 11:27 UTC nedokončil docker compose up (buffered output cut, container started=06:56 = předchozí 8570be5), retry 11:33 UTC OK; QA gate RELEASE tier 15/15 PASS, 0 FAIL — předchozí 6 fails (3 různých 500 v messages/dashboard/methodologies + greeting + 2 NOVÉ messages 500) vyřešeny tímto fixem) |
✅ hub-only | sentinel |
| 2026-05-15 | S60 Pulse | hub | 8570be5 (CR-145 ALS propagation pro fire-and-forget greeting callbacks — main agent commit pushnut bez vědomí pulse; fix NEDRŽEL — container řádek 212 stále messageRepo.save() original; FK_be15965a8de3e36645391e8c1ff violation v logs 06:58:51 + 07:03:58; QA gate RELEASE 6 fails: greeting+messages 3×+dashboard+methodologies; backfill v1 byl RLS no-op (s60_pulse_hub_user neviděl sessions bez SET pulse.tenantId); nahrazeno c457a92) |
⚠️ hub superseded | sentinel |
| 2026-05-15 | S60 Pulse | hub | 2b8bfee (hero PNG optimalizace pushnuta na origin — author commit Claude Main Agent, ne pulse → flag pro audit; 12× hero PNG 4–4.5 MB → 470–690 KB, −86 %; ověřeno wood-level3.png 4535624→660841 B; deploy-audit fix v fb0d532 součástí chainu; první deploy v 06:52 UTC nedokončil docker compose up (exit 0 ale buffered output cut), retry v 07:00 UTC OK; QA gate RELEASE tier 13/15 pass, 9 assertion failures ve 2 scripts: pulse-project-context.sh kompletně rozbitý (start/resumable/sessions, 8 fails) + pulse-session-lifecycle.sh first msg greeting; deploy.sh QA SKIP — no QA config, not blocking; čeká fix od pulse před prod) |
✅ hub-only | sentinel |
| 2026-05-14 | S60 Pulse | hub | d0b2407 (11 commits ahead 5b46529; CR-146 routing refactor + 3× CSS PDF fixy + PDF email attachment + ReviewPanel defensive + admin F2 responsive + NFR-006 F1 npm audit fix + LP komponenty Statistics/Gallery/Testimonials/Video + /api/public/stats endpoint + mobile output buttons; T-20260514-059 URGENT; bez nových migrací — "No migrations are pending"; QA gate 13/16 pass: pulse-project-context create test client FAIL, pulse-session-lifecycle first msg greeting FAIL, deploy-audit migration files mismatch FAIL — non-blocking (no QA config for s60-pulse), čeká fix od pulse před prod) | ✅ hub-only | sentinel |
| 2026-04-28 | BillIt | hub + prod | 1aa8dee (CR-022 Debug API self-service + CR-023 number-formats edit + DSN fix; T-20260428-166, migration CreateDebugConfig 1772650000000, secrets DSN UUID strip hyphens, debug_config 'global' OK na obou env) | ✅ | sentinel |
| 2026-04-27 | BillIt | hub + prod | 0c1e2db (fix(billit-web): banking page — show backend error + React Fragment key fix; T-20260427-481, žádné migrace, QA PATCH 4/4) | ✅ | sentinel |
| 2026-04-27 | S60 Pulse | hub + prod | dd2f7d7 (HOTFIX: TRIAL credits hold + admin UI creditCost editace; T-20260427-601, žádné migrace, QA RELEASE 15/15) | ✅ | sentinel |
| 2026-03-24 | BillIt | hub + prod | 127ae4b (CR-012: LP ceník Free 0/Starter 90/Pro 190, TenantPicker ?pick=1, ProfileSettings stránka; npm audit: 6 moderate lodash) | ✅ | sentinel |
| 2026-03-24 | BillIt | hub + prod | debe805 (CR-008: XLSX export, async export >1000 BullMQ, subjectId filter, ExportJob entity, migration AddExportJobs) | ✅ | sentinel |
| 2026-03-22 | S60Auth | hub + prod | 7236286 (REQ-032 diagnostics read-only GET /api/diagnostics/*; npm audit: 6 moderate) | ✅ | sentinel |
| 2026-03-20 | Gotenberg | hub + prod | gotenberg/gotenberg:8 | ✅ | sentinel |
| 2026-03-20 | S60 Pulse | hub + prod | 2a8a75e (mobile UX: cookie 30d, scroll fix, ghost text, Gotenberg PDF, feedback mailto) | ✅ | sentinel |
| 2026-03-20 | S60 Pulse | prod | 320d8c5 (admin impersonation, context sharing, collectedData + db5a2ea) | ✅ | sentinel |
| 2026-03-20 | S60 Pulse | hub | db5a2ea (severity validation fix, PDF emulateMediaType screen) | ✅ | sentinel |
| 2026-03-20 | S60 Pulse | hub | b41dbcf (feedback table migration) | ✅ | sentinel |
| 2026-03-19 | S60Auth | prod | 7cf35cb (redeploy, HC fix) | ✅ | sentinel |
| 2026-03-19 | qa-gate.sh | prod-alfa | — (scp) | ✅ | sentinel |
| 2026-03-18 | S60 Pulse | hub + prod | ff18e0e, 6f92678, 9236e13, 73c6ba7, 12be1d4 | ✅ | sentinel |
| 2026-03-18 | S60Auth | hub + prod | eaf2c06, 1b11c0d, 7cf35cb | ✅ | sentinel |
| 2026-03-18 | BillIt | hub + prod | 2b5fbe3, 5cce80f | ✅ | sentinel |
| 2026-03-17 | S60 Pulse | hub + prod | 41d2b0a, ff18e0e | ✅ | sentinel |
| 2026-03-11 | S60Auth | hub + prod (DB fix) | — | ✅ | sentinel |
| 2026-03-11 | N8N | hub-alfa + prod-alfa | n8nio/n8n:latest | ⚠️ SSL čeká na DNS | sentinel |
| 2026-03-11 | S60Mail | hub-alfa + prod-alfa | 908a90b (main) | ✅ | sentinel |
| 2026-03-11 | S60 Pulse | hub-alfa + prod-alfa | latest (master) | ✅ | sentinel |
| 2026-03-10 | S60Auth | prod-alfa | 25bf6d4 (master) | ✅ | sentinel |
| 2026-03-09 | S60Auth | hub-alfa | 25bf6d4 (master) | ✅ | sentinel |
Poznámky k deployům
2026-03-11 — S60 Pulse
Opraveny 3 problémy v Dockerfile (pulse agent notifikován):
npm ci→npm ci --legacy-peer-deps(4x) — ERESOLVE conflict@nestjs/testing@11vs@nestjs/common@10COPY --from=builder /app/admin/dist/→/app/admin-dist/— Vite buildí do parent directoryCOPY --from=builder /app/client/dist/→/app/client-dist/— totéž
2026-03-11 — S60Auth OAuth URL fix
BUG: Hub/prod auth DB byla zkopírována z dev. Tabulka systems měla všechny OAuth callback URL na s60dev.cz a localhost. Login z Pulse na prod redirectoval na dev.
Fix: Opraveny home_url a callback_url pro S60 Pulse:
- Hub:
pulse.s60hub.cz - Prod:
pulselab.cz
Venom, BillIt — stále dev URL, opraví se při jejich nasazení.
Přidáno do deploy procesu: kontrola OAuth URL v auth DB po každém deploy nové služby.
2026-03-11 — N8N
Nasazen na hub-alfa + prod-alfa. Kontejnery běží, nginx config ready. SSL čeká na DNS fix (infra agent požádán).
- DB: s60_n8n_hub + s60_n8n_prod (izolované)
- SMTP: Resend (smtp.resend.com:465)
2026-03-11 — S60Mail
Nasazen na hub-alfa + prod-alfa. Interní API (port 3010, bez veřejné domény).
- DB: s60_mail_hub + s60_mail_prod (izolované, NE sdílená s60_badwolf)
sslmode=requirev DATABASE_URL způsobuje SSL error — odstraněno- Tabulka
email_templatesvytvořena ručně (mail agent notifikován — přidat migrace do repo)
2026-03-18 — S60 Pulse (5 deployů)
Iterativní opravy a nové features:
- 6f92678 — PDF fix, cross-context collectedData
- 9236e13 — PDF fix #2
- 73c6ba7 — PDF light theme, trial kredity
- 12be1d4 — verzování metodik, workshop chat, DB migrace (methodology_versions)
- ff18e0e — PDF blank output fix + output URL migration
2026-03-18 — S60Auth (3 deploye)
eaf2c06— logout whitelist fix (CORS)1b11c0d— DB migrace (missing columns: marketing_html, purchase_url, is_favorite aj.)7cf35cb— Docker healthcheck přidán do compose
Incident F-338: Google OAuth padal kvůli chybějícím DB sloupcům. Fix = ALTER TABLE + restart.
2026-03-18 — BillIt (2 deploye)
2b5fbe3,5cce80f— opravy po prod nasazení
2026-03-17 — S60 Pulse
41d2b0a— spec systemff18e0e— PDF blank output + output URL migration (fix-output-urls.sql na hub+prod)
2026-03-09–10 — S60Auth
- Forward-auth kontejner se NEPOUŽÍVÁ — spouštět pouze
s60-auth-backendas60-auth-frontend - Google OAuth credentials vyžadují callback URL v Google Console
docker compose down && up -dpovinně (env_file se načítá jen při vytvoření kontejneru) | 2026-03-19 07:05 UTC | s60-auth | prod |7cf35cb| feat: Docker healthcheck pro backend + frontend [Kaizen F-340] | ✅ done (qa=skipped) | | 2026-03-20 04:11 UTC | s60-pulse | prod |a312e7a| fix: migration 1710000000002 — create feedback table (F-403) | ✅ done (qa=skipped) | | 2026-03-20 05:23 UTC | s60-pulse | hub |b41dbcf| feat: admin impersonation, context sharing fix, collectedData in API | ✅ done (qa=skipped) | | 2026-03-20 06:01 UTC | s60-pulse | prod |320d8c5| feat: admin impersonation, context sharing fix, collectedData in API | ✅ done (qa=skipped) | | 2026-03-20 12:19 UTC | s60-pulse | hub |6e9ba7d| feat: collectedData-driven AI context, public output URL wrapper | ✅ done (qa=skipped) | | 2026-03-20 12:26 UTC | s60-pulse | prod |6e9ba7d| feat: collectedData-driven AI context, public output URL wrapper | ✅ done (qa=skipped) | | 2026-03-20 18:48 UTC | s60-pulse | prod |2a8a75e| fix: mobile UX — persistent login, scroll fix, input ghost text | ✅ done (qa=skipped) | | 2026-03-20 19:11 UTC | s60-pulse | prod |2a8a75e| fix: mobile UX — persistent login, scroll fix, input ghost text | ✅ done (qa=skipped) | | 2026-03-22 08:37 UTC | s60-pulse | hub |6c99b82| docs(pulse): add complete spec catalog — REQ, DES, CR, CON, NFR specs | ⚠️ fail (qa=skipped) | | 2026-03-22 08:46 UTC | s60-pulse | prod |6c99b82| docs(pulse): add complete spec catalog — REQ, DES, CR, CON, NFR specs | ✅ done (qa=skipped) | | 2026-03-22 09:14 UTC | s60-pulse | hub |786f48c| test(pulse): REQ-017 — integration tests pro pricing (checkout, admin purchase, stats, transactions) | ✅ done (qa=skipped) | | 2026-03-22 15:38 UTC | s60-auth | hub |7236286| feat(auth): REQ-032 — diagnostics read-only endpoints | ✅ done (qa=skipped) | | 2026-03-22 15:42 UTC | s60-pulse | prod |4462e58| feat(pulse): REQ-029 — readonly debug API s dvouvrstvou autorizací | ✅ done (qa=skipped) | | 2026-03-22 15:47 UTC | s60-pulse | hub |4462e58| feat(pulse): REQ-029 — readonly debug API s dvouvrstvou autorizací | ✅ done (qa=skipped) | | 2026-03-22 17:18 UTC | s60-pulse | prod |bfe405b| fix(pulse): CR-003 — collectedData JSONB persistence bug + self-repair | ✅ done (qa=skipped) | | 2026-03-22 17:24 UTC | s60-pulse | hub |bfe405b| fix(pulse): CR-003 — collectedData JSONB persistence bug + self-repair | ✅ done (qa=skipped) | | 2026-03-22 18:30 UTC | s60-pulse | prod |c33d32c| fix(pulse): ACTIVE sessions viditelné v klientském UI | ✅ done (qa=skipped) | | 2026-03-22 18:32 UTC | s60-pulse | hub |c33d32c| fix(pulse): ACTIVE sessions viditelné v klientském UI | ✅ done (qa=skipped) | | 2026-03-23 03:37 UTC | billit | hub |bcd8d32| fix: bind docker ports to 127.0.0.1 + fix billit-api HC localhost→127.0.0.1 | ✅ done (qa=skipped) | | 2026-03-23 05:21 UTC | billit | prod |4fea85f| fix(security): resolve npm audit HIGH vulnerabilities | ✅ done (qa=skipped) | | 2026-03-24 04:37 UTC | billit | hub |debe805| feat(billit): CR-008 — XLSX export, subjectId filter, async export >1000 | ✅ done (qa=skipped) | | 2026-03-24 04:39 UTC | billit | prod |debe805| feat(billit): CR-008 — XLSX export, subjectId filter, async export >1000 | ✅ done (qa=skipped) | | 2026-03-24 05:38 UTC | s60-pulse | hub |dc59e11| feat(pulse): CR-006 + BUG#1 — finish flow + JSON endpoint fix | ✅ done (qa=skipped) | | 2026-03-24 11:05 UTC | s60-pulse | hub |541c2a7| fix(pulse): replace client.tier with client.subscription, fix never[] type [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-24 11:45 UTC | s60-pulse | prod |541c2a7| fix(pulse): replace client.tier with client.subscription, fix never[] type [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-24 12:34 UTC | s60-pulse | hub |7634e01| feat(pulse): CR-013 — Kategorie UX redesign + visibility flag | ✅ done (qa=skipped) | | 2026-03-24 12:35 UTC | s60-pulse | prod |7634e01| feat(pulse): CR-013 — Kategorie UX redesign + visibility flag | ✅ done (qa=skipped) | | 2026-03-26 07:20 UTC | s60-pulse | hub |8ce2887| fix(pulse): slugify strips diacritics instead of replacing with dashes [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 07:29 UTC | s60-pulse | prod |8ce2887| fix(pulse): slugify strips diacritics instead of replacing with dashes [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 08:15 UTC | s60-pulse | prod |a81febc| fix(pulse): disable synchronize — always false, migrations only [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 08:20 UTC | s60-pulse | hub |a81febc| fix(pulse): disable synchronize — always false, migrations only [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 08:25 UTC | s60-pulse | prod |0593344| fix(pulse): migration to fix broken diacritical slugs + synchronize:false [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 08:31 UTC | s60-pulse | hub |0593344| fix(pulse): migration to fix broken diacritical slugs + synchronize:false [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 08:37 UTC | s60-pulse | hub |0593344| fix(pulse): migration to fix broken diacritical slugs + synchronize:false [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 09:32 UTC | s60-pulse | hub |6bbb452| feat(pulse): debug API endpoints for methodologies, categories, metadata, versions [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 09:35 UTC | s60-pulse | prod |3aaa1c2| fix(pulse): fix test failures from isDefault + spec-structure after debug module addition | ✅ done (qa=skipped) | | 2026-03-26 09:39 UTC | s60-pulse | hub |3aaa1c2| fix(pulse): fix test failures from isDefault + spec-structure after debug module addition | ✅ done (qa=skipped) | | 2026-03-26 10:02 UTC | s60-pulse | prod |64ce3bf| fix(pulse): admin sees hidden categories + methodologies in client UI [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 10:07 UTC | s60-pulse | hub |64ce3bf| fix(pulse): admin sees hidden categories + methodologies in client UI [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 10:29 UTC | s60-pulse | prod |9c97e29| fix(pulse): migrate draft-only methodologies to active [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 10:33 UTC | s60-pulse | hub |9c97e29| fix(pulse): migrate draft-only methodologies to active [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 10:41 UTC | s60-pulse | hub |9c97e29| fix(pulse): migrate draft-only methodologies to active [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 11:37 UTC | s60-pulse | prod |b984a0d| fix(pulse): output filesystem fallback — recreate files from DB when missing [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 11:41 UTC | s60-pulse | hub |b984a0d| fix(pulse): output filesystem fallback — recreate files from DB when missing [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 11:42 UTC | s60-pulse | hub |b984a0d| fix(pulse): output filesystem fallback — recreate files from DB when missing [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 14:13 UTC | billit | hub |b78c395| feat(billit-wc-plugin): initial commit — WooCommerce payment gateway + fixes | ✅ done (qa=skipped) | | 2026-03-26 14:26 UTC | s60-pulse | hub |4192a53| feat(pulse): CR-014 — all client pages use dynamic methodology meta from API | ✅ done (qa=skipped) | | 2026-03-26 14:27 UTC | billit | hub |883df6b| test(billit-wc-plugin): verify_signature() — 7 cases incl. sha256= prefix strip [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 14:57 UTC | s60-pulse | hub |3cbb5d4| fix(pulse): CR-014 — wire ContentEditor to actual AI chat endpoint [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 14:58 UTC | s60-pulse | hub |3cbb5d4| fix(pulse): CR-014 — wire ContentEditor to actual AI chat endpoint [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 16:21 UTC | s60-pulse | hub |5d0cc37| fix(pulse): AI content chat — detailed info where each field is displayed [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-26 19:57 UTC | s60-pulse | hub |92eba2b| fix(pulse): CR-014 — route ordering fix + chat persistence [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 05:05 UTC | s60-pulse | hub |98f33e1| feat(pulse): download plain text transcript of conversation [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 05:13 UTC | s60-pulse | prod |98f33e1| feat(pulse): download plain text transcript of conversation [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 06:10 UTC | s60-pulse | hub |0cef520| feat(pulse): CR-016 — tooltips on all icon-only buttons in admin UI | ✅ done (qa=skipped) | | 2026-03-27 06:48 UTC | s60-pulse | hub |d86c229| fix(pulse): CR-016 — LP shows categories + better duration estimate [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 07:03 UTC | s60-pulse | hub |92abda4| fix(pulse): AI content chat loads actual methodologies dynamically [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 07:12 UTC | s60-pulse | hub |ac4efa7| fix(pulse): "Nový chat" button in Content Editor with confirmation [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 07:46 UTC | s60-pulse | hub |f6529f6| fix(pulse): AI chat now actually interpolates methodology list into prompt [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 08:04 UTC | s60-pulse | hub |962bba8| fix(pulse): content chat auto-creates missing keys + merges partial drafts [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 08:21 UTC | s60-pulse | hub |89023e4| fix(pulse): null-safe array access on detail pages — prevents crash on partial meta [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 08:45 UTC | s60-pulse | hub |301ff09| fix(pulse): route collision fix + smart preview URL [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 10:09 UTC | s60-pulse | prod |edd7ce6| fix(pulse): auto-redirect to existing session on duplicate start [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 10:10 UTC | s60-auth | hub |7a56ffc| feat(auth): REQ-033 — grant_type=refresh_token na POST /api/auth/token | ✅ done (qa=skipped) | | 2026-03-27 10:13 UTC | s60-auth | prod |686552b| feat(auth): REQ-033 — add refresh_token to OIDC discovery grant_types_supported | ✅ done (qa=skipped) | | 2026-03-27 10:18 UTC | s60-pulse | hub |edd7ce6| fix(pulse): auto-redirect to existing session on duplicate start [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 10:25 UTC | s60-auth | hub |686552b| feat(auth): REQ-033 — add refresh_token to OIDC discovery grant_types_supported | ✅ done (qa=skipped) | | 2026-03-27 10:27 UTC | s60-auth | prod |686552b| feat(auth): REQ-033 — add refresh_token to OIDC discovery grant_types_supported | ✅ done (qa=skipped) | | 2026-03-27 12:37 UTC | badwolf | prod |af30c56| docs: rename be. → api. across all docs and deploy config | ✅ done (qa=skipped) | | 2026-03-27 12:43 UTC | badwolf | hub |af30c56| docs: rename be. → api. across all docs and deploy config | ✅ done (qa=skipped) | | 2026-03-27 13:39 UTC | s60-auth | prod |0122eb6| fix(auth): allow name in UpdateSystemDto — fixes "property name should not exist" [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 13:41 UTC | s60-auth | hub |0122eb6| fix(auth): allow name in UpdateSystemDto — fixes "property name should not exist" [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 13:43 UTC | s60-auth | prod |0122eb6| fix(auth): allow name in UpdateSystemDto — fixes "property name should not exist" [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 13:47 UTC | s60-auth | hub |0122eb6| fix(auth): allow name in UpdateSystemDto — fixes "property name should not exist" [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 14:00 UTC | s60-auth | hub |25ee400| test(systems): UpdateSystemDto validation — regression test pro name field | ✅ done (qa=skipped) | | 2026-03-27 14:02 UTC | s60-auth | prod |25ee400| test(systems): UpdateSystemDto validation — regression test pro name field | ✅ done (qa=skipped) | | 2026-03-27 14:17 UTC | s60-auth | hub |d48aebf| fix(auth): pass OAuth context through social login callback to frontend [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 14:20 UTC | s60-auth | prod |d48aebf| fix(auth): pass OAuth context through social login callback to frontend [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 14:31 UTC | s60-auth | hub |d48aebf| fix(auth): pass OAuth context through social login callback to frontend [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 14:33 UTC | s60-auth | prod |d48aebf| fix(auth): pass OAuth context through social login callback to frontend [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 16:38 UTC | s60-auth | hub |d48aebf| fix(auth): pass OAuth context through social login callback to frontend [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 16:40 UTC | s60-auth | prod |3a6ed02| fix(auth): encode state param in Register.tsx loginParams href [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 16:48 UTC | s60-auth | hub |2f24eff| fix(auth): Register.tsx state encoding + Authorize.tsx graceful error fallback [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 16:54 UTC | s60-auth | hub |3a6ed02| fix(auth): encode state param in Register.tsx loginParams href [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 16:55 UTC | s60-auth | prod |3a6ed02| fix(auth): encode state param in Register.tsx loginParams href [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 16:56 UTC | s60-pulse | prod |6d0f750| fix(pulse): graceful AI overload handling — retry + revert session [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 17:05 UTC | s60-pulse | hub |6d0f750| fix(pulse): graceful AI overload handling — retry + revert session [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 17:06 UTC | s60-auth | hub |3a6ed02| fix(auth): encode state param in Register.tsx loginParams href [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 17:08 UTC | s60-auth | prod |3a6ed02| fix(auth): encode state param in Register.tsx loginParams href [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 17:26 UTC | s60-auth | hub |3a6ed02| fix(auth): encode state param in Register.tsx loginParams href [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 17:28 UTC | s60-auth | prod |3a6ed02| fix(auth): encode state param in Register.tsx loginParams href [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 19:16 UTC | s60-pulse | prod |83e41b5| fix(pulse): increase output generation token limit 8192 → 16384 [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 19:20 UTC | s60-pulse | prod |42b5a4e| fix(pulse): replace native confirm() with proper dialog for completed methodology [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 19:26 UTC | s60-pulse | hub |83e41b5| fix(pulse): increase output generation token limit 8192 → 16384 [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 19:29 UTC | s60-pulse | hub |42b5a4e| fix(pulse): replace native confirm() with proper dialog for completed methodology [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-27 19:30 UTC | s60-pulse | hub |42b5a4e| fix(pulse): replace native confirm() with proper dialog for completed methodology [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 08:45 UTC | s60-auth | hub |5a45dcd| fix(auth): accept ?redirect= and ?redirect_uri= as aliases for logout [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 08:47 UTC | s60-auth | prod |5a45dcd| fix(auth): accept ?redirect= and ?redirect_uri= as aliases for logout [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 12:47 UTC | s60-auth | prod |0700f2b| fix(auth): GET logout prochází frontend /logout page — čistí localStorage [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 12:51 UTC | s60-auth | hub |0700f2b| fix(auth): GET logout prochází frontend /logout page — čistí localStorage [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 12:52 UTC | s60-auth | prod |0700f2b| fix(auth): GET logout prochází frontend /logout page — čistí localStorage [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 12:55 UTC | s60-auth | hub |0700f2b| fix(auth): GET logout prochází frontend /logout page — čistí localStorage [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 13:05 UTC | s60-auth | hub |0700f2b| fix(auth): GET logout prochází frontend /logout page — čistí localStorage [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 13:06 UTC | s60-auth | prod |0700f2b| fix(auth): GET logout prochází frontend /logout page — čistí localStorage [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 13:21 UTC | badwolf | hub |e1d7d0c| feat(health): add version (git commit hash) to health endpoint [no-spec] | ✅ done (qa=skipped) | | 2026-03-28 13:23 UTC | venom | prod |b87bda9| feat: add /version endpoint with build metadata (commit, branch, buildTime) | ✅ done (qa=skipped) | | 2026-03-28 13:24 UTC | badwolf | prod |e1d7d0c| feat(health): add version (git commit hash) to health endpoint [no-spec] | ✅ done (qa=skipped) | | 2026-03-28 13:31 UTC | venom | hub |b87bda9| feat: add /version endpoint with build metadata (commit, branch, buildTime) | ✅ done (qa=skipped) | | 2026-03-28 13:31 UTC | badwolf | hub |e1d7d0c| feat(health): add version (git commit hash) to health endpoint [no-spec] | ✅ done (qa=skipped) | | 2026-03-28 13:45 UTC | billit | hub |c6efa99| fix(billit): add missing formatMoney export to format.ts [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 13:48 UTC | billit | prod |c6efa99| fix(billit): add missing formatMoney export to format.ts [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 14:17 UTC | billit | prod |c6efa99| fix(billit): add missing formatMoney export to format.ts [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 14:25 UTC | billit | hub |c6efa99| fix(billit): add missing formatMoney export to format.ts [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 14:28 UTC | s60-auth | hub |05e9347| fix(auth): encode state param in Register.tsx loginParams href [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 14:29 UTC | s60-auth | prod |05e9347| fix(auth): encode state param in Register.tsx loginParams href [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 15:10 UTC | billit | hub |87a1d3f| fix(billit): Dockerfile — use npm install instead of npm ci, Node 22 | ✅ done (qa=skipped) | | 2026-03-28 15:19 UTC | billit | prod |5200771| fix(billit): remove @s60/eslint-plugin-ai-docs file dep — unblocks Docker build [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 15:26 UTC | billit | hub |5200771| fix(billit): remove @s60/eslint-plugin-ai-docs file dep — unblocks Docker build [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 15:27 UTC | billit | hub |5200771| fix(billit): remove @s60/eslint-plugin-ai-docs file dep — unblocks Docker build [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 15:27 UTC | billit | prod |5200771| fix(billit): remove @s60/eslint-plugin-ai-docs file dep — unblocks Docker build [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 15:42 UTC | billit | hub |5200771| fix(billit): remove @s60/eslint-plugin-ai-docs file dep — unblocks Docker build [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 15:44 UTC | billit | prod |5200771| fix(billit): remove @s60/eslint-plugin-ai-docs file dep — unblocks Docker build [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 16:02 UTC | billit | hub |5200771| fix(billit): remove @s60/eslint-plugin-ai-docs file dep — unblocks Docker build [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 16:04 UTC | billit | prod |5200771| fix(billit): remove @s60/eslint-plugin-ai-docs file dep — unblocks Docker build [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 16:37 UTC | billit | hub |5200771| fix(billit): remove @s60/eslint-plugin-ai-docs file dep — unblocks Docker build [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 16:39 UTC | billit | prod |5200771| fix(billit): remove @s60/eslint-plugin-ai-docs file dep — unblocks Docker build [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 17:40 UTC | badwolf | prod |53d2e47| fix(badwolf): migration 023 — applications table + deleted_at on clients/course_dates + 021 tables on prod-alfa [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 20:18 UTC | s60-pulse | prod |36529f7| fix(pulse): use --ignore-scripts instead of HUSKY=0 in prod stage | ✅ done (qa=skipped) | | 2026-03-28 21:13 UTC | badwolf | hub |a682d7c| test(cors): add e2e tests for CORS allowed origins [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 21:14 UTC | badwolf | prod |a682d7c| test(cors): add e2e tests for CORS allowed origins [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 21:25 UTC | badwolf | hub |a682d7c| test(cors): add e2e tests for CORS allowed origins [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-28 21:26 UTC | badwolf | prod |a682d7c| test(cors): add e2e tests for CORS allowed origins [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 04:48 UTC | badwolf | hub |a682d7c| test(cors): add e2e tests for CORS allowed origins [no-spec bugfix] | ⚠️ fail (qa=skipped) | | 2026-03-29 05:05 UTC | billit | hub |40b4de9| fix(billit): webhook learning on order create, notification triggers, admin email whitelist | ✅ done (qa=skipped) | | 2026-03-29 05:20 UTC | billit | hub |e589167| test(billit): 197 tests passing — new suites + fixes for all modules | ✅ done (qa=skipped) | | 2026-03-29 05:22 UTC | billit | prod |e589167| test(billit): 197 tests passing — new suites + fixes for all modules | ✅ done (qa=skipped) | | 2026-03-29 05:39 UTC | badwolf | hub |feae93d| fix(online-courses): add basePriceCzk/Eur to entity + wcSite filter [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 06:03 UTC | venom | hub |73ed695| fix(orders): opravit React error #31 — sourceDetail JSONB objekt + clientId TS chyby | ✅ done (qa=skipped) | | 2026-03-29 06:04 UTC | venom | prod |d736c82| feat(products): REQ-001 draft — site filter + client-side workaround | ⚠️ fail (qa=skipped) | | 2026-03-29 06:17 UTC | venom | hub |41524b5| feat(products): REQ-001 — site filter UI + Weby column in product table | ✅ done (qa=skipped) | | 2026-03-29 06:18 UTC | venom | prod |136f8ba| refactor(products): REQ-001 — switch site filter to server-side (siteId param) | ⚠️ fail (qa=skipped) | | 2026-03-29 06:32 UTC | badwolf | hub |2067259| feat(products): add siteSlug filter to GET /products [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 06:33 UTC | badwolf | prod |2067259| feat(products): add siteSlug filter to GET /products [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 06:46 UTC | venom | hub |136f8ba| refactor(products): REQ-001 — switch site filter to server-side (siteId param) | ✅ done (qa=skipped) | | 2026-03-29 06:49 UTC | venom | prod |136f8ba| refactor(products): REQ-001 — switch site filter to server-side (siteId param) | ⚠️ fail (qa=skipped) | | 2026-03-29 06:55 UTC | billit | prod |e589167| test(billit): 197 tests passing — new suites + fixes for all modules | ✅ done (qa=skipped) | | 2026-03-29 06:58 UTC | venom | prod |136f8ba| refactor(products): REQ-001 — switch site filter to server-side (siteId param) | ⚠️ fail (qa=skipped) | | 2026-03-29 07:02 UTC | billit | hub |e589167| test(billit): 197 tests passing — new suites + fixes for all modules | ✅ done (qa=skipped) | | 2026-03-29 07:22 UTC | venom | hub |c473b9d| feat(products): REQ-002 — bundle type + bundle items UI + API client | ✅ done (qa=skipped) | | 2026-03-29 07:24 UTC | venom | prod |c473b9d| feat(products): REQ-002 — bundle type + bundle items UI + API client | ⚠️ fail (qa=skipped) | | 2026-03-29 07:50 UTC | badwolf | hub |9cd5ea6| fix(products): add 'bundle' to CreateProductDto type validation [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 08:22 UTC | badwolf | hub |fb19876| fix(products): PATCH /products auth via ApiKeyGuard + woocommerceId writeback [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 08:22 UTC | badwolf | prod |fb19876| fix(products): PATCH /products auth via ApiKeyGuard + woocommerceId writeback [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 08:36 UTC | billit | hub |e372101| feat(billit): DEC-003 — unimplemented Fakturoid endpoints return 404 + tests | ✅ done (qa=skipped) | | 2026-03-29 11:03 UTC | billit | hub |000af66| feat(billit): accounting UI on invoice detail (předkontace editor) | ✅ done (qa=skipped) | | 2026-03-29 12:08 UTC | billit | prod |000af66| feat(billit): accounting UI on invoice detail (předkontace editor) | ✅ done (qa=skipped) | | 2026-03-29 12:14 UTC | s60-auth | prod |877a692| fix(auth): ENV HUSKY=0 do frontend/Dockerfile builder stage [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 12:15 UTC | billit | hub |000af66| feat(billit): accounting UI on invoice detail (předkontace editor) | ✅ done (qa=skipped) | | 2026-03-29 12:17 UTC | s60-auth | hub |877a692| fix(auth): ENV HUSKY=0 do frontend/Dockerfile builder stage [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 12:18 UTC | s60-auth | prod |877a692| fix(auth): ENV HUSKY=0 do frontend/Dockerfile builder stage [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 12:20 UTC | s60-auth | hub |877a692| fix(auth): ENV HUSKY=0 do frontend/Dockerfile builder stage [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 12:29 UTC | s60-auth | hub |877a692| fix(auth): ENV HUSKY=0 do frontend/Dockerfile builder stage [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 12:31 UTC | s60-auth | prod |877a692| fix(auth): ENV HUSKY=0 do frontend/Dockerfile builder stage [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 14:03 UTC | badwolf | prod |c097b66| docs: add DEPLOY.md for sentinel deploy pipeline | ✅ done (qa=skipped) | | 2026-03-29 14:11 UTC | badwolf | hub |c097b66| docs: add DEPLOY.md for sentinel deploy pipeline | ✅ done (qa=skipped) | | 2026-03-29 14:17 UTC | badwolf | hub |c097b66| docs: add DEPLOY.md for sentinel deploy pipeline | ✅ done (qa=skipped) | | 2026-03-29 14:18 UTC | badwolf | prod |bd18692| feat(products): JwtOrApiKeyGuard — PATCH /products akceptuje JWT i API key | ✅ done (qa=skipped) | | 2026-03-29 14:38 UTC | billit | hub |4dd9c95| fix(billit): upgrade @nestjs/config to v4 + @nestjs/swagger to v11 — fixes NestJS v11 peer conflict [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 15:01 UTC | billit | hub |4dd9c95| fix(billit): upgrade @nestjs/config to v4 + @nestjs/swagger to v11 — fixes NestJS v11 peer conflict [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 15:19 UTC | billit | hub |4dd9c95| fix(billit): upgrade @nestjs/config to v4 + @nestjs/swagger to v11 — fixes NestJS v11 peer conflict [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 15:39 UTC | badwolf | hub |201e502| docs(specs): DEC-001 approved — S60Auth JWT auth for BadWolf | ✅ done (qa=skipped) | | 2026-03-29 15:40 UTC | badwolf | prod |201e502| docs(specs): DEC-001 approved — S60Auth JWT auth for BadWolf | ✅ done (qa=skipped) | | 2026-03-29 15:53 UTC | billit | hub |4dd9c95| fix(billit): upgrade @nestjs/config to v4 + @nestjs/swagger to v11 — fixes NestJS v11 peer conflict [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 16:02 UTC | billit | prod |4dd9c95| fix(billit): upgrade @nestjs/config to v4 + @nestjs/swagger to v11 — fixes NestJS v11 peer conflict [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 16:19 UTC | billit | hub |4dd9c95| fix(billit): upgrade @nestjs/config to v4 + @nestjs/swagger to v11 — fixes NestJS v11 peer conflict [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 16:22 UTC | billit | prod |4dd9c95| fix(billit): upgrade @nestjs/config to v4 + @nestjs/swagger to v11 — fixes NestJS v11 peer conflict [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 16:33 UTC | billit | prod |4dd9c95| fix(billit): upgrade @nestjs/config to v4 + @nestjs/swagger to v11 — fixes NestJS v11 peer conflict [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 16:41 UTC | billit | hub |4dd9c95| fix(billit): upgrade @nestjs/config to v4 + @nestjs/swagger to v11 — fixes NestJS v11 peer conflict [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 16:42 UTC | billit | prod |8771b10| fix(billit): email-first matching in tenant_users (disaster recovery safe) | ✅ done (qa=skipped) | | 2026-03-29 16:49 UTC | billit | hub |8771b10| fix(billit): email-first matching in tenant_users (disaster recovery safe) | ✅ done (qa=skipped) | | 2026-03-29 17:03 UTC | billit | hub |8771b10| fix(billit): email-first matching in tenant_users (disaster recovery safe) | ✅ done (qa=skipped) | | 2026-03-29 17:05 UTC | billit | prod |8771b10| fix(billit): email-first matching in tenant_users (disaster recovery safe) | ✅ done (qa=skipped) | | 2026-03-29 17:42 UTC | billit | hub |627116b| fix(billit): add database.config tests — verify SSL rejectUnauthorized:false for DO PG [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-29 17:43 UTC | billit | prod |a9cb241| fix(billit): user-friendly error handling — ErrorBoundary + API error toasts | ✅ done (qa=skipped) | | 2026-03-29 18:25 UTC | billit | prod |516cb96| fix(billit): TypeORM orderBy must use camelCase property names, not snake_case column names | ✅ done (qa=skipped) | | 2026-03-29 18:32 UTC | billit | hub |516cb96| fix(billit): TypeORM orderBy must use camelCase property names, not snake_case column names | ✅ done (qa=skipped) | | 2026-03-29 18:34 UTC | billit | prod |516cb96| fix(billit): TypeORM orderBy must use camelCase property names, not snake_case column names | ✅ done (qa=skipped) | | 2026-03-29 20:38 UTC | billit | hub |f2a4983| feat(billit): REQ-030 + REQ-031 specs (approved), public Stripe pay, invoice edit fix, confirm dialogs | ✅ done (qa=skipped) | | 2026-03-29 20:40 UTC | billit | prod |f2a4983| feat(billit): REQ-030 + REQ-031 specs (approved), public Stripe pay, invoice edit fix, confirm dialogs | ✅ done (qa=skipped) | | 2026-03-29 21:19 UTC | billit | hub |1335008| feat(billit): CR-016 sent→flag, currency select in invoice editor, DB migration sent→open | ✅ done (qa=skipped) | | 2026-03-29 21:45 UTC | billit | hub |14f27d4| docs(billit): REQ-033 spec — exchange rate on foreign currency invoices (DPH § 4 odst. 5) | ✅ done (qa=skipped) | | 2026-03-29 22:14 UTC | billit | hub |87ad21a| test(billit): fix existing tests + add tests for REQ-031/033 | ✅ done (qa=skipped) | | 2026-03-29 22:16 UTC | billit | prod |87ad21a| test(billit): fix existing tests + add tests for REQ-031/033 | ✅ done (qa=skipped) | | 2026-03-30 03:33 UTC | s60-pulse | prod |e5ced7e| chore(pulse): fix DEPLOY.md — db_change: migration, update to commit 9a93226 | ✅ done (qa=skipped) | | 2026-03-30 03:43 UTC | s60-pulse | hub |e5ced7e| chore(pulse): fix DEPLOY.md — db_change: migration, update to commit 9a93226 | ✅ done (qa=skipped) | | 2026-03-30 03:50 UTC | s60-pulse | prod |a5a1309| fix(pulse): add debug regenerate endpoints for pending outputs [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 03:57 UTC | billit | hub |d8548ff| deploy: update DEPLOY.md for a4fb5c2/109b7ba — auto tax doc, attachments UI, fixed rate, payment filter | ✅ done (qa=skipped) | | 2026-03-30 03:59 UTC | billit | prod |d42a0e7| feat(billit): post-deploy smoke tests, exchange-rate route fix, global error handling | ✅ done (qa=skipped) | | 2026-03-30 04:00 UTC | s60-pulse | hub |a5a1309| fix(pulse): add debug regenerate endpoints for pending outputs [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 04:31 UTC | s60-pulse | prod |37569c9| fix(pulse): robust JSON parsing + subsection tables in output template [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 04:40 UTC | s60-pulse | hub |37569c9| fix(pulse): robust JSON parsing + subsection tables in output template [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 06:22 UTC | badwolf | hub |0ffd27f| fix(auth): DEC-001 — JwtOrApiKeyGuard na PATCH /courses a /course-dates | ✅ done (qa=skipped) | | 2026-03-30 06:23 UTC | badwolf | prod |cffa880| docs: update DEPLOY.md — current 0ffd27f (DEC-001 6/6 PASS, migrace 027) | ✅ done (qa=skipped) | | 2026-03-30 06:44 UTC | billit | prod |83c9835| fix(billit): add missing migration for enabled_payment_methods + auto_emails [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 06:46 UTC | billit | hub |83c9835| fix(billit): add missing migration for enabled_payment_methods + auto_emails [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 08:07 UTC | billit | hub |02a6062| fix(billit): add missing exchange-rate/fixed route at account level [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 10:29 UTC | billit | hub |55f7c97| test(billit): ApiKeyGuard unit tests + Pulse Production key regression [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 10:34 UTC | billit | hub |55f7c97| test(billit): ApiKeyGuard unit tests + Pulse Production key regression [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 10:37 UTC | billit | hub |55f7c97| test(billit): ApiKeyGuard unit tests + Pulse Production key regression [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 10:40 UTC | billit | hub |55f7c97| test(billit): ApiKeyGuard unit tests + Pulse Production key regression [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 10:43 UTC | billit | prod |55f7c97| test(billit): ApiKeyGuard unit tests + Pulse Production key regression [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 11:02 UTC | s60-pulse | hub |24b41e4| fix(pulse): Billit order endpoint + bank transfer payload [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 11:04 UTC | s60-pulse | prod |24b41e4| fix(pulse): Billit order endpoint + bank transfer payload [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 12:02 UTC | s60-pulse | hub |4c16b13| feat(pulse): REQ-030 — billing settings page + checkout billing gate | ✅ done (qa=skipped) | | 2026-03-30 12:07 UTC | s60-pulse | prod |aaa2b7f| fix(test): update pricing-req017 regression tests for bank-transfer checkout (REQ-030) | ✅ done (qa=skipped) | | 2026-03-30 12:31 UTC | s60-pulse | hub |a008ee0| fix(pulse): Billit client payload — registrationNo instead of ico [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 13:03 UTC | s60-pulse | hub |b4eaf1c| feat(pulse): REQ-030 — add optional phone field to billing | ✅ done (qa=skipped) | | 2026-03-30 13:21 UTC | s60-pulse | hub |5927c67| fix(pulse): crash-recovery + stale spec tests [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 13:48 UTC | s60-pulse | prod |ca7c19e| fix(pulse): align Billit order response parsing + payment info UI [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 13:48 UTC | s60-pulse | hub |ca7c19e| fix(pulse): align Billit order response parsing + payment info UI [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 14:24 UTC | s60-pulse | hub |71e2010| fix(pulse): add migration 1710000000024 — billingPhone column missing on hub | ✅ done (qa=skipped) | | 2026-03-30 14:26 UTC | s60-pulse | prod |7eab9ca| fix(pulse): add missing billingPhone migration [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 14:45 UTC | billit | hub |30f53c3| fix(billit): upgrade pulse tenant plan free→pro — unblocks checkout [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 14:47 UTC | billit | prod |0047776| fix(billit): auto-deliver invoice from order (draft → open) so customer can pay | ✅ done (qa=skipped) | | 2026-03-30 14:51 UTC | s60-pulse | hub |c0b057d| fix(pulse): REQ-030 — checkout confirmation step before order creation [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 14:51 UTC | s60-pulse | prod |c0b057d| fix(pulse): REQ-030 — checkout confirmation step before order creation [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 15:03 UTC | billit | hub |0047776| fix(billit): auto-deliver invoice from order (draft → open) so customer can pay | ✅ done (qa=skipped) | | 2026-03-30 15:06 UTC | billit | prod |0047776| fix(billit): auto-deliver invoice from order (draft → open) so customer can pay | ✅ done (qa=skipped) | | 2026-03-30 15:06 UTC | billit | hub |0047776| fix(billit): auto-deliver invoice from order (draft → open) so customer can pay | ✅ done (qa=skipped) | | 2026-03-30 15:08 UTC | billit | prod |0047776| fix(billit): auto-deliver invoice from order (draft → open) so customer can pay | ✅ done (qa=skipped) | | 2026-03-30 15:35 UTC | s60-pulse | hub |c0c0f45| feat(pulse): Risk Radar methodology + inline QR code + invoice link [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 15:35 UTC | s60-pulse | prod |c0c0f45| feat(pulse): Risk Radar methodology + inline QR code + invoice link [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 15:36 UTC | s60-auth | hub |f9762f4| test(auth): REQ-035 — acceptance criteria tests for Client Credentials grant | ✅ done (qa=skipped) | | 2026-03-30 15:37 UTC | s60-auth | prod |f9762f4| test(auth): REQ-035 — acceptance criteria tests for Client Credentials grant | ✅ done (qa=skipped) | | 2026-03-30 15:57 UTC | billit | hub |9e6bdf7| docs(billit): REQ-008 — add @ai-guide headers to products service/controller | ✅ done (qa=skipped) | | 2026-03-30 16:07 UTC | s60-pulse | prod |c0c0f45| feat(pulse): Risk Radar methodology + inline QR code + invoice link [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 16:19 UTC | s60-pulse | prod |c0c0f45| feat(pulse): Risk Radar methodology + inline QR code + invoice link [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-30 20:15 UTC | s60-pulse | prod |a0e889a| test(pulse): update methodology count from 9→10 after risk-radar addition | ✅ done (qa=skipped) | | 2026-03-30 20:26 UTC | s60-pulse | hub |a0e889a| test(pulse): update methodology count from 9→10 after risk-radar addition | ✅ done (qa=skipped) | | 2026-03-30 20:28 UTC | s60-pulse | prod |a0e889a| test(pulse): update methodology count from 9→10 after risk-radar addition | ✅ done (qa=skipped) | | 2026-03-30 20:39 UTC | s60-pulse | prod |fdfee8c| test(pulse): update methodology count from 9→10 after risk-radar addition | ✅ done (qa=skipped) | | 2026-03-30 21:14 UTC | billit | hub |515f4e7| feat(billit): per-tenant Stripe Secret Key — no more global STRIPE_SECRET_KEY | ✅ done (qa=skipped) | | 2026-03-30 21:17 UTC | billit | prod |515f4e7| feat(billit): per-tenant Stripe Secret Key — no more global STRIPE_SECRET_KEY | ✅ done (qa=skipped) | | 2026-03-31 04:53 UTC | badwolf | hub |79d7718| fix(badwolf): GlitchTip/Sentry error tracking integration [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 05:07 UTC | venom | hub |4507fba| chore: add DEPLOY.md — required by deploy.sh | ✅ done (qa=skipped) | | 2026-03-31 05:08 UTC | venom | prod |4507fba| chore: add DEPLOY.md — required by deploy.sh | ⚠️ fail (qa=skipped) | | 2026-03-31 05:33 UTC | s60-auth | hub |29072e7| fix(auth): Login.tsx useEffect stale closure — add clientId+authLoading to deps [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 05:40 UTC | s60-auth | hub |29072e7| fix(auth): Login.tsx useEffect stale closure — add clientId+authLoading to deps [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 05:43 UTC | s60-auth | prod |29072e7| fix(auth): Login.tsx useEffect stale closure — add clientId+authLoading to deps [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 05:58 UTC | billit | hub |6ebd513| fix(billit): GlitchTip/Sentry DSN — activate error tracking [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 06:00 UTC | billit | prod |6ebd513| fix(billit): GlitchTip/Sentry DSN — activate error tracking [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 06:12 UTC | s60-auth | hub |29072e7| fix(auth): Login.tsx useEffect stale closure — add clientId+authLoading to deps [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 06:15 UTC | s60-auth | prod |29072e7| fix(auth): Login.tsx useEffect stale closure — add clientId+authLoading to deps [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 06:28 UTC | venom | hub |4507fba| chore: add DEPLOY.md — required by deploy.sh | ✅ done (qa=skipped) | | 2026-03-31 06:30 UTC | venom | prod |4507fba| chore: add DEPLOY.md — required by deploy.sh | ⚠️ fail (qa=skipped) | | 2026-03-31 09:02 UTC | billit | hub |0be8024| fix(billit): add missing migration for stripe_secret_key + stripe_connect_account_id [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 09:24 UTC | s60-mail | hub |4d636c6| feat(mail): GET /health/deep — deep health smoke test endpoint [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 09:26 UTC | s60-mail | prod |4d636c6| feat(mail): GET /health/deep — deep health smoke test endpoint [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 09:39 UTC | billit | hub |9607f22| feat(health): GET /health/deep — smoke test all parameterless GET routes [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 09:52 UTC | s60-mail | prod |4d636c6| feat(mail): GET /health/deep — deep health smoke test endpoint [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 10:29 UTC | billit | prod |10e587b| feat(billit): REQ-035 deep health monitoring + REQ-034 iDoklad spec approved | ✅ done (qa=skipped) | | 2026-03-31 10:58 UTC | billit | hub |b16871e| feat(billit): REQ-034 iDoklad import + REQ-035 deep health — implementation | ✅ done (qa=skipped) | | 2026-03-31 11:01 UTC | billit | prod |b16871e| feat(billit): REQ-034 iDoklad import + REQ-035 deep health — implementation | ✅ done (qa=skipped) | | 2026-03-31 11:13 UTC | s60-auth | hub |5e93041| feat(health): T-20260331-046 — GET /api/health/deep smoke test endpoint | ✅ done (qa=skipped) | | 2026-03-31 11:15 UTC | s60-auth | prod |5e93041| feat(health): T-20260331-046 — GET /api/health/deep smoke test endpoint | ✅ done (qa=skipped) | | 2026-03-31 11:50 UTC | billit | hub |778b886| feat(billit): REQ-026 — studio60 Stripe gateway migration + integration guide | ✅ done (qa=skipped) | | 2026-03-31 11:53 UTC | billit | prod |778b886| feat(billit): REQ-026 — studio60 Stripe gateway migration + integration guide | ✅ done (qa=skipped) | | 2026-03-31 13:05 UTC | s60-pulse | hub |70ba23c| fix(pulse): regenerate-pending runs in background (fire-and-forget) [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 13:14 UTC | billit | hub |d7d17c8| docs(billit): REQ-036 Stripe Connect platform spec (marketplace payments) | ✅ done (qa=skipped) | | 2026-03-31 13:40 UTC | billit | hub |d7d17c8| docs(billit): REQ-036 Stripe Connect platform spec (marketplace payments) | ✅ done (qa=skipped) | | 2026-03-31 14:09 UTC | billit | prod |d7d17c8| docs(billit): REQ-036 Stripe Connect platform spec (marketplace payments) | ✅ done (qa=skipped) | | 2026-03-31 16:34 UTC | billit | hub |93b8614| feat(billit): REQ-034 iDoklad import UI in Settings + REQ-036 approved | ✅ done (qa=skipped) | | 2026-03-31 16:38 UTC | billit | prod |93b8614| feat(billit): REQ-034 iDoklad import UI in Settings + REQ-036 approved | ✅ done (qa=skipped) | | 2026-03-31 16:51 UTC | s60-auth | hub |1b388e9| fix(auth): exclude /health/deep from smoke-tested routes to prevent recursive self-call [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 16:53 UTC | s60-auth | prod |1b388e9| fix(auth): exclude /health/deep from smoke-tested routes to prevent recursive self-call [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 17:09 UTC | s60-auth | hub |1b388e9| fix(auth): exclude /health/deep from smoke-tested routes to prevent recursive self-call [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 17:10 UTC | s60-auth | prod |1b388e9| fix(auth): exclude /health/deep from smoke-tested routes to prevent recursive self-call [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 17:23 UTC | s60-auth | hub |1b388e9| fix(auth): exclude /health/deep from smoke-tested routes to prevent recursive self-call [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 17:25 UTC | s60-auth | prod |1b388e9| fix(auth): exclude /health/deep from smoke-tested routes to prevent recursive self-call [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 17:39 UTC | billit | hub |00b34c5| test(billit): DEC-012 — platform/vendor AC1 tests in tenants.service.spec | ✅ done (qa=skipped) | | 2026-03-31 17:41 UTC | billit | prod |00b34c5| test(billit): DEC-012 — platform/vendor AC1 tests in tenants.service.spec | ✅ done (qa=skipped) | | 2026-03-31 17:54 UTC | venom | hub |628387d| feat(venom): REQ-002 — bundle items quantity & reorder controls | ✅ done (qa=skipped) | | 2026-03-31 19:55 UTC | venom | hub |153123c| test(venom): regression test pro /health endpoint [no-spec bugfix] | ⚠️ fail (qa=skipped) | | 2026-03-31 20:04 UTC | venom | hub |153123c| test(venom): regression test pro /health endpoint [no-spec bugfix] | ⚠️ fail (qa=skipped) | | 2026-03-31 20:34 UTC | billit | hub |c6bd04c| docs(billit): update DEPLOY.md for 18e94c7 — migration AddUniqueConstraintApiKeyHash | ✅ done (qa=skipped) | | 2026-03-31 20:41 UTC | s60-auth | hub |6b6f918| fix(auth): add GET /api/auth/forward-auth — restore Nginx auth_request endpoint [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 20:42 UTC | s60-auth | prod |6b6f918| fix(auth): add GET /api/auth/forward-auth — restore Nginx auth_request endpoint [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 20:53 UTC | venom | hub |153123c| test(venom): regression test pro /health endpoint [no-spec bugfix] | ⚠️ fail (qa=skipped) | | 2026-03-31 21:20 UTC | billit | hub |d0202cc| fix(billit): add unique constraint on api_keys(tenant_id, prefix) [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 21:24 UTC | s60-auth | hub |6b6f918| fix(auth): add GET /api/auth/forward-auth — restore Nginx auth_request endpoint [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 21:25 UTC | s60-auth | prod |6b6f918| fix(auth): add GET /api/auth/forward-auth — restore Nginx auth_request endpoint [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 21:35 UTC | venom | hub |153123c| test(venom): regression test pro /health endpoint [no-spec bugfix] | ⚠️ fail (qa=skipped) | | 2026-03-31 21:38 UTC | venom | hub |153123c| test(venom): regression test pro /health endpoint [no-spec bugfix] | ⚠️ fail (qa=skipped) | | 2026-03-31 21:56 UTC | billit | hub |d0202cc| fix(billit): add unique constraint on api_keys(tenant_id, prefix) [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 21:58 UTC | billit | prod |d0202cc| fix(billit): add unique constraint on api_keys(tenant_id, prefix) [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 22:59 UTC | billit | hub |659c23e| docs(billit): update DEPLOY.md for 8037c90 — test+config deploy | ✅ done (qa=skipped) | | 2026-03-31 23:06 UTC | venom | hub |4a9a5f0| fix(venom): healthcheck localhost → 127.0.0.1 [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-03-31 23:07 UTC | venom | prod |4a9a5f0| fix(venom): healthcheck localhost → 127.0.0.1 [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 04:40 UTC | s60-pulse | hub |7a3cb51| fix(pulse): findResumableByClient regression + COMPLETED session handling + test alignment | ✅ done (qa=skipped) | | 2026-04-01 05:48 UTC | s60-pulse | hub |5dcd9ab| fix(deploy): db_change: migration — new AddOutputEmailTracking migration | ✅ done (qa=skipped) | | 2026-04-01 06:02 UTC | billit | hub |7cfdcc2| fix(billit): LandingPage img self-closing tag syntax error [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 06:08 UTC | billit | hub |7cfdcc2| fix(billit): LandingPage img self-closing tag syntax error [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 06:11 UTC | billit | prod |7cfdcc2| fix(billit): LandingPage img self-closing tag syntax error [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 06:48 UTC | s60-pulse | hub |85dadb5| chore(pulse): update DEPLOY.md to 3314080 | ✅ done (qa=skipped) | | 2026-04-01 06:49 UTC | s60-pulse | hub |85dadb5| chore(pulse): update DEPLOY.md to 3314080 | ✅ done (qa=skipped) | | 2026-04-01 07:01 UTC | s60-pulse | prod |1cd261e| chore(pulse): update DEPLOY.md to fd9e25c | ✅ done (qa=skipped) | | 2026-04-01 07:24 UTC | billit | hub |7cfdcc2| fix(billit): LandingPage img self-closing tag syntax error [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 07:30 UTC | s60-pulse | hub |836ec97| fix(pulse): thank-you page shows payment details + pay online link to Billit invoice [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 07:39 UTC | billit | hub |7cfdcc2| fix(billit): LandingPage img self-closing tag syntax error [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 07:40 UTC | s60-pulse | prod |836ec97| fix(pulse): thank-you page shows payment details + pay online link to Billit invoice [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 08:08 UTC | billit | hub |7cfdcc2| fix(billit): LandingPage img self-closing tag syntax error [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 08:09 UTC | billit | prod |9dc32bb| feat(billit): public invoice return_url — redirect back to app after payment | ✅ done (qa=skipped) | | 2026-04-01 08:10 UTC | billit | hub |220aa23| fix(billit): DashboardPage require(recharts) → ESM import [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 08:25 UTC | billit | hub |2915ea3| fix(billit): GlitchTip/Sentry exception filter — capture all 500+ errors | ✅ done (qa=skipped) | | 2026-04-01 08:26 UTC | billit | prod |84486ea| fix(billit): recharts require is not defined — inline in vitest [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 08:58 UTC | s60-pulse | prod |e5ebe3f| chore(pulse): update DEPLOY.md to ce90986 | ✅ done (qa=skipped) | | 2026-04-01 08:59 UTC | s60-pulse | hub |e5ebe3f| chore(pulse): update DEPLOY.md to ce90986 | ✅ done (qa=skipped) | | 2026-04-01 09:06 UTC | billit | hub |84486ea| fix(billit): recharts require is not defined — inline in vitest [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 09:09 UTC | billit | prod |84486ea| fix(billit): recharts require is not defined — inline in vitest [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 09:55 UTC | billit | hub |7eae327| feat(billit): suppressEmails flag in POST /orders — app handles notifications itself | ✅ done (qa=skipped) | | 2026-04-01 09:57 UTC | billit | prod |7eae327| feat(billit): suppressEmails flag in POST /orders — app handles notifications itself | ✅ done (qa=skipped) | | 2026-04-01 10:02 UTC | s60-pulse | hub |ef20924| feat(pulse): prerequisites admin UI — add/remove dependencies between methodologies | ✅ done (qa=skipped) | | 2026-04-01 10:03 UTC | s60-pulse | prod |96a310f| chore(pulse): DEPLOY.md — add migration_from | ✅ done (qa=skipped) | | 2026-04-01 10:10 UTC | s60-pulse | hub |f797ee3| fix(pulse): add getMetadata + hasAnyPurchase mocks to conversation tests [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 10:12 UTC | s60-pulse | hub |f797ee3| fix(pulse): add getMetadata + hasAnyPurchase mocks to conversation tests [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 10:13 UTC | s60-pulse | prod |f797ee3| fix(pulse): add getMetadata + hasAnyPurchase mocks to conversation tests [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 10:39 UTC | s60-pulse | hub |15a8345| fix(pulse): trial toggle error handling + fallback when allMeta empty [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 10:41 UTC | s60-pulse | prod |15a8345| fix(pulse): trial toggle error handling + fallback when allMeta empty [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 12:21 UTC | s60-pulse | prod |a8aefa2| fix(pulse): send ALL billing fields to Billit (street, city, zip, country) [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 12:24 UTC | s60-pulse | prod |f396b55| chore(pulse): update DEPLOY.md to a8aefa2 | ✅ done (qa=skipped) | | 2026-04-01 12:28 UTC | billit | hub |32eb1c2| fix(billit): expose phone + vatNo fields on POST /orders client [no-spec bugfix] | ✅ done (qa=pass) | | 2026-04-01 12:30 UTC | billit | prod |23e2ace| fix(billit): update tests for topClients/cashflow and per-tenant webhook secret [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 12:58 UTC | billit | hub |c74eeba| fix(billit): downgrade @sentry to v7 for GlitchTip UUID DSN compatibility [no-spec bugfix] | ✅ done (qa=pass) | | 2026-04-01 13:00 UTC | billit | prod |c74eeba| fix(billit): downgrade @sentry to v7 for GlitchTip UUID DSN compatibility [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-01 13:02 UTC | billit | hub |c74eeba| fix(billit): downgrade @sentry to v7 for GlitchTip UUID DSN compatibility [no-spec bugfix] | ✅ done (qa=pass) | | 2026-04-01 13:14 UTC | billit | hub |c74eeba| fix(billit): downgrade @sentry to v7 for GlitchTip UUID DSN compatibility [no-spec bugfix] | ✅ done (qa=pass) | | 2026-04-01 13:28 UTC | s60-pulse | prod |cecdbd0| chore(pulse): DEPLOY.md — update to f6e7cdd with migration_from | ✅ done (qa=skipped) | | 2026-04-01 13:29 UTC | billit | hub |5c875c1| fix(billit): orders detail — load subject+invoice relations, invoice sort by createdAt | ✅ done (qa=pass) | | 2026-04-01 13:31 UTC | billit | prod |5c875c1| fix(billit): orders detail — load subject+invoice relations, invoice sort by createdAt | ✅ done (qa=skipped) | | 2026-04-01 13:35 UTC | s60-pulse | prod |cecdbd0| chore(pulse): DEPLOY.md — update to f6e7cdd with migration_from | ✅ done (qa=skipped) | | 2026-04-01 14:30 UTC | s60-pulse | hub |22f04a7| chore(pulse): DEPLOY.md — update to 9f407d6 with test mock fix | ✅ done (qa=pass) | | 2026-04-01 14:37 UTC | billit | hub |c371e84| fix(billit): quote REDIS_PASSWORD in docker-compose to prevent word-splitting crash [no-spec bugfix] | ✅ done (qa=pass) | | 2026-04-01 15:05 UTC | billit | hub |ed3186a| fix(billit): DEC-009 — oprav fallback slug studio-60 → studio60 v integration spec | ✅ done (qa=pass) | | 2026-04-01 15:12 UTC | billit | prod |2b914b8| fix(billit): Stripe webhook raw body v3 — bodyParser:false + express.raw() clean | ✅ done (qa=skipped) | | 2026-04-01 15:13 UTC | billit | prod |5f36a0f| chore(deploy): DEPLOY.md — aktualizace HEAD na 2b914b8 pro prod deploy | ✅ done (qa=skipped) | | 2026-04-01 15:25 UTC | billit | prod |b8e0be7| fix(billit): webhook debug logging + various service improvements | ✅ done (qa=skipped) | | 2026-04-01 15:38 UTC | billit | hub |31eac37| chore(deploy): DEPLOY.md — db_change migration (false positive fix) | ✅ done (qa=pass) | | 2026-04-01 18:04 UTC | billit | hub |40d3db8| fix(deploy): DEPLOY.md db_change none→migration for settlement_status fix | ✅ done (qa=pass) | | 2026-04-01 18:06 UTC | billit | prod |40d3db8| fix(deploy): DEPLOY.md db_change none→migration for settlement_status fix | ✅ done (qa=skipped) | | 2026-04-01 19:29 UTC | billit | hub |1fd8181| fix(deploy): DEPLOY.md update HEAD to 5b8b3d9 | ✅ done (qa=pass) | | 2026-04-01 19:31 UTC | billit | prod |1fd8181| fix(deploy): DEPLOY.md update HEAD to 5b8b3d9 | ✅ done (qa=skipped) | | 2026-04-01 19:48 UTC | billit | hub |0ac0711| fix(orders): show linked invoices, hide 'create invoice' when exists | ✅ done (qa=pass) | | 2026-04-01 19:51 UTC | billit | prod |0ac0711| fix(orders): show linked invoices, hide 'create invoice' when exists | ✅ done (qa=skipped) | | 2026-04-01 19:51 UTC | billit | hub |eb9da8d| chore(deploy): DEPLOY.md — hub+prod deploy 0ac0711 (e35efe2+65e7ff8+0ac0711 email fixes) | ✅ done (qa=pass) | | 2026-04-01 19:52 UTC | billit | prod |eb9da8d| chore(deploy): DEPLOY.md — hub+prod deploy 0ac0711 (e35efe2+65e7ff8+0ac0711 email fixes) | ✅ done (qa=skipped) | | 2026-04-01 20:07 UTC | billit | hub |6737d19| chore(deploy): DEPLOY.md — billit 0321052 payment recording, hub deploy pending | ✅ done (qa=pass) | | 2026-04-01 20:29 UTC | billit | hub |ef824ef| chore(deploy): DEPLOY.md — billit e6b9d85 delete payment UI, hub+prod deploy pending | ✅ done (qa=pass) | | 2026-04-01 20:32 UTC | billit | prod |ef824ef| chore(deploy): DEPLOY.md — billit e6b9d85 delete payment UI, hub+prod deploy pending | ✅ done (qa=skipped) | | 2026-04-01 20:35 UTC | s60-pulse | hub |ab4441a| Revert "fix(billing): use raw body for BillIt webhook HMAC verification" | ⚠️ fail (qa=skipped) | | 2026-04-01 20:40 UTC | billit | hub |c50e44a| fix(billit-web): NODE_ENV=development před npm ci v Dockerfile | ✅ done (qa=pass) | | 2026-04-01 20:42 UTC | billit | prod |c50e44a| fix(billit-web): NODE_ENV=development před npm ci v Dockerfile | ✅ done (qa=skipped) | | 2026-04-01 20:47 UTC | billit | hub |8340303| fix(test): integration test default tenant slug → studio-60 | ✅ done (qa=pass) | | 2026-04-01 20:48 UTC | billit | hub |8340303| fix(test): integration test default tenant slug → studio-60 | ✅ done (qa=pass) | | 2026-04-01 20:50 UTC | billit | prod |8340303| fix(test): integration test default tenant slug → studio-60 | ✅ done (qa=skipped) | | 2026-04-01 20:55 UTC | s60-pulse | hub |adba4de| chore(pulse): DEPLOY.md → efe9784 (hotfix archivedBy + adminId crash) | ✅ done (qa=pass) | | 2026-04-01 21:10 UTC | billit | hub |b0f28f4| chore(deploy): DEPLOY.md — ab4181c (TypeORM cascade fix + integration test slug fix) | ✅ done (qa=pass) | | 2026-04-01 21:45 UTC | s60-pulse | hub |adba4de| chore(pulse): DEPLOY.md → efe9784 (hotfix archivedBy + adminId crash) | ✅ done (qa=pass) | | 2026-04-01 22:02 UTC | s60-pulse | prod |3379856| chore(pulse): DEPLOY.md → 36e1b13 (credit drain regression tests) | ✅ done (qa=skipped) | | 2026-04-01 22:20 UTC | s60-pulse | hub |ed3a518| chore(pulse): DEPLOY.md → 31d0c2e (complete credit hold fix) | ✅ done (qa=pass) | | 2026-04-01 22:22 UTC | s60-pulse | prod |ed3a518| chore(pulse): DEPLOY.md → 31d0c2e (complete credit hold fix) | ✅ done (qa=skipped) | | 2026-04-01 22:41 UTC | s60-pulse | prod |ed3a518| chore(pulse): DEPLOY.md → 31d0c2e (complete credit hold fix) | ✅ done (qa=skipped) | | 2026-04-01 22:55 UTC | s60-pulse | prod |ed3a518| chore(pulse): DEPLOY.md → 31d0c2e (complete credit hold fix) | ✅ done (qa=skipped) | | 2026-04-02 02:28 UTC | billit | hub |4cee37b| chore(deploy): mark 8340303/ab4181c prod deployed 2026-04-01 | ✅ done (qa=pass) | | 2026-04-02 02:30 UTC | billit | prod |4cee37b| chore(deploy): mark 8340303/ab4181c prod deployed 2026-04-01 | ✅ done (qa=skipped) | | 2026-04-02 03:19 UTC | s60-pulse | hub |70362a9| docs(pulse): DES-005 — Billit webhook kontrakt + code warnings (T-20260402-031) | ✅ done (qa=pass) | | 2026-04-02 03:21 UTC | s60-pulse | prod |70362a9| docs(pulse): DES-005 — Billit webhook kontrakt + code warnings (T-20260402-031) | ✅ done (qa=skipped) | | 2026-04-02 03:42 UTC | s60-pulse | hub |db38b3e| fix(pulse): CR-022 — refresh credits in UI after session start (hold decrements balance) | ✅ done (qa=pass) | | 2026-04-02 03:42 UTC | s60-pulse | hub |db38b3e| fix(pulse): CR-022 — refresh credits in UI after session start (hold decrements balance) | ✅ done (qa=pass) | | 2026-04-02 03:43 UTC | s60-pulse | prod |db38b3e| fix(pulse): CR-022 — refresh credits in UI after session start (hold decrements balance) | ✅ done (qa=skipped) | | 2026-04-02 04:04 UTC | s60-pulse | hub |94e8311| feat(pulse): CR-022 — three-layer credit hold release (navigate + beforeunload + TTL) | ✅ done (qa=pass) | | 2026-04-02 04:06 UTC | s60-pulse | prod |94e8311| feat(pulse): CR-022 — three-layer credit hold release (navigate + beforeunload + TTL) | ✅ done (qa=skipped) | | 2026-04-02 04:16 UTC | s60-pulse | prod |e210fb4| fix(pulse): CR-022 — re-hold on chat entry + resume, don't abandon on navigate away | ✅ done (qa=skipped) | | 2026-04-02 04:16 UTC | s60-pulse | hub |e210fb4| fix(pulse): CR-022 — re-hold on chat entry + resume, don't abandon on navigate away | ✅ done (qa=pass) | | 2026-04-02 04:18 UTC | s60-pulse | prod |e210fb4| fix(pulse): CR-022 — re-hold on chat entry + resume, don't abandon on navigate away | ✅ done (qa=skipped) | | 2026-04-02 14:25 UTC | badwolf | hub |2b25375| fix(db): TypeORM connection timeout + retry pro DO Managed PG cold start [no-spec bugfix] | ⚠️ fail (qa=skipped) | | 2026-04-02 14:27 UTC | badwolf | prod |2b25375| fix(db): TypeORM connection timeout + retry pro DO Managed PG cold start [no-spec bugfix] | ⚠️ fail (qa=skipped) | | 2026-04-03 04:16 UTC | billit | hub |da7cf97| chore(deploy): prepare DEPLOY.md for 5b1f2ed (reg-billit-scope tests) | ✅ done (qa=pass) | | 2026-04-03 04:18 UTC | billit | prod |854b631| fix(billit): DEC-012 — vendor API URL /api/v1 → /v1 + reg-billit-scope-03 regression test | ✅ done (qa=skipped) | | 2026-04-05 04:07 UTC | billit | hub |02da8fb| chore(deploy): prepare DEPLOY.md for c8b4df5 (reaktivace test API klíčů) | ✅ done (qa=pass) | | 2026-04-05 04:09 UTC | billit | prod |02da8fb| chore(deploy): prepare DEPLOY.md for c8b4df5 (reaktivace test API klíčů) | ✅ done (qa=skipped) | | 2026-04-05 13:12 UTC | badwolf | hub |03ff1aa| deploy: DEPLOY.md update — 0bc1e2c (DEC-001 JWT-only auth, T-20260405-085) | ⚠️ fail (qa=skipped) | | 2026-04-05 13:13 UTC | badwolf | hub |03ff1aa| deploy: DEPLOY.md update — 0bc1e2c (DEC-001 JWT-only auth, T-20260405-085) | ⚠️ fail (qa=skipped) | | 2026-04-05 15:26 UTC | badwolf | hub |03ff1aa| deploy: DEPLOY.md update — 0bc1e2c (DEC-001 JWT-only auth, T-20260405-085) | ⚠️ fail (qa=skipped) | | 2026-04-07 09:24 UTC | billit | hub |a36fa21| feat(REQ-040): admin panel — tenant list with sort/filter/search + impersonation | ✅ done (qa=pass) | | 2026-04-07 09:38 UTC | billit | hub |62c2def| feat(REQ-040): admin billing + system pages, impersonate UUID fix | ✅ done (qa=pass) | | 2026-04-07 09:41 UTC | billit | prod |62c2def| feat(REQ-040): admin billing + system pages, impersonate UUID fix | ✅ done (qa=skipped) | | 2026-04-07 09:47 UTC | s60-pulse | hub |2e4dfe1| chore(pulse): rebuild client-dist for deploy | ✅ done (qa=pass) | | 2026-04-07 09:49 UTC | s60-pulse | prod |2e4dfe1| chore(pulse): rebuild client-dist for deploy | ✅ done (qa=skipped) | | 2026-04-07 09:51 UTC | billit | hub |62c2def| feat(REQ-040): admin billing + system pages, impersonate UUID fix | ✅ done (qa=pass) | | 2026-04-07 09:53 UTC | billit | prod |62c2def| feat(REQ-040): admin billing + system pages, impersonate UUID fix | ✅ done (qa=skipped) | | 2026-04-07 15:03 UTC | billit | hub |91118a4| fix(admin): accept superadmin/admin roles + redirect non-admins | ✅ done (qa=skip) | | 2026-04-07 15:06 UTC | billit | prod |91118a4| fix(admin): accept superadmin/admin roles + redirect non-admins | ✅ done (qa=skipped) | | 2026-04-07 15:12 UTC | billit | hub |92ad249| chore(deploy): update DEPLOY.md for 62c2def+91118a4 — admin panel + AdminGuard fix | ✅ done (qa=skip) | | 2026-04-07 15:14 UTC | billit | prod |92ad249| chore(deploy): update DEPLOY.md for 62c2def+91118a4 — admin panel + AdminGuard fix | ✅ done (qa=skipped) | | 2026-04-07 15:46 UTC | billit | hub |413e226| feat(CR-017): delete invoices in any status + bulk delete | ✅ done (qa=skip) | | 2026-04-07 15:48 UTC | billit | prod |acf1bb9| fix(billit): ProductsModule missing TenantModule import → DI crash [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-07 15:54 UTC | billit | hub |96054b1| chore(deploy): update DEPLOY.md for acf1bb9 — ProductsModule DI fix + CR-017 | ✅ done (qa=skip) | | 2026-04-07 15:56 UTC | billit | hub |96054b1| chore(deploy): update DEPLOY.md for acf1bb9 — ProductsModule DI fix + CR-017 | ✅ done (qa=skip) | | 2026-04-07 16:01 UTC | billit | hub |136fd0c| Merge branch 'master' of github.com:studio60-cz/billit | ✅ done (qa=skip) | | 2026-04-07 16:04 UTC | billit | prod |136fd0c| Merge branch 'master' of github.com:studio60-cz/billit | ✅ done (qa=skipped) | | 2026-04-07 16:08 UTC | billit | hub |1c3a2f0| chore(deploy): update DEPLOY.md for 2fad31f — FK fix for invoice delete | ✅ done (qa=skip) | | 2026-04-07 16:13 UTC | billit | hub |60b984a| fix(billit): DEC-012 — SettlementsModule missing VendorApiModule → DI crash → HUB 502 | ✅ done (qa=skip) | | 2026-04-07 16:14 UTC | billit | hub |60b984a| fix(billit): DEC-012 — SettlementsModule missing VendorApiModule → DI crash → HUB 502 | ✅ done (qa=pass) | | 2026-04-07 16:41 UTC | billit | hub |f15d514| chore(deploy): update DEPLOY.md for 00fce28 — DEC-019 CreateAuditLog migration | ✅ done (qa=pass) | | 2026-04-07 16:43 UTC | billit | prod |f15d514| chore(deploy): update DEPLOY.md for 00fce28 — DEC-019 CreateAuditLog migration | ✅ done (qa=skipped) | | 2026-04-07 16:50 UTC | billit | hub |9b5bd9f| chore(deploy): update DEPLOY.md for 1e0eb5b — CreateAuditLog migration split fix | ✅ done (qa=pass) | | 2026-04-07 17:06 UTC | billit | hub |b9eb6ea| chore(deploy): mark c332861 hub+prod deployed 2026-04-07 | ✅ done (qa=pass) | | 2026-04-07 17:11 UTC | billit | hub |8d873b0| fix(invoices): DEC-019 — replace invoiceRepo.remove() with raw SQL DELETE | ✅ done (qa=pass) | | 2026-04-07 17:21 UTC | billit | prod |8bc37e7| chore(deploy): update DEPLOY.md for 8d873b0 — migration idempotent note (prod at f15d514) | ✅ done (qa=skipped) | | 2026-04-07 17:29 UTC | billit | hub |6d38cb0| chore(deploy): update DEPLOY.md for c7b05e1+e9c9829 — BankEmailConsumer error handler + graceful shutdown | ✅ done (qa=skip) | | 2026-04-07 17:31 UTC | billit | prod |4bdbcab| chore(deploy): update DEPLOY.md for c7b05e1+e9c9829 — BankEmailConsumer error handler + graceful shutdown | ✅ done (qa=skipped) | | 2026-04-08 03:33 UTC | billit | hub |018f831| fix(CR-017): robust invoice delete — tenant_id in audit, cleanup email_logs/notifications | ✅ done (qa=pass) | | 2026-04-08 03:35 UTC | billit | prod |018f831| fix(CR-017): robust invoice delete — tenant_id in audit, cleanup email_logs/notifications | ✅ done (qa=skipped) | | 2026-04-08 03:38 UTC | billit | hub |018f831| fix(CR-017): robust invoice delete — tenant_id in audit, cleanup email_logs/notifications | ✅ done (qa=pass) | | 2026-04-08 03:39 UTC | billit | prod |018f831| fix(CR-017): robust invoice delete — tenant_id in audit, cleanup email_logs/notifications | ✅ done (qa=skipped) | | 2026-04-08 14:55 UTC | billit | hub |9dcea12| chore(deploy): update DEPLOY.md for bd0f61c — CR-018 bulk order actions | ✅ done (qa=pass) | | 2026-04-08 14:56 UTC | billit | hub |9dcea12| chore(deploy): update DEPLOY.md for bd0f61c — CR-018 bulk order actions | ✅ done (qa=pass) | | 2026-04-08 14:57 UTC | billit | prod |9dcea12| chore(deploy): update DEPLOY.md for bd0f61c — CR-018 bulk order actions | ✅ done (qa=skipped) | | 2026-04-08 14:57 UTC | billit | prod |9dcea12| chore(deploy): update DEPLOY.md for bd0f61c — CR-018 bulk order actions | ✅ done (qa=skipped) | | 2026-04-09 04:48 UTC | billit | hub |3a2938a| feat(banking): REQ-005-M2 — POST /bank-accounts/:id/inbound-email | ✅ done (qa=skip) | | 2026-04-09 04:52 UTC | billit | hub |0ff2c44| chore(deploy): set commit hash 9320b80 in DEPLOY.md | ✅ done (qa=skip) | | 2026-04-09 04:53 UTC | billit | hub |0ff2c44| chore(deploy): set commit hash 9320b80 in DEPLOY.md | ✅ done (qa=skip) | | 2026-04-09 04:56 UTC | billit | prod |0ff2c44| chore(deploy): set commit hash 9320b80 in DEPLOY.md | ✅ done (qa=skipped) | | 2026-04-09 05:07 UTC | billit | hub |166ef60| refactor(banking): REQ-006-M2 review — cleanup Varianta A dead code + fix spec refs | ✅ done (qa=skip) | | 2026-04-09 05:09 UTC | billit | prod |166ef60| refactor(banking): REQ-006-M2 review — cleanup Varianta A dead code + fix spec refs | ✅ done (qa=skipped) | | 2026-04-09 05:12 UTC | billit | hub |166ef60| refactor(banking): REQ-006-M2 review — cleanup Varianta A dead code + fix spec refs | ✅ done (qa=skip) | | 2026-04-09 05:14 UTC | billit | prod |166ef60| refactor(banking): REQ-006-M2 review — cleanup Varianta A dead code + fix spec refs | ✅ done (qa=skipped) | | 2026-04-09 05:19 UTC | billit | hub |166ef60| refactor(banking): REQ-006-M2 review — cleanup Varianta A dead code + fix spec refs | ✅ done (qa=skip) | | 2026-04-09 05:20 UTC | billit | prod |166ef60| refactor(banking): REQ-006-M2 review — cleanup Varianta A dead code + fix spec refs | ✅ done (qa=skipped) | | 2026-04-09 05:27 UTC | s60-mail | hub |cc8d242| fix(mail): deep-health spec — reset callCount between deepCheck() calls [no-spec bugfix] | ✅ done (qa=skip) | | 2026-04-09 05:31 UTC | s60-mail | prod |cc8d242| fix(mail): deep-health spec — reset callCount between deepCheck() calls [no-spec bugfix] | ⚠️ fail (qa=skipped) | | 2026-04-09 05:33 UTC | s60-mail | prod |cc8d242| fix(mail): deep-health spec — reset callCount between deepCheck() calls [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-09 05:42 UTC | billit | prod |84ba3eb| chore(deploy): mark 166ef60 (8efdec2) deployed hub+prod 2026-04-09 | ✅ done (qa=skipped) | | 2026-04-09 06:11 UTC | s60-pulse | hub |242b945| fix(pulse): debug endpoints for methodology versions + output detail + JSON sanitization [no-spec bugfix] | ✅ done (qa=pass) | | 2026-04-09 06:13 UTC | s60-pulse | prod |242b945| fix(pulse): debug endpoints for methodology versions + output detail + JSON sanitization [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-09 12:08 UTC | billit | hub |fde216c| fix: deliver email only on explicit suppressEmails=false, validate bank account | ✅ done (qa=skip) | | 2026-04-09 12:09 UTC | billit | hub |fde216c| fix: deliver email only on explicit suppressEmails=false, validate bank account | ✅ done (qa=skip) | | 2026-04-09 12:10 UTC | billit | prod |fde216c| fix: deliver email only on explicit suppressEmails=false, validate bank account | ✅ done (qa=skipped) | | 2026-04-09 12:10 UTC | billit | prod |fde216c| fix: deliver email only on explicit suppressEmails=false, validate bank account | ✅ done (qa=skipped) | | 2026-04-09 12:13 UTC | billit | hub |12b5542| chore(deploy): mark fde216c deploy hub+prod 2026-04-09 | ✅ done (qa=skip) | | 2026-04-09 12:15 UTC | billit | prod |12b5542| chore(deploy): mark fde216c deploy hub+prod 2026-04-09 | ✅ done (qa=skipped) | | 2026-04-09 12:34 UTC | billit | hub |5082b9c| fix: validate IBAN on bank account before delivering invoice | ✅ done (qa=skip) | | 2026-04-09 12:36 UTC | billit | prod |5082b9c| fix: validate IBAN on bank account before delivering invoice | ✅ done (qa=skipped) | | 2026-04-09 13:51 UTC | billit | hub |665fce3| fix(web): show backend error messages in toast instead of generic text | ✅ done (qa=pass) | | 2026-04-09 13:53 UTC | billit | prod |665fce3| fix(web): show backend error messages in toast instead of generic text | ✅ done (qa=skipped) | | 2026-04-09 14:01 UTC | billit | hub |a5b7928| chore(deploy): set d1d15ea as current in DEPLOY.md | ✅ done (qa=pass) | | 2026-04-09 14:03 UTC | billit | prod |a5b7928| chore(deploy): set d1d15ea as current in DEPLOY.md | ✅ done (qa=skipped) | | 2026-04-09 14:03 UTC | billit | hub |d1d15ea| fix(web): add bank account edit + IBAN missing warning | ✅ done (qa=pass) | | 2026-04-09 14:04 UTC | billit | prod |d1d15ea| fix(web): add bank account edit + IBAN missing warning | ✅ done (qa=skipped) | | 2026-04-09 14:20 UTC | billit | hub |d4433f3| fix(web+api): bank account edit — fioApiToken in DTO, inbound email display | ✅ done (qa=skip) | | 2026-04-09 14:21 UTC | billit | hub |a5f6f93| chore(deploy): set d4433f3 as current in DEPLOY.md | ✅ done (qa=pass) | | 2026-04-09 14:24 UTC | billit | prod |d4433f3| fix(web+api): bank account edit — fioApiToken in DTO, inbound email display | ✅ done (qa=skipped) | | 2026-04-09 14:33 UTC | billit | hub |ba831d5| chore(deploy): set f80d338 as current in DEPLOY.md | ✅ done (qa=pass) | | 2026-04-09 14:34 UTC | billit | prod |ba831d5| chore(deploy): set f80d338 as current in DEPLOY.md | ✅ done (qa=skipped) | | 2026-04-09 18:57 UTC | s60-mail | hub |af041f9| chore(mail): update DEPLOY.md — fd6eb21, rebuild outdated image [no-spec bugfix] | ✅ done (qa=skip) | | 2026-04-09 19:00 UTC | s60-mail | prod |b2029bd| fix(mail): odstraněn stray callCount z testu po hook zásahu | ✅ done (qa=skipped) | | 2026-04-10 03:55 UTC | badwolf | hub |11c2a07| deploy: DEPLOY.md update — hub last 03ff1aa, migration 030 in diff (T-20260410-092) | ✅ done (qa=pass) | | 2026-04-10 03:56 UTC | badwolf | prod |11c2a07| deploy: DEPLOY.md update — hub last 03ff1aa, migration 030 in diff (T-20260410-092) | ⚠️ fail (qa=skipped) | | 2026-04-10 04:00 UTC | s60-mail | hub |41a02a6| chore(mail): update DEPLOY.md — 949d276, REQ-005 Bull Board + fixes [T-20260410-096] | ✅ done (qa=skip) | | 2026-04-10 04:02 UTC | s60-mail | prod |41a02a6| chore(mail): update DEPLOY.md — 949d276, REQ-005 Bull Board + fixes [T-20260410-096] | ✅ done (qa=skipped) | | 2026-04-10 04:44 UTC | s60-mail | hub |e9d57e4| feat(mail): REQ-005 — bank-email-inbound fronta v Bull Board | ✅ done (qa=skip) | | 2026-04-10 04:46 UTC | s60-mail | prod |e9d57e4| feat(mail): REQ-005 — bank-email-inbound fronta v Bull Board | ✅ done (qa=skipped) | | 2026-04-10 07:24 UTC | billit | hub |0f9c045| fix: subject search — server-side filtering, find all imported contacts | ✅ done (qa=pass) | | 2026-04-10 07:26 UTC | billit | prod |0f9c045| fix: subject search — server-side filtering, find all imported contacts | ✅ done (qa=skipped) | | 2026-04-10 09:22 UTC | billit | hub |4cfe4c0| feat(web): enhanced banking page — matched/ignored tabs, invoice links | ✅ done (qa=pass) | | 2026-04-10 09:24 UTC | billit | prod |feea100| feat: FR-13 token regeneration + CR-018 bulk orders UI | ✅ done (qa=skipped) | | 2026-04-10 09:27 UTC | billit | hub |feea100| feat: FR-13 token regeneration + CR-018 bulk orders UI | ✅ done (qa=pass) | | 2026-04-10 10:06 UTC | billit | hub |17f085d| fix: shorten inbound email token to 16 chars (bank length limits) | ✅ done (qa=pass) | | 2026-04-10 10:08 UTC | billit | prod |17f085d| fix: shorten inbound email token to 16 chars (bank length limits) | ✅ done (qa=skipped) | | 2026-04-10 10:46 UTC | s60-pulse | hub |7cafe54| fix(pulse): checkout page — detect auth, prefill form, hide login button [no-spec bugfix] | ✅ done (qa=pass) | | 2026-04-10 10:48 UTC | s60-pulse | prod |7cafe54| fix(pulse): checkout page — detect auth, prefill form, hide login button [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-10 11:08 UTC | billit | hub |c6ae4a2| refactor: remove billit-redis — use shared infra Redis | ✅ done (qa=pass) | | 2026-04-10 11:10 UTC | billit | prod |c6ae4a2| refactor: remove billit-redis — use shared infra Redis | ✅ done (qa=skipped) | | 2026-04-10 18:48 UTC | s60-mail | hub |705648f| fix(mail): REQ-005 — fetch email body přes Resend API (webhook posílá jen metadata) | ✅ done (qa=skip) | | 2026-04-10 18:49 UTC | s60-mail | prod |705648f| fix(mail): REQ-005 — fetch email body přes Resend API (webhook posílá jen metadata) | ✅ done (qa=skipped) | | 2026-04-10 18:57 UTC | billit | hub |97a2606| feat(banking): inbound email log — track every email with status + debug API | ✅ done (qa=skip) | | 2026-04-10 18:59 UTC | billit | prod |8c9b11c| fix(deploy): DEPLOY.md db_change none→migration for 97a2606 (CreateInboundEmailLog) [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-10 19:12 UTC | billit | hub |22cea97| fix(banking): NEVER silently drop emails — fallback to any bank account | ✅ done (qa=skip) | | 2026-04-10 19:14 UTC | billit | prod |22cea97| fix(banking): NEVER silently drop emails — fallback to any bank account | ✅ done (qa=skipped) | | 2026-04-10 19:34 UTC | billit | hub |57eb332| fix(banking): parse Fio short format — no currency, "Zpráva příjemci" | ✅ done (qa=skip) | | 2026-04-10 19:36 UTC | billit | prod |57eb332| fix(banking): parse Fio short format — no currency, "Zpráva příjemci" | ✅ done (qa=skipped) | | 2026-04-10 20:04 UTC | billit | hub |04cf991| feat(web): expandable transaction detail row in banking page | ✅ done (qa=skip) | | 2026-04-10 20:06 UTC | billit | prod |04cf991| feat(web): expandable transaction detail row in banking page | ✅ done (qa=skipped) | | 2026-04-11 03:11 UTC | s60-pulse | hub |76ec639| fix(pulse): checkout auth detection fix (/auth/me not /api/auth/me) + header credit label [no-spec bugfix] | ✅ done (qa=pass) | | 2026-04-11 03:12 UTC | s60-pulse | prod |76ec639| fix(pulse): checkout auth detection fix (/auth/me not /api/auth/me) + header credit label [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-11 03:54 UTC | billit | hub |e02d586| fix(web): public invoice — paid state, return_url preserved after Stripe | ✅ done (qa=skip) | | 2026-04-11 03:56 UTC | billit | prod |29713a8| fix: email subject uses document type label (Zálohová faktura, Daňový doklad...) | ✅ done (qa=skipped) | | 2026-04-11 03:58 UTC | billit | hub |29713a8| fix: email subject uses document type label (Zálohová faktura, Daňový doklad...) | ✅ done (qa=skip) | | 2026-04-11 04:06 UTC | s60-pulse | hub |4d99694| fix(pulse): eliminate ALL silent catches + add order email to authenticated checkout [no-spec bugfix] | ✅ done (qa=pass) | | 2026-04-11 04:08 UTC | s60-pulse | prod |4d99694| fix(pulse): eliminate ALL silent catches + add order email to authenticated checkout [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-17 16:05 UTC | s60-pulse | hub |2c36842| docs(pulse): DEPLOY.md — CR-035 + 697/50 test count aktualizováno | ⚠️ fail (qa=skipped) | | 2026-04-17 16:23 UTC | s60-pulse | hub |5542518| feat(pulse): CR-035 — seed hero PNG obrázky z Radčiných přílohových PDF | ✅ done (qa=pass) | | 2026-04-18 03:53 UTC | s60-pulse | hub |4ab1bc4| fix(pulse): CR-035 — hero journey respects admin impersonation | ✅ done (qa=pass) | | 2026-04-18 04:08 UTC | s60-pulse | hub |9281f2f| fix(pulse): CR-035 — header ukazuje jméno impersonated klienta, ne admina | ✅ done (qa=pass) | | 2026-04-18 04:51 UTC | s60-pulse | hub |234fab5| feat(pulse): CR-036 — rerender output from stored JSON + destruktivní UX ochrany | ✅ done (qa=pass) | | 2026-04-18 05:18 UTC | s60-auth | hub |f2f9cdd| feat(auth): REQ-036 — impersonation frontend (banner + admin UI) | ⚠️ fail (qa=skipped) | | 2026-04-18 05:45 UTC | s60-pulse | hub |d67b5df| feat(pulse): CR-037 + CR-038 — programatický JSON repair + cache-busting | ✅ done (qa=pass) | | 2026-04-18 05:54 UTC | s60-pulse | hub |f5d0b5f| feat(pulse): CR-039 — S60Auth system impersonation banner (client + admin) | ✅ done (qa=pass) | | 2026-04-18 06:43 UTC | s60-pulse | hub |963fd7d| feat(pulse): CR-041 — namapuj kategorie na Hero Journey + seed prerekvizity | ✅ done (qa=pass) | | 2026-04-18 06:55 UTC | s60-pulse | hub |a73229f| feat(pulse): CR-042 — client HP hero avatar 2× větší (size lg→xl) | ✅ done (qa=pass) | | 2026-04-18 18:51 UTC | s60-auth | hub |f2f9cdd| feat(auth): REQ-036 — impersonation frontend (banner + admin UI) | ✅ done (qa=skip) | | 2026-04-18 18:54 UTC | s60-auth | prod |f2f9cdd| feat(auth): REQ-036 — impersonation frontend (banner + admin UI) | ✅ done (qa=skipped) | | 2026-04-18 19:01 UTC | s60-pulse | hub |0c7a522| fix(pulse): CR-067 — current hero = nejnižší nedokončený level (ne nejvyšší s progress) | ✅ done (qa=pass) | | 2026-04-18 19:18 UTC | s60-pulse | hub |a604694| fix(pulse): CR-068 — dokončené metodiky per klient (across projects) + konzultace label | ✅ done (qa=pass) | | 2026-04-18 19:24 UTC | s60-pulse | prod |a604694| fix(pulse): CR-068 — dokončené metodiky per klient (across projects) + konzultace label | ⚠️ fail (qa=skipped) | | 2026-04-18 20:25 UTC | s60-pulse | hub |c67c2c7| feat(pulse): CR-070 — Output footer CTA blok (Studio60 + Byznys Parťák) | ✅ done (qa=skip) | | 2026-04-18 20:27 UTC | s60-pulse | prod |02f2f65| fix(pulse): CR-071 — PDF light template (CR-032) bez agresivního dark→light override | ✅ done (qa=skipped) | | 2026-04-18 20:31 UTC | s60-pulse | hub |02f2f65| fix(pulse): CR-071 — PDF light template (CR-032) bez agresivního dark→light override | ✅ done (qa=skip) | | 2026-04-19 04:50 UTC | s60-pulse | hub |0925fb0| feat(pulse): CR-076 — globální process handlers (unhandledRejection + uncaughtException + AI worker error) | ✅ done (qa=pass) | | 2026-04-19 04:52 UTC | s60-pulse | prod |0925fb0| feat(pulse): CR-076 — globální process handlers (unhandledRejection + uncaughtException + AI worker error) | ✅ done (qa=skipped) | | 2026-04-19 05:15 UTC | s60-pulse | hub |de127cd| feat(pulse): CR-077 — "rychlá cesta" (bypass prereq za N× kredit) | ✅ done (qa=pass) | | 2026-04-19 05:36 UTC | s60-pulse | hub |36d1518| fix(pulse): CR-077 — "Spustit teď" na novém řádku + resolver prereq UUID pro category lock | ✅ done (qa=pass) | | 2026-04-19 06:30 UTC | s60-pulse | hub |a1d2d90| fix(pulse): CR-078 — locked metodika zachovává tone barvu (zámek indikuje stav) | ✅ done (qa=pass) | | 2026-04-19 06:35 UTC | s60-pulse | prod |a1d2d90| fix(pulse): CR-078 — locked metodika zachovává tone barvu (zámek indikuje stav) | ✅ done (qa=skipped) | | 2026-04-19 08:00 UTC | s60-pulse | hub |d360652| feat(pulse): CR-079 — Hero rename + 4×4 expansion (Spark/Bolt/Storm/Pulsar) | ✅ done (qa=pass) | | 2026-04-19 08:01 UTC | s60-pulse | prod |d360652| feat(pulse): CR-079 — Hero rename + 4×4 expansion (Spark/Bolt/Storm/Pulsar) | ✅ done (qa=skipped) | | 2026-04-19 11:11 UTC | s60-pulse | hub |6009b5c| feat(pulse): CR-082 — redirect legacy slugů + icon mapping update | ✅ done (qa=pass) | | 2026-04-19 12:35 UTC | s60-pulse | hub |e12cd2b| feat(pulse): CR-087 — input limits + jailbreak/off-topic protection | ✅ done (qa=pass) | | 2026-04-19 12:40 UTC | s60-pulse | prod |e12cd2b| feat(pulse): CR-087 — input limits + jailbreak/off-topic protection | ✅ done (qa=skipped) | | 2026-04-19 13:57 UTC | s60-pulse | hub |a969f7a| fix(pulse): CR-090 — mobile responsive hero spotlight + Další krok | ✅ done (qa=pass) | | 2026-04-19 13:58 UTC | s60-pulse | prod |a969f7a| fix(pulse): CR-090 — mobile responsive hero spotlight + Další krok | ✅ done (qa=skipped) | | 2026-04-19 14:38 UTC | s60-pulse | hub |7d741e5| fix(pulse): CR-091 — přesun nových hero PNG do specs/wireframes/hero/ | ✅ done (qa=pass) | | 2026-04-19 14:40 UTC | s60-pulse | prod |7d741e5| fix(pulse): CR-091 — přesun nových hero PNG do specs/wireframes/hero/ | ✅ done (qa=skipped) | | 2026-04-20 15:46 UTC | s60-pulse | hub |f69281d| test(pulse): CR-106 smoke + unit tests (10 scenarios pass) | ✅ done (qa=skip) | | 2026-04-20 19:12 UTC | s60-pulse | hub |1db218b| chore(pulse): SQL pro per-environment fix pořadí Základy značky | ✅ done (qa=skip) | | 2026-04-20 19:22 UTC | s60-pulse | hub |b338b5a| fix(pulse): CR-104 completeness — readyForOutput=false pokud schema=[] + bulk apply script | ✅ done (qa=skip) | | 2026-04-20 19:45 UTC | s60-pulse | hub |9bebe41| fix(pulse): migrace 051+052+053 — seed data (dataSchemas + outputSections + sortOrder) | ✅ done (qa=skip) | | 2026-04-20 20:19 UTC | s60-pulse | hub |5248076| fix(pulse): migrace 055 — invert Základy značky prereq chain | ✅ done (qa=pass) | | 2026-04-20 20:29 UTC | s60-pulse | prod |5248076| fix(pulse): migrace 055 — invert Základy značky prereq chain | ✅ done (qa=skipped) | | 2026-04-20 21:22 UTC | s60-pulse | hub |19ee169| fix(pulse): AI error diagnostika + credit-balance/billing detekce (Radka 2026-04-20) | ✅ done (qa=pass) | | 2026-04-21 04:03 UTC | s60-pulse | hub |236f6f5| fix(pulse): Sonnet 4-6 prefill guard + /errors admin endpoint + slug→název displej | ✅ done (qa=pass) | | 2026-04-21 05:12 UTC | s60-pulse | hub |66a6284| feat(pulse): REQ-034 F1 — reset hesla + resend email + merge klientů UI | ✅ done (qa=pass) | | 2026-04-21 05:36 UTC | s60-pulse | hub |fe4facf| fix(pulse): finish() respektuje dataSchema + Clients → detail link + forensic 404 | ✅ done (qa=pass) | | 2026-04-21 05:55 UTC | s60-pulse | hub |442e213| docs(pulse): AI prompt checklist + SQL query checklist (CR-102 F4 prep) | ✅ done (qa=pass) | | 2026-04-21 06:16 UTC | venom | hub |2271d5f| docs(specs): REQ-006 draft — Impersonation Banner | ✅ done (qa=skip) | | 2026-04-21 06:18 UTC | venom | prod |2271d5f| docs(specs): REQ-006 draft — Impersonation Banner | ✅ done (qa=skipped) | | 2026-04-21 06:21 UTC | s60-auth | hub |438ef9d| docs: CLAUDE.md aktualizace — DB migrace Hetzner, REQ-033/035/036, diagnostics | ✅ done (qa=skip) | | 2026-04-21 06:22 UTC | s60-auth | prod |438ef9d| docs: CLAUDE.md aktualizace — DB migrace Hetzner, REQ-033/035/036, diagnostics | ✅ done (qa=skipped) | | 2026-04-21 06:29 UTC | s60-mail | hub |52ed5b6| chore(mail): update DEPLOY.md — b4e97be CLAUDE.md update [T-20260421-212] | ✅ done (qa=skip) | | 2026-04-21 06:30 UTC | s60-mail | prod |52ed5b6| chore(mail): update DEPLOY.md — b4e97be CLAUDE.md update [T-20260421-212] | ✅ done (qa=skipped) | | 2026-04-21 06:32 UTC | s60-auth | hub |438ef9d| docs: CLAUDE.md aktualizace — DB migrace Hetzner, REQ-033/035/036, diagnostics | ✅ done (qa=skip) | | 2026-04-21 06:33 UTC | s60-auth | prod |438ef9d| docs: CLAUDE.md aktualizace — DB migrace Hetzner, REQ-033/035/036, diagnostics | ✅ done (qa=skipped) | | 2026-04-21 06:54 UTC | s60-pulse | hub |255776f| feat(pulse): CR-108 F1A — Brand Identity v1.2 helpers foundation | ✅ done (qa=pass) | | 2026-04-21 07:32 UTC | s60-pulse | hub |6d3f21e| feat(pulse): CR-108 F3 — integrace 8 nových block types do brand-identity/brand-guide outputSections | ✅ done (qa=skip) | | 2026-04-21 07:49 UTC | s60-pulse | hub |53f9562| fix(pulse): partial regen — placeholder v hex + archetyp sekce chybí primaryColor | ✅ done (qa=pass) | | 2026-04-21 08:02 UTC | s60-pulse | hub |6d3f21e| feat(pulse): CR-108 F3 — integrace 8 nových block types do brand-identity/brand-guide outputSections | ✅ done (qa=skip) | | 2026-04-21 08:07 UTC | s60-pulse | hub |3546598| fix(pulse): per-section JSON parse retry s error feedbackem + diag v generationNotes | ✅ done (qa=skip) | | 2026-04-21 08:51 UTC | s60-pulse | hub |4b55bf3| feat(pulse): user-friendly partial status + prompt hint pro unicode quotes | ✅ done (qa=skip) | | 2026-04-21 09:12 UTC | s60-pulse | prod |79f4d6e| Merge branch 'master' of github.com:studio60-cz/s60-pulse | ✅ done (qa=skipped) | | 2026-04-21 09:50 UTC | s60-pulse | hub |15b65a1| chore(deploy): mark 79f4d6e prod deployed 2026-04-21 — T-20260421-309 | ✅ done (qa=skip) | | 2026-04-21 09:57 UTC | s60-pulse | prod |15b65a1| chore(deploy): mark 79f4d6e prod deployed 2026-04-21 — T-20260421-309 | ✅ done (qa=skipped) | | 2026-04-21 11:35 UTC | s60-pulse | hub |2d185e9| chore(deploy): DEPLOY.md pro ae75073 hub deploy — T-20260421-433 | ✅ done (qa=pass) | | 2026-04-21 11:58 UTC | s60-pulse | hub |0851e50| docs(pulse): aktualizace nápovědy — CR-107/REQ-034/CR-108/CR-110 | ✅ done (qa=skip) | | 2026-04-21 13:04 UTC | s60-pulse | hub |f0e945c| chore(deploy): DEPLOY.md pro d379244 hub deploy — T-20260421-481 | ✅ done (qa=pass) | | 2026-04-21 14:01 UTC | s60-pulse | hub |b2be43d| chore(deploy): mark bdd792b hub deployed 2026-04-21 — T-20260421-511 | ✅ done (qa=pass) | | 2026-04-21 14:50 UTC | s60-pulse | hub |f59f207| fix(pulse): CR-112 — schema permissive + explicit AI instructions | ✅ done (qa=pass) | | 2026-04-21 16:38 UTC | s60-pulse | hub |30125b6| fix(pulse): graceful shutdown — stop_grace_period 30s + enableShutdownHooks | ✅ done (qa=skip) | | 2026-04-21 17:15 UTC | s60-pulse | hub |f63e90f| fix(pulse): CR-112 — harmony-illustrations Q4=B Adobe continuous kruhy | ✅ done (qa=skip) | | 2026-04-21 17:18 UTC | s60-pulse | hub |235d8a1| chore(deploy): DEPLOY.md pro f63e90f hub deploy — T-20260421-639 | ✅ done (qa=skip) | | 2026-04-21 17:21 UTC | s60-pulse | prod |235d8a1| chore(deploy): DEPLOY.md pro f63e90f hub deploy — T-20260421-639 | ✅ done (qa=skipped) | | 2026-04-21 18:09 UTC | s60-pulse | hub |ee75d5e| chore(deploy): doplnit migration_from do DEPLOY.md — T-20260421-686 | ✅ done (qa=skip) | | 2026-04-22 08:05 UTC | s60-pulse | hub |1ddef95| fix(pulse): update stale tests — methodology count 10→11 (brand-guide), spec-structure threshold 3→4 (special-offer) [no-spec bugfix] | ✅ done (qa=skip) | | 2026-04-22 08:14 UTC | s60-pulse | hub |372f8ea| chore(deploy): DEPLOY.md pro c833741 — migration_from d6936a4 + pre-existing test failures note | ✅ done (qa=skip) | | 2026-04-22 08:22 UTC | s60-pulse | prod |372f8ea| chore(deploy): DEPLOY.md pro c833741 — migration_from d6936a4 + pre-existing test failures note | ✅ done (qa=skipped) | | 2026-04-22 08:36 UTC | s60-pulse | hub |5f12354| chore(deploy): DEPLOY.md pro 85ba4a7 hub deploy — T-20260422-238 | ✅ done (qa=skip) | | 2026-04-22 16:23 UTC | s60-pulse | hub |0faf24d| fix(pulse): opravit DEPLOY.md — migration_from + Current commit [no-spec bugfix] | ✅ done (qa=skip) | | 2026-04-22 21:18 UTC | s60-auth | hub |ae996f1| fix(auth): DEPLOY.md db_change none→migration (AddDcrColumns) [no-spec bugfix] | ✅ done (qa=skip) | | 2026-04-22 21:20 UTC | s60-auth | prod |ae996f1| fix(auth): DEPLOY.md db_change none→migration (AddDcrColumns) [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-22 21:33 UTC | s60-auth | hub |ae996f1| fix(auth): DEPLOY.md db_change none→migration (AddDcrColumns) [no-spec bugfix] | ✅ done (qa=skip) | | 2026-04-22 21:37 UTC | s60-auth | prod |ae996f1| fix(auth): DEPLOY.md db_change none→migration (AddDcrColumns) [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-22 21:51 UTC | s60-auth | hub |72d6661| chore: DEPLOY.md aktualizace pro 6c66da8 — db_change: none | ✅ done (qa=pass) | | 2026-04-22 21:54 UTC | s60-auth | prod |72d6661| chore: DEPLOY.md aktualizace pro 6c66da8 — db_change: none | ✅ done (qa=skipped) | | 2026-04-23 04:05 UTC | s60-auth | hub |4ea0e78| chore: DEPLOY.md aktualizace pro f61b982 — db_change: none | ✅ done (qa=pass) | | 2026-04-23 04:06 UTC | s60-auth | prod |4ea0e78| chore: DEPLOY.md aktualizace pro f61b982 — db_change: none | ✅ done (qa=skipped) | | 2026-04-23 05:55 UTC | s60-auth | hub |57a69cb| fix(auth): add migration AddRegisteredByEmail — registered_by_email column for DCR admin [no-spec bugfix] | ✅ done (qa=skip) | | 2026-04-23 05:57 UTC | s60-auth | prod |d6390b5| chore: update DEPLOY.md — db_change: migration for REQ-037 DCR columns | ✅ done (qa=skipped) | | 2026-04-23 06:28 UTC | s60-auth | hub |f1751d2| chore: DEPLOY.md — doplň migration_from pro aa4012c | ✅ done (qa=pass) | | 2026-04-23 06:29 UTC | s60-auth | prod |f1751d2| chore: DEPLOY.md — doplň migration_from pro aa4012c | ✅ done (qa=skipped) | | 2026-04-23 07:12 UTC | s60-auth | hub |9ba3fbe| chore: DEPLOY.md aktualizace pro cc5b153 — db_change: none | ✅ done (qa=pass) | | 2026-04-23 07:13 UTC | s60-auth | prod |9ba3fbe| chore: DEPLOY.md aktualizace pro cc5b153 — db_change: none | ✅ done (qa=skipped) | | 2026-04-23 10:09 UTC | s60-auth | hub |7815cad| chore: DEPLOY.md aktualizace pro 90200d9 — db_change: none | ✅ done (qa=pass) | | 2026-04-23 10:10 UTC | s60-auth | prod |7815cad| chore: DEPLOY.md aktualizace pro 90200d9 — db_change: none | ✅ done (qa=skipped) | | 2026-04-23 10:23 UTC | s60-auth | hub |edf2564| chore: DEPLOY.md aktualizace pro 68b7c49 — db_change: none | ✅ done (qa=pass) | | 2026-04-23 10:24 UTC | s60-auth | prod |edf2564| chore: DEPLOY.md aktualizace pro 68b7c49 — db_change: none | ✅ done (qa=skipped) | | 2026-04-23 12:16 UTC | s60-pulse | hub |0e70dbf| fix(pulse): DEPLOY.md — aktualizace na 9d5ef9b s migrací 070 (CR-111) | ✅ done (qa=skip) | | 2026-04-23 12:26 UTC | s60-pulse | prod |0e70dbf| fix(pulse): DEPLOY.md — aktualizace na 9d5ef9b s migrací 070 (CR-111) | ✅ done (qa=skipped) | | 2026-04-23 12:52 UTC | s60-pulse | hub |eb13cb5| fix(pulse): systemic phase transitions — safety net + data mig všech 11 metodik | ✅ done (qa=skip) | | 2026-04-23 12:55 UTC | s60-pulse | prod |eb13cb5| fix(pulse): systemic phase transitions — safety net + data mig všech 11 metodik | ✅ done (qa=skipped) | | 2026-04-23 13:06 UTC | s60-auth | hub |7e2c836| chore: DEPLOY.md — full migration SQL for hub/prod deploy | ✅ done (qa=skip) | | 2026-04-23 13:08 UTC | s60-auth | hub |7e2c836| chore: DEPLOY.md — full migration SQL for hub/prod deploy | ✅ done (qa=skip) | | 2026-04-23 13:14 UTC | s60-auth | prod |7e2c836| chore: DEPLOY.md — full migration SQL for hub/prod deploy | ✅ done (qa=skipped) | | 2026-04-23 13:22 UTC | s60-auth | hub |410fd2a| chore: DEPLOY.md — doplň migration_from pro 2ee2405 | ✅ done (qa=pass) | | 2026-04-23 13:23 UTC | s60-auth | prod |410fd2a| chore: DEPLOY.md — doplň migration_from pro 2ee2405 | ✅ done (qa=skipped) | | 2026-04-24 05:42 UTC | s60-pulse | hub |8c5f922| deploy(pulse): DEPLOY.md — 53c7e36 (migrace 072+073 + UX batch) — T-20260424-170 | ✅ done (qa=skip) | | 2026-04-24 05:45 UTC | s60-pulse | prod |8c5f922| deploy(pulse): DEPLOY.md — 53c7e36 (migrace 072+073 + UX batch) — T-20260424-170 | ✅ done (qa=skipped) | | 2026-04-25 04:10 UTC | s60-pulse | hub |0e5b59a| deploy(pulse): DEPLOY.md — 7704ba1 (storno rename + sticky bar + ikony z DB) — T-20260425-110 | ✅ done (qa=skip) | | 2026-04-25 04:13 UTC | s60-pulse | prod |0e5b59a| deploy(pulse): DEPLOY.md — 7704ba1 (storno rename + sticky bar + ikony z DB) — T-20260425-110 | ✅ done (qa=skipped) | | 2026-04-25 05:12 UTC | s60-auth | hub |336985a| chore: DEPLOY.md aktualizace pro a8c4e10 — db_change: none | ✅ done (qa=pass) | | 2026-04-25 05:13 UTC | s60-auth | prod |336985a| chore: DEPLOY.md aktualizace pro a8c4e10 — db_change: none | ✅ done (qa=skipped) | | 2026-04-25 11:21 UTC | s60-pulse | hub |1999ef5| deploy(pulse): DEPLOY.md — b579ebe (CR-118+CR-119 + migrace 074+075) — T-20260425-314 | ✅ done (qa=skip) | | 2026-04-25 11:25 UTC | s60-pulse | hub |1999ef5| deploy(pulse): DEPLOY.md — b579ebe (CR-118+CR-119 + migrace 074+075) — T-20260425-314 | ✅ done (qa=skip) | | 2026-04-25 12:09 UTC | s60-pulse | prod |341200f| deploy(pulse): hub b579ebe (1999ef5) OK — T-20260425-318 CR-118+CR-119 | ✅ done (qa=skipped) | | 2026-04-25 19:55 UTC | s60-pulse | prod |341200f| sentinel-version pilot — first label-verified deploy | ✅ done (qa=skipped) | | 2026-04-25 20:12 UTC | s60-mail | hub |6a3a41e| chore(mail): update DEPLOY.md — ccfebb6 test fix [T-20260425-578] | ✅ done (qa=skip) | | 2026-04-25 20:14 UTC | s60-mail | prod |6a3a41e| chore(mail): update DEPLOY.md — ccfebb6 test fix [T-20260425-578] | ✅ done (qa=skipped) | | 2026-04-25 20:22 UTC | billit | hub |26e7092| fix(billit): update billit-api CLAUDE.md — Redis, PG migration, inbound email [no-spec bugfix] | ✅ done (qa=skip) | | 2026-04-25 20:35 UTC | billit | hub |26e7092| fix(billit): update billit-api CLAUDE.md — Redis, PG migration, inbound email [no-spec bugfix] | ✅ done (qa=skip) | | 2026-04-25 20:38 UTC | billit | prod |576a1b0| chore(deploy): sentinel T-20260425-599 — 26e7092 hub ✓, prod pending | ✅ done (qa=skipped) | | 2026-04-25 21:03 UTC | billit | prod |3e6157d| chore(deploy): sentinel T-20260425-599 — 26e7092 hub+prod ✓ | ✅ done (qa=skipped) | | 2026-04-26 03:44 UTC | s60-auth | hub |336985a| chore: DEPLOY.md aktualizace pro a8c4e10 — db_change: none | ✅ done (qa=pass) | | 2026-04-26 07:47 UTC | s60-pulse | hub |edc1f35| docs(pulse): DEPLOY.md update — Current 8df104d (MCP per-env name fix, no migration) | ✅ done (qa=skip) | | 2026-04-26 08:30 UTC | s60-pulse | prod |884ae9e| deploy(pulse): DEPLOY.md update — Current c308da2 (hardcoded slug→asset refactor, no migration) — T-20260426-242 | ✅ done (qa=skipped) | | 2026-04-26 08:32 UTC | s60-auth | prod |336985a| chore: DEPLOY.md aktualizace pro a8c4e10 — db_change: none | ✅ done (qa=skipped) | | 2026-04-26 08:36 UTC | badwolf | hub |60b60b3| docs(claude): přidat pravidlo OTÁZKA ≠ PŘÍKAZ (globální, f2bf692) | ✅ done (qa=pass) | | 2026-04-26 08:40 UTC | badwolf | prod |60b60b3| docs(claude): přidat pravidlo OTÁZKA ≠ PŘÍKAZ (globální, f2bf692) | ⚠️ fail (qa=skipped) | | 2026-04-26 09:45 UTC | s60-pulse | hub |1b5c361| deploy(pulse): hub+prod c308da2 OK — T-20260426-242 (hardcoded slug→asset refactor, no migration) | ✅ done (qa=pass) | | 2026-04-26 10:15 UTC | s60-pulse | prod |1b5c361| deploy(pulse): hub+prod c308da2 OK — T-20260426-242 (hardcoded slug→asset refactor, no migration) | ✅ done (qa=skipped) | | 2026-04-26 19:01 UTC | badwolf | hub |53d2cf9| fix(test): jwks-rsa ESM mock + aktualizovat spec pro global JwksAuthGuard (T-20260426-542) | ✅ done (qa=pass) | | 2026-04-26 19:02 UTC | badwolf | prod |53d2cf9| fix(test): jwks-rsa ESM mock + aktualizovat spec pro global JwksAuthGuard (T-20260426-542) | ⚠️ fail (qa=skipped) | | 2026-04-26 19:17 UTC | venom | hub |bd472fb| fix(venom): parseJwt — správné dekódování Base64URL pro RS256 JWT [no-spec bugfix] | ✅ done (qa=skip) | | 2026-04-26 19:19 UTC | venom | prod |bd472fb| fix(venom): parseJwt — správné dekódování Base64URL pro RS256 JWT [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-26 19:48 UTC | billit | hub |4312270| chore(deploy): CR-021 — DEPLOY.md + deploy.yml pro 30b0c61 (JWKS_URI) | ✅ done (qa=pass) | | 2026-04-27 05:18 UTC | s60-pulse | hub |bcbca34| fix(pulse): CR-121 — validate bot token before save + send token from UI | ✅ done (qa=pass) | | 2026-04-27 05:22 UTC | s60-pulse | prod |bcbca34| fix(pulse): CR-121 — validate bot token before save + send token from UI | ✅ done (qa=skipped) | | 2026-04-27 09:47 UTC | billit | hub |9a32e65| chore(deploy): sentinel T-20260427-277 — d8f3db4 billit-web hub pending | ✅ done (qa=pass) | | 2026-04-27 09:48 UTC | billit | prod |9a32e65| chore(deploy): sentinel T-20260427-277 — d8f3db4 billit-web hub pending | ✅ done (qa=skipped) | | 2026-04-27 19:07 UTC | s60-pulse | hub |dd2f7d7| fix(pulse): TRIAL credits hold + creditCost editace v admin UI | ✅ done (qa=pass) | | 2026-04-27 19:10 UTC | s60-pulse | prod |dd2f7d7| fix(pulse): TRIAL credits hold + creditCost editace v admin UI | ✅ done (qa=skipped) | | 2026-04-27 19:26 UTC | billit | hub |0c1e2db| fix(billit-web): banking page — show backend error + fix React key warning | ✅ done (qa=pass) | | 2026-04-27 19:28 UTC | billit | prod |0c1e2db| fix(billit-web): banking page — show backend error + fix React key warning | ✅ done (qa=skipped) | | 2026-04-28 05:27 UTC | billit | hub |1aa8dee| chore(deploy): DEPLOY.md update for 747234e (CR-022 + CR-023 + DSN) | ✅ done (qa=skip) | | 2026-04-28 05:30 UTC | billit | prod |1aa8dee| chore(deploy): DEPLOY.md update for 747234e (CR-022 + CR-023 + DSN) | ✅ done (qa=skipped) | | 2026-04-28 09:43 UTC | s60-auth | hub |b28d79c| chore: DEPLOY.md aktualizace pro 0cbff8e — db_change: none | ✅ done (qa=pass) | | 2026-04-28 09:45 UTC | s60-auth | prod |b28d79c| chore: DEPLOY.md aktualizace pro 0cbff8e — db_change: none | ✅ done (qa=skipped) | | 2026-04-28 09:55 UTC | s60-auth | hub |9b9a228| test(auth): DCR auto-approve unit tests — covers authorization_code + client_secret_post [no-spec bugfix] | ✅ done (qa=pass) | | 2026-04-28 09:56 UTC | s60-auth | prod |9b9a228| test(auth): DCR auto-approve unit tests — covers authorization_code + client_secret_post [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-04-28 12:51 UTC | s60-pulse | hub |3587e72| deploy(pulse): update release → 53c4e1a (+PDF page break fix) | ✅ done (qa=pass) | | 2026-04-28 13:00 UTC | s60-pulse | prod |3587e72| deploy(pulse): update release → 53c4e1a (+PDF page break fix) | ✅ done (qa=skipped) | | 2026-04-28 13:23 UTC | s60-pulse | hub |63ae3ab| deploy(pulse): update release → b7f1407 (+PDF page break wider coverage) | ✅ done (qa=pass) | | 2026-04-28 13:26 UTC | s60-pulse | prod |63ae3ab| deploy(pulse): update release → b7f1407 (+PDF page break wider coverage) | ✅ done (qa=skipped) | | 2026-04-29 16:12 UTC | s60-pulse | hub |4f73c55| deploy(pulse): update release → 9fccd7d (CR-124..135 batch + CR-134 JSONB hotfix) | ✅ done (qa=skip) | | 2026-04-29 16:25 UTC | s60-pulse | hub |e296646| deploy(pulse): update release → a83fa98 (+CR-135 JPEG support amendment) | ✅ done (qa=skip) | | 2026-04-29 16:37 UTC | s60-pulse | prod |e296646| deploy(pulse): update release → a83fa98 (+CR-135 JPEG support amendment) | ⚠️ fail (qa=skipped) | | 2026-04-29 19:33 UTC | s60-pulse | hub |6e68e51| feat(pulse): CR-139 follow-up — dynamic credit cost + public page refactor + visual check | ✅ done (qa=pass) | | 2026-04-29 19:36 UTC | s60-pulse | prod |6e68e51| feat(pulse): CR-139 follow-up — dynamic credit cost + public page refactor + visual check | ✅ done (qa=skipped) | | 2026-04-29 19:52 UTC | s60-pulse | hub |b454919| fix(pulse): CR-093 follow-up — heroes Radka golden/iron/wood mapping (migration 088) | ✅ done (qa=pass) | | 2026-04-29 19:56 UTC | s60-pulse | prod |1e1f1b5| test(pulse): REQ-005 — regression pulse-int-auth-03 extended invite token endpoints | ✅ done (qa=skipped) | | 2026-04-30 07:37 UTC | s60-pulse | hub |5ff6982| fix(pulse): CR-132 follow-up — reopen tlačítko nad výstupem (Chat + Profile + Admin) + noCredits guard | ✅ done (qa=skip) | | 2026-04-30 07:41 UTC | s60-pulse | prod |5ff6982| fix(pulse): CR-132 follow-up — reopen tlačítko nad výstupem (Chat + Profile + Admin) + noCredits guard | ✅ done (qa=skipped) | | 2026-05-02 17:52 UTC | billit | hub |cc81773| feat(billit): REQ-042 — Fio REST API plné napojení | ⚠️ fail (qa=skipped) | | 2026-05-03 04:24 UTC | billit | hub |cc81773| feat(billit): REQ-042 — Fio REST API plné napojení | ⚠️ fail (qa=skipped) | | 2026-05-03 04:27 UTC | billit | hub |cc81773| feat(billit): REQ-042 — Fio REST API plné napojení | ✅ done (qa=skip) | | 2026-05-03 04:48 UTC | billit | prod |cc81773| feat(billit): REQ-042 — Fio REST API plné napojení | ✅ done (qa=skipped) | | 2026-05-07 13:52 UTC | billit | hub |9fa75ce| fix(billit-web): UX — full-form subject create dialog + click-to-copy API key | ✅ done (qa=skip) | | 2026-05-07 14:07 UTC | billit | prod |9fa75ce| fix(billit-web): UX — full-form subject create dialog + click-to-copy API key | ✅ done (qa=skipped) | | 2026-05-09 05:12 UTC | billit | hub |d895467| feat(billit): REQ-045 GAPs 1, 2, 4 — dual-write interface (subjects upsert + invoice idempotency + /message.json) | ✅ done (qa=skip) | | 2026-05-09 05:15 UTC | billit | prod |d895467| feat(billit): REQ-045 GAPs 1, 2, 4 — dual-write interface (subjects upsert + invoice idempotency + /message.json) | ✅ done (qa=skipped) | | 2026-05-12 03:00 UTC | s60-pulse | hub |269797c| test(pulse): fix 4 failing suites před CR-141 deploy — 891/891 green | ⚠️ fail (qa=skipped) | | 2026-05-12 06:35 UTC | s60-pulse | hub |870ec07| chore(pulse): DEPLOY.md Current → 893632c (CR-141 refactor commit) | ✅ done (qa=skip) | | 2026-05-12 06:39 UTC | s60-pulse | prod |870ec07| chore(pulse): DEPLOY.md Current → 893632c (CR-141 refactor commit) | ✅ done (qa=skipped) | | 2026-05-12 07:33 UTC | s60-pulse | hub |7f2677c| chore(pulse): DEPLOY.md Current → cc3208f (CR-143 + CR-144) | ✅ done (qa=skip) | | 2026-05-13 14:05 UTC | s60-pulse | hub |15c3804| chore(pulse): DEPLOY.md Current → 4796e2d (CR-145 RLS robustness) | ✅ done (qa=skip) | | 2026-05-13 14:10 UTC | s60-pulse | prod |15c3804| chore(pulse): DEPLOY.md Current → 4796e2d (CR-145 RLS robustness) | ✅ done (qa=skipped) | | 2026-05-14 03:56 UTC | s60-pulse | hub |5b46529| chore(pulse): DEPLOY.md Current → c8e059b (Anita bugfix) | ✅ done (qa=skip) | | 2026-05-14 04:01 UTC | s60-pulse | prod |5b46529| chore(pulse): DEPLOY.md Current → c8e059b (Anita bugfix) | ✅ done (qa=skipped) | | 2026-05-14 05:57 UTC | s60-pulse | hub |8ca87f5| chore(pulse): DEPLOY.md Current → b91fae4 (legacy YAML cleanup) | ✅ done (qa=skip) | | 2026-05-14 06:01 UTC | s60-pulse | prod |8ca87f5| chore(pulse): DEPLOY.md Current → b91fae4 (legacy YAML cleanup) | ✅ done (qa=skipped) | | 2026-05-14 18:02 UTC | s60-pulse | hub |d0b2407| chore(pulse): DEPLOY.md Current → 99dccbd (batch 2026-05-14 — 10 commits) | ✅ done (qa=skip) | | 2026-05-15 05:00 UTC | s60-pulse | hub |2b8bfee| fix(pulse): hero PNG optimalizace — commit do origin (bylo jen lokálně) [no-spec bugfix] | ✅ done (qa=skip) | | 2026-05-15 06:59 UTC | s60-pulse | hub |8570be5| fix(pulse): CR-145 ALS propagation pro fire-and-forget greeting callbacks | ✅ done (qa=skip) | | 2026-05-15 09:33 UTC | s60-pulse | hub |c457a92| fix(pulse): AiCostLogger — tenantId GUC + column v ai_cost_events INSERT [no-spec bugfix] | ✅ done (qa=pass) | | 2026-05-15 12:37 UTC | s60-pulse | hub |8a7b7e5| fix(pulse): WELCOME_MESSAGES_SQL — odebrat trailing comma po odstraněném updatedAt line | ✅ done (qa=skip) | | 2026-05-15 12:41 UTC | s60-pulse | prod |8a7b7e5| fix(pulse): WELCOME_MESSAGES_SQL — odebrat trailing comma po odstraněném updatedAt line | ✅ done (qa=skipped) | | 2026-05-16 04:31 UTC | s60-pulse | hub |8f35d57| chore(pulse): DEPLOY.md update — Current 6cfe392 (CR-148 migration 106) | ✅ done (qa=skip) | | 2026-05-16 04:49 UTC | s60-pulse | hub |9b4dd17| chore(pulse): DEPLOY.md update — Current 5461057 (CR-148 + Baťa pricing) | ✅ done (qa=skip) | | 2026-05-16 04:54 UTC | s60-pulse | prod |9b4dd17| chore(pulse): DEPLOY.md update — Current 5461057 (CR-148 + Baťa pricing) | ✅ done (qa=skipped) | | 2026-05-16 06:16 UTC | s60-pulse | hub |e378fed| chore(pulse): DEPLOY.md update — Current 3c54bff (routing fix + sídlo) | ✅ done (qa=skip) | | 2026-05-16 06:19 UTC | s60-pulse | prod |e378fed| chore(pulse): DEPLOY.md update — Current 3c54bff (routing fix + sídlo) | ✅ done (qa=skipped) | | 2026-05-16 07:04 UTC | s60-pulse | hub |fbe4897| chore(pulse): DEPLOY.md update — Current bd4af36 (URL uklid) | ✅ done (qa=skip) | | 2026-05-16 07:07 UTC | s60-pulse | prod |fbe4897| chore(pulse): DEPLOY.md update — Current bd4af36 (URL uklid) | ✅ done (qa=skipped) | | 2026-05-16 08:16 UTC | s60-pulse | hub |e4419b4| chore(pulse): DEPLOY.md update — Current 7fe0680 (CR-150 spec + sync chain) | ✅ done (qa=skip) | | 2026-05-16 08:19 UTC | s60-pulse | prod |e4419b4| chore(pulse): DEPLOY.md update — Current 7fe0680 (CR-150 spec + sync chain) | ✅ done (qa=skipped) | | 2026-05-16 08:34 UTC | s60-pulse | hub |d3b3387| chore(pulse): DEPLOY.md sync — Current 4c19bb7 (help LP storage fix) | ✅ done (qa=skip) | | 2026-05-16 08:37 UTC | s60-pulse | prod |d3b3387| chore(pulse): DEPLOY.md sync — Current 4c19bb7 (help LP storage fix) | ✅ done (qa=skipped) | | 2026-05-19 05:15 UTC | s60-pulse | hub |2389de7| chore(pulse): DEPLOY.md update — Current 898bd39 (12 commits, 3 migrations) | ✅ done (qa=skip) | | 2026-05-19 06:36 UTC | s60-pulse | hub |a171e7a| chore(pulse): DEPLOY.md sync — Current 4edf585 (CI mock fix) | ✅ done (qa=skip) | | 2026-05-19 07:10 UTC | s60-pulse | hub |5eedc6e| chore(pulse): DEPLOY.md sync — Current b6ea47e (LP fix batch) | ✅ done (qa=skip) | | 2026-05-19 07:18 UTC | s60-pulse | prod |5eedc6e| chore(pulse): DEPLOY.md sync — Current b6ea47e (LP fix batch) | ✅ done (qa=skipped) | | 2026-05-19 07:30 UTC | s60-pulse | hub |2ea2d11| chore(pulse): DEPLOY.md sync — Current 72bac90 (LP image paths fix) | ✅ done (qa=skip) | | 2026-05-19 07:34 UTC | s60-pulse | prod |2ea2d11| chore(pulse): DEPLOY.md sync — Current 72bac90 (LP image paths fix) | ✅ done (qa=skipped) | | 2026-05-19 10:57 UTC | s60-pulse | hub |30c423b| chore(pulse): DEPLOY.md sync — Current 805ba2b (Sentry try/catch) | ✅ done (qa=skip) | | 2026-05-19 10:59 UTC | s60-pulse | prod |30c423b| chore(pulse): DEPLOY.md sync — Current 805ba2b (Sentry try/catch) | ✅ done (qa=skipped) | | 2026-05-20 03:43 UTC | s60-pulse | hub |8bbd33b| chore(pulse): DEPLOY.md sync — Current dec2f77 (CR-155 Tier 2 + CR-159) | ✅ done (qa=skip) | | 2026-05-20 04:18 UTC | s60-pulse | hub |0c121a5| chore(pulse): DEPLOY.md sync — Current 42fea6f (ORDER BY refactor follow-up) | ✅ done (qa=skip) | | 2026-05-20 04:45 UTC | s60-pulse | prod |0c121a5| chore(pulse): DEPLOY.md sync — Current 42fea6f (ORDER BY refactor follow-up) | ✅ done (qa=skipped) | | 2026-05-20 07:21 UTC | s60-pulse | hub |caa4467| chore(pulse): DEPLOY.md sync — Current d4946e1 (@sentry/browser 7.110.0 pin) | ✅ done (qa=pass) | | 2026-05-21 10:09 UTC | s60-auth | hub |6c03148| chore: DEPLOY.md aktualizace pro 17559b5 — db_change: migration | ✅ done (qa=skip) | | 2026-05-21 10:15 UTC | s60-pulse | hub |537e1b0| chore(pulse): DEPLOY.md sync — Current 96f6bd4 (6 commitů + migrace 119) | ⚠️ fail (qa=skipped) | | 2026-05-22 03:32 UTC | s60-pulse | hub |a5d1a0e| chore(pulse): DEPLOY.md sync — Current e6e375f (migrace 119 fix) | ✅ done (qa=skip) | | 2026-05-22 04:48 UTC | s60-pulse | hub |a52a6c1| chore(pulse): DEPLOY.md sync — Current d966436 (migrace 120 + saveMessage fix) | ✅ done (qa=skip) | | 2026-05-22 15:27 UTC | s60-auth | hub |6c03148| chore: DEPLOY.md aktualizace pro 17559b5 — db_change: migration | ✅ done (qa=skip) | | 2026-05-22 15:30 UTC | s60-auth | prod |6c03148| chore: DEPLOY.md aktualizace pro 17559b5 — db_change: migration | ✅ done (qa=skipped) | | 2026-05-22 15:56 UTC | s60-pulse | hub |a52a6c1| chore(pulse): DEPLOY.md sync — Current d966436 (migrace 120 + saveMessage fix) | ✅ done (qa=skip) | | 2026-05-22 15:59 UTC | s60-pulse | prod |a52a6c1| chore(pulse): DEPLOY.md sync — Current d966436 (migrace 120 + saveMessage fix) | ✅ done (qa=skipped) | | 2026-05-23 03:22 UTC | s60-pulse | hub |0afd88a| chore(pulse): DEPLOY.md sync — Current 9af0100 (Filip projekt switch fix) | ✅ done (qa=skip) | | 2026-05-23 03:25 UTC | s60-pulse | prod |0afd88a| chore(pulse): DEPLOY.md sync — Current 9af0100 (Filip projekt switch fix) | ✅ done (qa=skipped) | | 2026-05-24 07:59 UTC | billit | hub |12f72df| chore(deploy): DEPLOY.md update for CR-026 + REQ-045 + UX bundle (ff5c1a9) | ✅ done (qa=skip) | | 2026-05-24 08:04 UTC | billit | prod |12f72df| chore(deploy): DEPLOY.md update for CR-026 + REQ-045 + UX bundle (ff5c1a9) | ✅ done (qa=skipped) | | 2026-05-24 10:49 UTC | billit | hub |5dc4b0b| fix(billit-api): CR-026 — Money XML Druh/wrapper per documentType (účetní bug) | ⚠️ fail (qa=skipped) | | 2026-05-24 10:52 UTC | billit | hub |5dc4b0b| fix(billit-api): CR-026 — Money XML Druh/wrapper per documentType (účetní bug) | ✅ done (qa=skip) | | 2026-05-24 10:54 UTC | billit | prod |5dc4b0b| fix(billit-api): CR-026 — Money XML Druh/wrapper per documentType (účetní bug) | ⚠️ fail (qa=skipped) | | 2026-05-25 10:38 UTC | s60-pulse | hub |7fca4e6| chore(pulse): DEPLOY.md update — Current 074a5cf (CR-164 legal pages) | ✅ done (qa=skip) | | 2026-05-25 11:08 UTC | s60-pulse | prod |7fca4e6| chore(pulse): DEPLOY.md update — Current 074a5cf (CR-164 legal pages) | ✅ done (qa=skipped) | | 2026-05-28 03:15 UTC | s60-pulse | hub |902a9f2| chore(pulse): DEPLOY.md update — Current 2b254a9 (CR-165 MD fix + project grouping) | ✅ done (qa=skip) | | 2026-05-28 03:18 UTC | s60-pulse | prod |902a9f2| chore(pulse): DEPLOY.md update — Current 2b254a9 (CR-165 MD fix + project grouping) | ✅ done (qa=skipped) | | 2026-05-28 05:00 UTC | s60-pulse | hub |34acb76| feat(pulse): CR-168 sync v3 — full all-tables + FK-aware + rate limit | ✅ done (qa=skip) | | 2026-05-28 05:04 UTC | s60-pulse | prod |34acb76| feat(pulse): CR-168 sync v3 — full all-tables + FK-aware + rate limit | ✅ done (qa=skipped) | | 2026-05-29 04:02 UTC | s60-pulse | hub |c8d40f3| chore(pulse): DEPLOY.md update — Current f548004 (CR-167 hotfix #1+#2 + Bug B finding) | ✅ done (qa=skip) | | 2026-05-29 04:05 UTC | s60-pulse | prod |c8d40f3| chore(pulse): DEPLOY.md update — Current f548004 (CR-167 hotfix #1+#2 + Bug B finding) | ✅ done (qa=skipped) | | 2026-05-30 04:56 UTC | s60-pulse | hub |916b4b5| fix(pulse): CR-171 — loosen STRICT validation persona-card + risk- family | ✅ done (qa=skip) | | 2026-05-30 05:06 UTC | s60-pulse | prod |916b4b5| fix(pulse): CR-171 — loosen STRICT validation persona-card + risk- family | ✅ done (qa=skipped) | | 2026-05-31 06:11 UTC | s60-pulse | hub |85523a9| feat(pulse): CR-172/173/174/175/176 batch — credit fix + GTM + hero cleanup + LP CTAs + completion modal | ✅ done (qa=skip) | | 2026-05-31 06:31 UTC | s60-pulse | hub |d93dcc2| fix(pulse): CR-175 — outputs_more_cta směřuje na pulse.s60hub.cz, ne YT playlist | ✅ done (qa=skip) | | 2026-05-31 06:56 UTC | s60-pulse | hub |6fcc33c| fix(pulse): CR-175 hotfix — migrace 127 force UPDATE outputs_more_cta_url na YT playlist | ✅ done (qa=skip) | | 2026-05-31 07:54 UTC | s60-pulse | hub |39fe4a2| feat(pulse): CR-175 expand — append 5 video recenzí z playlistu + conditional render | ✅ done (qa=skip) | | 2026-05-31 10:07 UTC | s60-pulse | hub |acf1334| fix(pulse): CR-175 — migrace 130 REPLACE recenze na finálních 5 z playlistu (sparováno s Michaelinou DB verzí) | ✅ done (qa=skip) | | 2026-05-31 12:13 UTC | s60-pulse | hub |c509bbe| feat(pulse): CR-175 v3 — outputs jen YT shorts 1:1 + náhodná rotace 3 z N per request | ✅ done (qa=skip) | | 2026-05-31 12:20 UTC | s60-pulse | prod |c509bbe| feat(pulse): CR-175 v3 — outputs jen YT shorts 1:1 + náhodná rotace 3 z N per request | ✅ done (qa=skipped) | | 2026-05-31 12:28 UTC | billit | hub |c1a6d8d| fix(billit-api): REQ-029 — self-vendor guard (skip split when vendor=platform) | ⚠️ fail (qa=skipped) | | 2026-05-31 12:32 UTC | billit | hub |c1a6d8d| fix(billit-api): REQ-029 — self-vendor guard (skip split when vendor=platform) | ✅ done (qa=skip) | | 2026-05-31 12:34 UTC | billit | prod |c1a6d8d| fix(billit-api): REQ-029 — self-vendor guard (skip split when vendor=platform) | ⚠️ fail (qa=skipped) | | 2026-05-31 12:36 UTC | billit | prod |c1a6d8d| fix(billit-api): REQ-029 — self-vendor guard (skip split when vendor=platform) | ✅ done (qa=skipped) | | 2026-05-31 12:42 UTC | s60-pulse | hub |23dd1f7| feat(pulse): REQ-035 F1 — GDPR consent banner (orestbida/cookieconsent v3, Pulse brand) | ✅ done (qa=skip) | | 2026-05-31 14:22 UTC | s60-pulse | hub |4593301| fix(pulse): REQ-035 — consent banner privacy link /p/privacy-policy → /legal/privacy | ✅ done (qa=skip) | | 2026-05-31 14:24 UTC | s60-pulse | prod |4593301| fix(pulse): REQ-035 — consent banner privacy link /p/privacy-policy → /legal/privacy | ✅ done (qa=skipped) | | 2026-06-01 03:05 UTC | s60-pulse | hub |b4e0f97| fix(pulse): REQ-035 — consent banner CSS overrides PO CDN link (titulky byly neviditelné) | ✅ done (qa=skip) | | 2026-06-01 03:10 UTC | s60-pulse | prod |b4e0f97| fix(pulse): REQ-035 — consent banner CSS overrides PO CDN link (titulky byly neviditelné) | ✅ done (qa=skipped) | | 2026-06-01 11:21 UTC | s60-auth | hub |76efeee| fix(auth): CR-004 — httpOnly access_token cookie pro OAuth authorize (+approve spec) | ✅ done (qa=skip) | | 2026-06-01 11:34 UTC | s60-auth | prod |76efeee| fix(auth): CR-004 — httpOnly access_token cookie pro OAuth authorize (+approve spec) | ✅ done (qa=skipped) | | 2026-06-01 11:50 UTC | s60-pulse | hub |3ffa282| feat(pulse): CR-177 — /auth/callback defense-in-depth (circuit breaker + idempotence + structured logging) | ✅ done (qa=skip) | | 2026-06-01 11:53 UTC | s60-pulse | prod |3ffa282| feat(pulse): CR-177 — /auth/callback defense-in-depth (circuit breaker + idempotence + structured logging) | ✅ done (qa=skipped) | | 2026-06-01 12:10 UTC | s60-pulse | hub |1cf6edf| fix(pulse): CR-177 v2 — per-phase error diagnostics v /auth/callback (prod stále reason=auth_failed) | ✅ done (qa=skip) | | 2026-06-01 12:13 UTC | s60-pulse | prod |1cf6edf| fix(pulse): CR-177 v2 — per-phase error diagnostics v /auth/callback (prod stále reason=auth_failed) | ✅ done (qa=skipped) | | 2026-06-01 16:29 UTC | s60-pulse | hub |86f7ba7| fix(pulse): CR-177 v3 — exchangeCode form-urlencoded + RAW response log (smyčka root cause kandidát) | ✅ done (qa=skip) | | 2026-06-01 16:32 UTC | s60-pulse | prod |86f7ba7| fix(pulse): CR-177 v3 — exchangeCode form-urlencoded + RAW response log (smyčka root cause kandidát) | ✅ done (qa=skipped) | | 2026-06-01 16:48 UTC | s60-pulse | hub |c636afe| fix(pulse): CR-177 v4 — tenant context v /auth/callback (root cause #2 smyčky: client_upsert RLS fail) | ✅ done (qa=skip) | | 2026-06-01 16:52 UTC | s60-pulse | prod |c636afe| fix(pulse): CR-177 v4 — tenant context v /auth/callback (root cause #2 smyčky: client_upsert RLS fail) | ✅ done (qa=skipped) | | 2026-06-01 17:18 UTC | s60-pulse | hub |c2ec67e| fix(pulse): CR-178 — req019-auth-me test mock pro TenantContextService (CI gate fix) | ✅ done (qa=skip) | | 2026-06-01 17:21 UTC | s60-pulse | prod |c2ec67e| fix(pulse): CR-178 — req019-auth-me test mock pro TenantContextService (CI gate fix) | ✅ done (qa=skipped) | | 2026-06-02 14:27 UTC | s60-pulse | hub |a84dfc2| feat(pulse): DEC-011 — sjednocení úložiště dat stránek (content_blocks SSoT) | ✅ done (qa=skip) | | 2026-06-02 14:55 UTC | s60-pulse | prod |a84dfc2| feat(pulse): DEC-011 — sjednocení úložiště dat stránek (content_blocks SSoT) | ✅ done (qa=skipped) | | 2026-06-04 08:04 UTC | s60-pulse | hub |bdc7d3c| feat(pulse): REQ-037 — editovatelné transakční email šablony (Phase 1) | ✅ done (qa=skip) | | 2026-06-04 08:12 UTC | s60-pulse | prod |bdc7d3c| feat(pulse): REQ-037 — editovatelné transakční email šablony (Phase 1) | ✅ done (qa=skipped) | | 2026-06-04 20:29 UTC | s60-pulse | hub |51cc971| fix(pulse): CR-183 — output-gen worker tenant-context wrap (RLS) + prevence | ✅ done (qa=skip) | | 2026-06-04 20:32 UTC | s60-pulse | prod |51cc971| fix(pulse): CR-183 — output-gen worker tenant-context wrap (RLS) + prevence | ✅ done (qa=skipped) | | 2026-06-05 04:33 UTC | s60-pulse | hub |2aa51da| fix(pulse): CR-184 — worker failures do error_events (díra v monitoringu) | ⚠️ fail (qa=skipped) | | 2026-06-05 04:38 UTC | s60-pulse | hub |51cc971| fix(pulse): CR-183 — output-gen worker tenant-context wrap (RLS) + prevence | ✅ done (qa=skip) | | 2026-06-05 05:34 UTC | s60-pulse | hub |2856441| fix(pulse): CR-184 — TelegramQueue circular DI přes ModuleRef lazy resolve | ✅ done (qa=skip) | | 2026-06-05 05:37 UTC | s60-pulse | prod |2856441| fix(pulse): CR-184 — TelegramQueue circular DI přes ModuleRef lazy resolve | ✅ done (qa=skipped) | | 2026-06-08 04:50 UTC | s60-pulse | hub |c45f1f2| feat(pulse): CR-185 — dynamický version footer (commit + čas buildu) | ✅ done (qa=skip) | | 2026-06-08 04:55 UTC | s60-pulse | prod |c45f1f2| feat(pulse): CR-185 — dynamický version footer (commit + čas buildu) | ✅ done (qa=skipped) | | 2026-06-08 07:17 UTC | s60-pulse | hub |46ef634| fix(pulse): abandonSession guard — completed session nelze abandonovat + repair 6 prod sessions | ✅ done (qa=skip) | | 2026-06-08 07:26 UTC | s60-pulse | prod |46ef634| fix(pulse): abandonSession guard — completed session nelze abandonovat + repair 6 prod sessions | ✅ done (qa=skipped) | | 2026-06-10 03:40 UTC | s60-pulse | hub |cb34d99| fix(pulse): project filter — "Vše" tlačítko vždy + reset stale filtru (skryté výstupy) | ✅ done (qa=skip) | | 2026-06-10 03:43 UTC | s60-pulse | prod |cb34d99| fix(pulse): project filter — "Vše" tlačítko vždy + reset stale filtru (skryté výstupy) | ✅ done (qa=skipped) | | 2026-06-10 07:37 UTC | billit | hub |5171d2c| feat(billit): CR-028 — invite-only registrace (uzavření veřejného self-signup) | ✅ done (qa=pass) | | 2026-06-10 07:39 UTC | billit | prod |5171d2c| feat(billit): CR-028 — invite-only registrace (uzavření veřejného self-signup) | ✅ done (qa=skipped) | | 2026-06-10 09:31 UTC | s60-pulse | hub |2c50b20| fix(pulse): marker leak v historii — strip control markeru v getConversationHistory | ✅ done (qa=skip) | | 2026-06-10 10:49 UTC | s60-pulse | hub |8590001| chore(pulse): DEPLOY.md refresh — Current b64a803, db_change: migration (137) | ✅ done (qa=skip) | | 2026-06-10 10:53 UTC | s60-pulse | prod |8590001| chore(pulse): DEPLOY.md refresh — Current b64a803, db_change: migration (137) | ✅ done (qa=skipped) | | 2026-06-11 06:58 UTC | s60-auth | hub |7c994ab| chore: DEPLOY.md — batch f398a84 (CR-005/006 + REQ-042/043), db_change: migration | ✅ done (qa=skip) | | 2026-06-11 07:00 UTC | s60-auth | prod |7c994ab| chore: DEPLOY.md — batch f398a84 (CR-005/006 + REQ-042/043), db_change: migration | ✅ done (qa=skipped) | | 2026-06-14 04:30 UTC | s60-pulse | hub |0b0562c| chore(pulse): DEPLOY.md update — Current 90015e0, db_change: migration (CR-192 mig 138) | ✅ done (qa=skip) | | 2026-06-14 04:35 UTC | billit | hub |96f04b1| feat(billit): CR-029 — PDF (ZIP) export + period filtr + zrušení prodejní stránky | ✅ done (qa=pass) | | 2026-06-14 04:35 UTC | s60-pulse | prod |0b0562c| chore(pulse): DEPLOY.md update — Current 90015e0, db_change: migration (CR-192 mig 138) | ✅ done (qa=skipped) | | 2026-06-14 04:37 UTC | billit | prod |96f04b1| feat(billit): CR-029 — PDF (ZIP) export + period filtr + zrušení prodejní stránky | ✅ done (qa=skipped) | | 2026-06-18 04:20 UTC | billit | hub |db5dec5| feat(billit): DEC-013/014 — interní hub pozice + rebrand groundwork (env-driven URL/domény + Studio60 Účto) | ✅ done (qa=pass) | | 2026-06-18 04:23 UTC | billit | prod |db5dec5| feat(billit): DEC-013/014 — interní hub pozice + rebrand groundwork (env-driven URL/domény + Studio60 Účto) | ✅ done (qa=skipped) | | 2026-06-18 05:30 UTC | vaultwarden | prod |unknown| manual | ✅ done (qa=skipped) | | 2026-06-18 06:08 UTC | vaultwarden | prod |unknown| manual | ✅ done (qa=skipped) | | 2026-06-18 09:02 UTC | vaultwarden | prod |unknown| manual | ✅ done (qa=skipped) | | 2026-06-18 12:13 UTC | billit | hub |53a9b79| fix(billit): brand display name 'Studio 60 Účto' s mezerou (Liborova oprava) | ✅ done (qa=pass) | | 2026-06-18 12:16 UTC | billit | prod |53a9b79| fix(billit): brand display name 'Studio 60 Účto' s mezerou (Liborova oprava) | ✅ done (qa=skipped) | | 2026-06-18 16:02 UTC | s60-pulse | hub |5cfed56| chore(pulse): DEPLOY.md — Current 75f493e (+ REQ-039 přidělené konzultace, migrace 141) | ✅ done (qa=skip) |
Pozn. 5cfed56 hub (dress rehearsal prod→hub clone): CR-188…196 + REQ-039 bundle. Mirror prod→hub (counts 8/8 identické), 3 pending migrace (139 CR-196 RLS empty-safe, 140 CR-190 holds, 141 REQ-039 assignments) aplikovány čistě, container healthy RestartCount=0. CR-196 kritická cesta ověřena: veřejné servírování výstupu
200(ne 500 — CR-189 blocker fix funguje). QA gate FAIL (11/15) = NEvalidní: (a) hardcoded testX-Api-Keyje stale → 401 na hub i prod (test fixture, ne kód); (b) NOVÉ chování bundlu — neplatný API klíč odmítnut za ~10.5s vs prod 0.1s (blokující auth-validace v X-Api-Key cestě, log jenTenantResolverMiddleware [CR-188] fallback) → překročí gate--max-time 10→000ERR. Prod čeká na rozhodnutí Libora. | 2026-06-18 16:34 UTC | s60-pulse | prod |5cfed56| chore(pulse): DEPLOY.md — Current 75f493e (+ REQ-039 přidělené konzultace, migrace 141) | ✅ done (qa=skipped) |Pozn. 5cfed56 prod: Bundle nasazen po hub dress rehearsal (viz pozn. výše). Pre-upgrade prod DB dump
/tmp/dress-rehearsal-20260618/prod-pre-upgrade-163045Z.dump. Migrace 139/140/141 aplikovány na bootu (migration:run→ no pending),methodology_assignmentsexistuje, container healthy RestartCount=0. CR-196 public output serve ověřeno200(0.055s). ENV FLIP:BILLIT_API_URLbillit.cz→https://ucto.studio60.cz/api(DEC-014 rebrand, jen prod; hub míří na billit.s60hub.cz, nezměněn) — secret/root/secrets/pulse/.env.prod(backup.env.prod.bak-20260618-billiturl), ucto cíl živý (root 200), billit.cz/api teď 301→ucto → TODO T-20260618-062 splněn. Prod gate: QA-pass stamp override (hub QA FAIL = test-fixture stale key + known 10s invalid-key delay, NE funkční regrese; CR-196 critical path manuálně ověřen) — autorizoval Libor. Finding 10s eskalován pulse (T-20260618-070, „na tom se pracuje"). | 2026-06-18 18:08 UTC | s60-pulse | hub |00a16b7| fix(pulse): hardening — timeout na S60Auth API-key validate fetch (sentinel finding) | ✅ done (qa=skip) | | 2026-06-18 18:11 UTC | s60-pulse | prod |00a16b7| fix(pulse): hardening — timeout na S60Auth API-key validate fetch (sentinel finding) | ✅ done (qa=skipped) |Pozn. 00a16b7 hub+prod (follow-up na 5cfed56 finding): 1-commit hardening (
fetchWithTimeoutAbortController 5s na S60Auth api-key validate fetch), bez migrací/env. Korekce mého 5cfed56 findingu: 10s NEbyla bundle regrese —validateApiKeybyte-identický s prodem; příčina = hub S60Auth pomalý na invalid klíče + fetch bez timeoutu (env, ne kód). Prod S60Auth rychlý → prod nikdy netrpěl (pulse T-083, root cause eskalován auth T-071). Hardening ověřen empiricky: hub invalid-key reject10.5s → 5.004s(cap funguje), prod0.134s(rychlý S60Auth, cap netrigne). QA gate teďgot 401místo000ERR(= reject ≤ gate max-time, hardening prokázán); testy stále FAIL jen kvůli stale fixture klíči (qa T-074). Prod gate override (Liborem autorizováno DEPLOY OK hub+prod). Health 200, RestartCount=0, BILLIT_API_URL=ucto zachován, CR-196 public serve 200. | 2026-06-19 04:10 UTC | s60-pulse | hub |d348713| chore(pulse): DEPLOY.md — Current 0902755 (REQ-041 P2 grafika + MD export) | ✅ done (qa=skip) | | 2026-06-19 04:13 UTC | s60-pulse | prod |d348713| chore(pulse): DEPLOY.md — Current 0902755 (REQ-041 P2 grafika + MD export) | ✅ done (qa=skipped) |Pozn. d348713 hub+prod: CR-197 (admin tablet sidebar) + REQ-040 (AI-free choice engine) + REQ-041 (HEXACO psychodiagnostika 240 položek, deterministický scoring + grafika, MD/PDF). db_change=NONE (žádné migrace/env). Normální hub→prod (dress rehearsal netřeba). BOOT SELF-SEED HEXACO ověřen hub i prod:
methodology_versions hexaco-ipip-czactive v1 +methodology_metadataisAssignable=t creditCost=10, log „[REQ-041] Seeded HEXACO (2 phases, 240 items, assignable)", boot healthy RestartCount=0 (idempotentní fail-soft). Prod smoke:/app/200 (0.066s),/api/tenant/me200 (0.09s). Prod gate override (Liborem autorizováno DEPLOY OK hub+prod). QA gate hub stále FAIL jen na stale fixture X-Api-Key (got 401, qa T-074 pending) — ne kód. | 2026-06-19 10:25 UTC | s60-pulse | hub |7fac425| feat(pulse): CR-198 — HEXACO report: 4 akční AI sekce (silné stránky/růstové oblasti/doporučení/další kroky) | ✅ done (qa=skip) | | 2026-06-19 10:28 UTC | s60-pulse | prod |7fac425| feat(pulse): CR-198 — HEXACO report: 4 akční AI sekce (silné stránky/růstové oblasti/doporučení/další kroky) | ✅ done (qa=skipped)Pozn. 7fac425 hub+prod: Bundle 00a16b7→7fac425 (reálně d348713→7fac425, oba env byly na d348713 — pulse baseline „00a16b7" byl neaktuální). CR-198 (HEXACO 4 akční sekce) + REQ-041 F4 (próza) + REQ-040 (klient stepper UX) + REQ-039 lifecycle + LP redirect RLS fix (veřejné SSR routy běží v tenant kontextu — přihlášení nepadali na /app; souvisí s 2026-06-18 /app slowness). db_change=NONE. BOOT RESEED HEXACO v4 ověřen hub+prod:
methodology_versions hexaco-ipip-czactive=v2 (contentVersion 4), v1 archived, log „[REQ-041] Seeded HEXACO v2 (contentVersion 4, 2 phases, 240 items)", boot healthy R=0 (idempotentní fail-soft). Prod smoke/app/200 (0.076s). Prod gate override (Liborem autorizováno). T-074 status: qa dokončil Bearer migraci (Variant B), ale gate stále FAIL — qa-pulse má jen client roli, padající endpointy chtějí admin/system → čeká na auth (povýšit qa-pulse / vydat systémový API klíč). Override maskuje reálnou credentials mezeru, ne flaky test. | | 2026-06-20 05:56 UTC | s60-pulse | hub |4e9d91e| chore(pulse): DEPLOY.md — Current f217739 (CR-199 + migrace 142, db_change=migration) | ✅ done (qa=skip) | | 2026-06-20 06:07 UTC | s60-pulse | prod |4e9d91e| chore(pulse): DEPLOY.md — Current f217739 (CR-199 + migrace 142, db_change=migration) | ✅ done (qa=skipped) |Pozn. 4e9d91e (CR-199 dual-theme redesign) hub+prod — dress rehearsal:
4e9d91e= DEPLOY.md chore nad funkčnímf217739(světlá opt-in varianta; tmavá = prod byte-exact beze změny). Deploy guard zachytil první pokus (DEPLOY.md hlavička staráCurrent: 7fac425 db_change:noneale HEAD měl migraci 142) → pulse opravil DEPLOY.md (T-012). Migrace 142 CR199PricingCutover řeší 2 admin-edited řádky automaticky: (#1) nulujepage_templates.pricing.updatedByPŘED reseedem → reseed naseeduje CR-199 template (přepsán Liborův edit z 8.6., schváleno); (#2) jsonb transformlanding.pricing_packages→ featured-6. Dress rehearsal prod→hub (counts 6/6): migrace+reseed ověřeny proti prod datům — hub pricing tpl 14926→24637 B (theme-light), featured 20kr→6kr. Prod cutover ověřen: pricingupdatedBy→NULL/v109/24637B, landing featured 20 kreditů→6 kreditů „Nejoblíbenější" (PRE: 20kr featured), render/p/pricing+landing 200,/app/200, health R=0. ⚠️ Ruční krok provedl sentinel: Redis flushcontent:landing:livena hub i prod (migrace neumí Redis; bez flushe landing drží starý featured). Pre-upgrade prod dumpprod-pre-cr199-060434Z.dump. Prod gate override (hub QA FAIL = dress-rehearsal prod-mirror data postrádá qa-pulse fixture; real gate 15/15 2026-06-19). Liborem autorizováno. | 2026-06-20 11:52 UTC | s60-pulse | hub |b70b231| chore(pulse): DEPLOY.md — Current 6f0390a (CR-199 + CR-200 bundle, migrace 142) | ✅ done (qa=skip) | | 2026-06-20 11:59 UTC | s60-pulse | prod |b70b231| chore(pulse): DEPLOY.md — Current 6f0390a (CR-199 + CR-200 bundle, migrace 142) | ✅ done (qa=skipped) |Pozn. b70b231 (CR-199+CR-200 bundle) hub+prod: CR-200 přibundlnut k CR-199 (Liborovo rozhodnutí). CR-200 = admin editace metodik + 3-stavová viditelnost (Viditelná/Skrytá/Archivovaná → isArchived/isAssignable) + security fix (
PATCH metadata/:slugbyl bez role guardu → +@Roles('admin')); žádná migrace (jen 142 z CR-199, na produ už aplikovaná → no-op). Bez full dress rehearsal (CR-199 migrace už rehearsovaná+verified, CR-200 nulové data riziko). Hub vrácen na vlastní data (z hub-rollback dumpu, resolved follow-up #1 — po CR-199 dress rehearsal držel prod-mirror). 🔑 ROOT CAUSE recurring QA gate FAIL nalezen: deploy.sh inline gate běží přes SSH na hub serveru se STAROU kopií qa testů (X-Api-Key), ne s qa Bearer migrací (ta je jen v sentinel/cerebro/root/projects/qa). Sentinel-localqa-gate.sh hub pulse= 15/15 PASS (genuine), inline FAIL = stale hub copy. → prod gate prošel bez override (genuine stamp). Eskalováno qa/infra (sync hub qa test copy). CR-199 data intact hub+prod (pricing 24637B/updatedBy NULL, featured 6 kreditů), Redis flush hub+prod, render /p/pricing+landing+/app 200, health R=0. | 2026-06-20 16:15 UTC | s60-pulse | hub |7f573bd| chore(pulse): DEPLOY.md — Current 926f503 (bundle CR-199 + CR-200 + CR-201 + Home/cookie, migrace 142+143) | ✅ done (qa=skip) | | 2026-06-20 16:20 UTC | s60-pulse | prod |7f573bd| chore(pulse): DEPLOY.md — Current 926f503 (bundle CR-199 + CR-200 + CR-201 + Home/cookie, migrace 142+143) | ✅ done (qa=skipped) |Pozn. 7f573bd (CR-199+200+201 bundle) hub+prod — dress rehearsal: Přibyl CR-201 (HEXACO/MCP incident fix: MCP templates draft-only přes admin PublishQueue, cena z creditCost, prázdné regiony → render fallback) + Home/cookie. Migrace 143 CR201ClearBrokenHexacoTemplateContent (vyčistí prázdný live HEXACO region content, defenzivní) + 142 (CR-199, no-op na produ). Dress rehearsal prod→hub: migrace 142+143 ověřeny proti prod datům, CR201 log „prázdné regions vyčištěny → render fallbackuje na React layout", HEXACO loaded v2, featured-6 intact hub+prod, redis flush hub+prod, render /p/pricing+landing+/app 200, health R=0. 🎯 qa vyřešil stale hub test copy (T-023) → deploy.sh inline funkční gate teď 15/15 PASS genuine (Smoke 2/0 Regression 13/0). ⚠️ Nový recurring blocker: deploy-audit FALSE POSITIVE —
qa-deploy-audit.shpouštígit diff migration_from..HEADna pinned-deploy repu cílového serveru, kterýmigration_from(7fac425) NEZNÁ → count 0 → „db_change=migration but no new migration files found" FAIL → smazán stamp. Migrace 142+143 přitom prokazatelně aplikované. Prod gate override (audit FP + funkční 15/15). Eskalováno qa (history-independent check). Pre-upgrade dumpprod-pre-cr201-*.dump. Liborem autorizováno. | 2026-06-20 20:19 UTC | s60-pulse | hub |d67e968| chore(pulse): DEPLOY.md — Current 34a742d (CR-202 Objednávky + Transakce + audit_event, migrace 144+145+146) | ✅ done (qa=pass) | | 2026-06-20 20:23 UTC | s60-pulse | prod |d67e968| chore(pulse): DEPLOY.md — Current 34a742d (CR-202 Objednávky + Transakce + audit_event, migrace 144+145+146) | ✅ done (qa=skipped) |Pozn. d67e968 (CR-202 Objednávky + Transakce + audit_event) hub+prod — dress rehearsal: 3 nové migrace 144 CR202Orders (tabulka
ordersDDL + unique billitInvoiceId + RLS) / 145 CR202AuditEvent (DDL + RLS) / 146 CR202BackfillOrders (per-tenant SET LOCAL backfill historických paid orders z purchase credit_transactions, ON CONFLICT DO NOTHING, read-only vůči ledgeru). ADITIVNÍ + FAIL-SOFT (credit/ledger/webhook flow beze změny; Order+audit vedlejší evidence; billitInvoiceId=idempotency). Bez ENV/build-arg/ručního kroku. Dress rehearsal prod→hub: PRE 6 paid purchase tx → backfill vytvořil přesně 6 orders (hub i prod), RLS prokazatelně enabled (relrowsecurity=t) na orders+audit_event, credit_transactions purchase=6 NEZMĚNĚNO (backfill read-only vůči ledgeru ověřen). 🎯 QA gate FULLY PASSED 15/15 STATUS:OK genuine (deploy-audit už NEpadá — qa fix/migration_from 926f503 resolvuje) → prod gate bez override poprvé u migration-bearing deploye. Pre-upgrade dumpprod-pre-cr202-*.dump. Health R=0, render / + /app 200. Liborem autorizováno. Bokem: billit env ověření pulse prod BILLIT_API_URL=ucto (T-047), qa-gate path zodpovězeno qa (T-048). | 2026-06-20 20:50 UTC | billit | hub |eb19f2a| feat(billit): CR-030 — unified cancel/refund objednávky (jedno volání) | ✅ done (qa=pass) | | 2026-06-20 20:53 UTC | billit | prod |eb19f2a| feat(billit): CR-030 — unified cancel/refund objednávky (jedno volání) | ✅ done (qa=skipped) |Pozn. eb19f2a (CR-030 unified cancel/refund) hub+prod: Nový endpoint
POST /v1/accounts/{slug}/orders/{id}/cancel(idempotentní, existující webhook typy). db_change=none, žádné migrace/env, jen billit-api. 53a9b79→eb19f2a. Hub QA gate PASSED 4/4, prod VERIFIED 2/2 containers (api+web health 200). Cancel endpoint registrovaný hub+prod (POST→401 auth guard, ne 404). Funkční test (cancel na reálné objednávce → cancelled/refunded/noop) = auth'd, dělá billit/Libor. billit.cz/health→301 (DEC-014 redirect na ucto, očekávané). Deploy na pokyn Libora (přímý DEPLOY OK v session). | 2026-06-20 21:25 UTC | s60-pulse | hub |903b411| chore(pulse): DEPLOY.md — Current b0cde9f (CR-203 admin storno/refund, db_change none, žádná migrace) | ✅ done (qa=pass) | | 2026-06-20 21:28 UTC | s60-pulse | prod |903b411| chore(pulse): DEPLOY.md — Current b0cde9f (CR-203 admin storno/refund, db_change none, žádná migrace) | ✅ done (qa=skipped) |Pozn. 903b411 (CR-203 admin storno/refund) hub+prod: admin tlačítko Storno/Refund deleguje na Billit unified endpoint (CR-030, eb19f2a). Jádro = bugfix: Pulse webhook router rozšířen o
order.refunded/invoice.refunded/invoice.credit_note_created→ refund cesta (DŘÍV Pulse tyto eventy IGNOROVALO → refund zaplacené objednávky nevracel kredity; teď i ruční Billit refund zpracován). db_change=none, žádné migrace/env, čistý fast-forward d67e968→903b411. Payment-safe (webhook fail-soft 200, kredity první, 3-vrstvá idempotence). Bez dress rehearsal (no DB change), bez ručního kroku. Hub QA gate PASSED 15/15 genuine (audit fix qa T-050 funguje), prod VERIFIED. Cancel route /api/admin/orders/:id/cancel registrovaný hub+prod (401 guard), BillingWebhookController aktivní, render / + /app 200, health R=0. CR-202 orders intact (6→7, 1 nová reálná objednávka = Order creation živě funguje). Admin tlačítko vyžaduje billit CR-030 live (eb19f2a nasazen) — webhook cesta funguje hned. | 2026-06-20 21:39 UTC | billit | hub |4541b33| feat(billit): CR-031 — refunds (Stripe auto + bankovní/manuální úkol→potvrzení) | ✅ done (qa=pass) | | 2026-06-20 21:41 UTC | billit | prod |4541b33| feat(billit): CR-031 — refunds (Stripe auto + bankovní/manuální úkol→potvrzení) | ✅ done (qa=skipped) |Pozn. 4541b33 (CR-031 refunds + CR-030) hub+prod: CR-031 refunds (Stripe auto refund + bankovní/manuální pending úloha) + refunds modul (api controller/service/dto/entity + web RefundsPage/RefundDialog). db_change=migration
1772740000000-CreateRefunds(nová tabulkarefunds, CREATE TABLE IF NOT EXISTS, additive DDL, žádný backfill). eb19f2a→4541b33. Bez dress rehearsal (nová prázdná tabulka, žádná existující data k transformaci). Hub QA gate PASSED 42/42 (MAJOR tier), prod VERIFIED 2/2 containers. Migrace ověřena hub+prod: tabulkarefundsvytvořena (16 sloupců, prod 0 řádků), refunds endpoint/v1/accounts/{slug}/refundsregistrovaný (401 guard), api health 200, R=0. ⚠️ Stripe refund = REÁLNÉ peníze — deploy refund nespouští, jen přidává schopnost; testuje Libor opatrně. Bank/manual refund jen vytvoří úlohu (peníze neposílá). Deploy na přímý Liborův DEPLOY OK. | 2026-06-21 03:41 UTC | s60-pulse | hub |825c233| chore(pulse): DEPLOY.md — Current 7bf7ae2 (bundle CR-203 + CR-204 + CR-205, db_change none) | ✅ done (qa=pass) | | 2026-06-21 03:44 UTC | s60-pulse | prod |825c233| chore(pulse): DEPLOY.md — Current 7bf7ae2 (bundle CR-203 + CR-204 + CR-205, db_change none) | ✅ done (qa=skipped) |Pozn. 825c233 (bundle CR-203+204+205) hub+prod: Reálná delta nad prod (903b411=CR-203 už live) = CR-204 + CR-205. CR-204 reorganizace admin menu (18 plochých→6 top-level+2 skupiny, jen vizuální nav). CR-205 sjednocené headery (sdílený AppHeader+PublicHeader; /app/m/:slug má teď menu); přihlášený ceník = React /app/pricing (reuse createCheckout, CHECKOUT LOGIKA NEZMĚNĚNA), přihlášený /p/pricing→302 /app/pricing, anon /p/pricing zůstává SSR. db_change=none, čistý fast-forward d67e968→7bf7ae2, žádné migrace/env/ruční krok, bez dress rehearsal. Hub QA gate PASSED 15/15 genuine, prod VERIFIED. Ověřeno hub+prod: anon /p/pricing 200 SSR (featured-6 z CR-199 intact), /app/pricing 200 (React nová), landing + /app 200, health R=0. (CR-203 admin storno tlačítko deleguje na billit CR-030 eb19f2a live.) | 2026-06-21 04:53 UTC | s60-pulse | hub |
83ec9f6| chore(pulse): DEPLOY.md — Current b62b1fa (HOTFIX refund bug + audit stopa, migrace 147) | ✅ done (qa=pass) | | 2026-06-21 04:56 UTC | s60-pulse | prod |83ec9f6| chore(pulse): DEPLOY.md — Current b62b1fa (HOTFIX refund bug + audit stopa, migrace 147) | ✅ done (qa=skipped) |Pozn. 83ec9f6 (🔴 HOTFIX b62b1fa — prod refund bug) hub+prod: Aktivní prod bug: Billit cancel/refund webhook NEposílá externalId (na rozdíl od order.paid) →
parseExternalIdcrash nanull.startsWith→ webhook 500 → refund kreditů + Order stav se NEzpracovaly (objednávka zůstala paid, kredity nevráceny). Root cause přes prod debug API. Fix: parseExternalId null-safe + processTermination clientId fallback z Order → refund proběhne i bez externalId, 3-vrstvá idempotence zachována. + novýorder.cancel_billit_resultaudit_event (durabilní stopa). + CR-206 part 1 backend (orders.cancelRequestedAt marker). Migrace 147 CR206OrderCancelRequestedAt (orders.cancelRequestedAt, ADD COLUMN IF NOT EXISTS, bez backfillu) — bez dress rehearsal (triviální additive DDL). 825c233→83ec9f6, žádné env/ruční krok. Hub QA gate PASSED 15/15 genuine, prod VERIFIED. Ověřeno hub+prod: migrace 147 aplikována, sloupec orders.cancelRequestedAt existuje, orders=7 intact, render / + /app 200, health R=0. Funkční refund E2E (signed webhook bez externalId) = Liborova prod session (test objednávka PF-2026-0002). Dev: 1387/1387 + E2E přesného prod scénáře, reviewer PASS 7 payment-critical bodů. | 2026-06-21 05:09 UTC | billit | hub |f15d743| docs(deploy): CR-033 do bundlu s CR-032 (3e78eee) — DEV_AUTH gate, env warning | ✅ done (qa=skip) | | 2026-06-21 05:11 UTC | billit | prod |f15d743| docs(deploy): CR-033 do bundlu s CR-032 (3e78eee) — DEV_AUTH gate, env warning | ✅ done (qa=skipped) |Pozn. f15d743 (CR-032 refunds entity + 🔒 CR-033 security) hub+prod: Scope se rozšířil za briefing (Libor briefován na CR-032/3ed69ea, master mezitím na f15d743 = +CR-033) → re-briefováno, Libor schválil f15d743 + odstranění hub DEV_AUTH. 🔒 CR-033 = SECURITY-CRITICAL: JwtAuthGuard honoroval
X-User-Id/Emailhlavičky BEZ tokenu i na PRODU → kdokoliv = superadmin (živá auth-bypass díra). Fix: X-User funguje jen přiDEV_AUTH=true. Finding: hub mělDEV_AUTH=truev/root/secrets/billit/.env.hub→ odstraněn (backup.env.hub.bak-20260621-devauth), deploy syncnul env bez něj. Ověřeno hub+prod: X-User bez tokenu → 401 (dřív superadmin), DEV_AUTH pryč z obou containerů. CR-032: refunds vždy přes Refund entitu + Stripe-fail fallback + completedBy provenance; migraceRefundCompletedBy(ALTER refunds ADD completed_by) aplikována hub+prod. Hub QA gate FAIL 2/4 = billit testy EXPLOITOVALY ten X-User backdoor (auth bez tokenu) → CR-033 ho zavřel → 401; NE regrese, security fix funguje. Prod gate override (dokumentováno). Eskalováno qa: billit QA testy potřebují Bearer migraci (jako pulse T-074). Pre-upgrade dumpbillit-prod-pre-cr032-*.dump. health R=0. ⚠️ Po CR-033 X-User auth nefunguje na hub/prod → debug přes Bearer. Funkční refund E2E = Liborova prod session (test obj. PF-2026-0002). | 2026-06-21 08:34 UTC | s60-pulse | hub |a44f1f2| chore(pulse): DEPLOY.md — Current 3ffe87d (CR-206 UI, db_change none); b62b1fa hotfix LIVE na produ | ✅ done (qa=pass) | | 2026-06-21 08:36 UTC | s60-pulse | prod |a44f1f2| chore(pulse): DEPLOY.md — Current 3ffe87d (CR-206 UI, db_change none); b62b1fa hotfix LIVE na produ | ✅ done (qa=skipped) |Pozn. a44f1f2 (CR-206 UI follow-up) hub+prod: Navazuje na hotfix b62b1fa (83ec9f6, už live). Jen admin UI: znovupoužitelné OrdersTable/TransactionsTable (globální stránky=wrappery + clientId filtr v ClientDetail) + badge „Refund požadován" + ClientDetail konsolidace (tab Platby = transakce+objednávky filtr na klienta, sloučené Chyby&hlášení, Kredity rename). db_change=none, žádné migrace/env/ruční krok, čistý fast-forward 83ec9f6→a44f1f2 (7 souborů admin UI). Bez dress rehearsal. Hub QA gate PASSED 15/15 genuine, prod VERIFIED. Ověřeno hub+prod: /admin/ 200, / + /app/ + /p/pricing 200, orders=7 intact, health R=0. | 2026-06-21 11:19 UTC | s60-pulse | hub |
f5cc62c| chore(pulse): DEPLOY.md — Current 45ef915 (CR-206 reconcile hotfix-2, db_change none) | ✅ done (qa=pass) | | 2026-06-21 11:22 UTC | s60-pulse | prod |f5cc62c| chore(pulse): DEPLOY.md — Current 45ef915 (CR-206 reconcile hotfix-2, db_change none) | ✅ done (qa=skipped) |Pozn. f5cc62c (🔴 HOTFIX-2 45ef915 — CR-206 refund reconcile) hub+prod: Navazuje na refund incident. Bug: objednávka refundovaná na Billitu ale Pulse zmeškal webhook (původní crash, fix HOTFIX-1) → Order paid, kredity nevrácené; re-klik refund → Billit noop (terminal) → Pulse dřív NIC → out-of-sync navždy. Fix: admin cancel aplikuje terminal stav z Billit SYNCHRONNÍ odpovědi přes sdílenou
applyTerminalRefund→ dosynchronizuje zaseklou objednávku i normální flow; idempotentní (sdílí refund-${id} guard). db_change=none, backend only, čistý fast-forward a44f1f2→f5cc62c. Hub QA gate PASSED 15/15 genuine, prod VERIFIED, health R=0, /admin+/app 200. Recovery PF-2026-0002 = Libor re-klikne Refund v adminu. Dev 1391/1391, reviewer PASS. | 2026-06-21 18:43 UTC | s60-pulse | hub |13ba7ca| chore(pulse): DEPLOY.md — Current 689f73c (DEC-015 + CR-207, db_change none); prod LIVE 45ef915 | ✅ done (qa=pass) | | 2026-06-21 18:46 UTC | s60-pulse | prod |13ba7ca| chore(pulse): DEPLOY.md — Current 689f73c (DEC-015 + CR-207, db_change none); prod LIVE 45ef915 | ✅ done (qa=skipped) |Pozn. 13ba7ca (DEC-015 + CR-207) hub+prod — dress rehearsal: DEC-015 druh metodiky (chat/questionnaire) jako capability registr + oprava (abandonSession uvolňoval kredit i u dotazníku s progressem) + HEXACO boot reseed contentVersion 5. CR-207 HEXACO grounded AI komentář (deep interpretation pass na Opus 4.8 fail-soft + anti-halucinační guard + ověřování + /api/debug/ guard). Vč. nikdy nenasazeného 47e8a4c (HEXACO choice-session fix). db_change=none, env
PULSE_DEEP_MODELvolitelné (default claude-opus-4-8, fail-soft, na produ NEnastaveno → default). Čistý fast-forward f5cc62c→13ba7ca. Dress rehearsal prod→hub: HEXACO reseed v5 ověřen proti prod datům hub+prod (active version 3/contentVersion 5, v1+v2 archived, log „Seeded HEXACO v3 contentVersion 5"), boot healthy R=0 (žádný DI cyklus). Hub QA gate PASSED 15/15 genuine*, prod VERIFIED, render / + /app + /admin 200. ⚠️ Deep pass se spustí až při generování HEXACO výstupu (ne na bootu) → fail-soft, ověření jestli prod ANTHROPIC key zvládá Opus 4.8 = až při reálném výstupu (admin badge flagne fail-soft). Dev 1427/1427, reviewer PASS. | 2026-06-21 19:26 UTC | s60-pulse | hub |54da302| chore(pulse): DEPLOY.md — Current b72a930 (CR-207 prod fix: Opus temperature + AI-array-as-string) | ✅ done (qa=pass) | | 2026-06-21 19:34 UTC | s60-pulse | prod |54da302| chore(pulse): DEPLOY.md — Current b72a930 (CR-207 prod fix: Opus temperature + AI-array-as-string) | ✅ done (qa=skipped) |Pozn. 54da302 (kód b72a930 — CR-207 deep-pass prod fix) hub+prod — dress rehearsal: Opravuje deep pass odhalený na 13ba7ca: (1)
temperaturedeprecated pro Opus 4.8 → deep pass spadlAI_INVALID; fix=neposílat temperature. (2) AI vrátil combos pole jako JSON-string → prázdné karty; fix=asArray() koerce. db_change=none, čistý fast-forward 13ba7ca→54da302. Hub QA gate PASSED 15/15 genuine, prod VERIFIED, render / + /app + /admin 200, health R=0, HEXACO stále active v3/contentVersion 5 (idempotentní). Dress rehearsal deep-pass verifikace (regenerace HEXACO outputu na hub clone): ✅ fix #1 potvrzen — žádnýAI_INVALID(deep pass už nespadne), anti-halucinační guard běžel. ⚠️ deep Opus obsah se na hub NEvygeneroval — log[CR-207] … fallback: Růstové oblasti, Další kroky, Zajímavé kombinace→ fail-soft na deterministický (Opus na hub env nedostupný) → fix #2 (combos jako pole) z hub clonu NEpotvrditelný. Plná verifikace deep obsahu = jen prod (regenerace Moniky Webster). ⚠️⚠️ OTEVŘENÁ OTÁZKA: dosáhne prod kontejner na Opus 4.8? — pokud prod taky fail-softne jako hub, deep feature degradovaná i na produ (chce key/egress fix / PULSE_DEEP_MODEL override). Dev: 1432/1432, deepGenerated true. ✅ VYŘEŠENO regenerací Moniky na produ (debug key /api/debug/outputs/:id/regenerate, sync): deep pass běžel 3,5 min (Opus reálně volán),[CR-207] 1 slabé místo fallback Další kroky(jen 1 sekce, vs 3 na hub) → prod NA Opus 4.8 DOSÁHNE; combositems= PRAVÉ POLE (fix #2 potvrzen), bohatý grounded deep komentář, json_len 16296→22768; Moničin output opraven. Hub fail-soft = hub-env (Opus nedostupný), ne kód. | 2026-06-21 21:55 UTC | s60-pulse | hub |1bf067b| chore(pulse): DEPLOY.md — Current d97541b (async output fix + REQ-042 + CR-207 + DEC-015, db_change none) | ✅ done (qa=pass) | | 2026-06-21 21:58 UTC | s60-pulse | prod |1bf067b| chore(pulse): DEPLOY.md — Current d97541b (async output fix + REQ-042 + CR-207 + DEC-015, db_change none) | ✅ done (qa=skipped) |Pozn. 1bf067b (kód d97541b — async output fix + REQ-042) hub+prod: Nad nasazený 54da302 (DEC-015+CR-207). 🔴 Async output fix: completion konzultace generoval output SYNCHRONNĚ v requestu (HEXACO deep Opus ~4 min → request timeout, output nevidět, deep selhal — přesně sync-timeout, na který jsem narazil při manuální regeneraci Moniky 27c2bff0, curl 000/3,5 min). Fix: completion → enqueueGeneration (BullMQ worker pulse-output-gen), dokončuje CR-140. REQ-042: export/import konzultace napříč prostředími (admin, bez kreditu/outputu/auditu importu). db_change=none, 0 migrací, env PULSE_DEEP_MODEL volitelné (nenastaveno). Hub QA gate PASSED 15/15 genuine, prod VERIFIED. Ověřeno hub+prod: OutputQueueService worker ACTIVE (concurrency=5, queue=pulse-output-gen) + AI queue started, render / + /app + /admin 200, health R=0. Pulse potvrdil Opus 4.8 access OVĚŘEN (shoda s mým prod nálezem u 54da302). PO DEPLOYI (Libor): přegenerovat HEXACO Robin Vondrašek + Monika Webster (teď přes worker → deepGenerated) + REQ-042 E2E export/import. Dev 1454/1454, reviewer PASS. | 2026-06-22 05:29 UTC | s60-pulse | hub |
4938dd8| chore(pulse): DEPLOY.md — Current 296519d (REQ-042 import fixy: completed auto-enqueue + contentVersion warning) | ✅ done (qa=pass) | | 2026-06-22 05:32 UTC | s60-pulse | prod |4938dd8| chore(pulse): DEPLOY.md — Current 296519d (REQ-042 import fixy: completed auto-enqueue + contentVersion warning) | ✅ done (qa=skipped) |Pozn. 4938dd8 (kód 296519d — REQ-042 import fixy) hub+prod: Z Liborova prod ostrého testu REQ-042: (1) falešný version warning → srovnává jen logickou contentVersion (ne row-version per-prostředí counter dev v2 vs prod v3); (2) completed import bez výstupu (klient „od začátku") → import COMPLETED konzultace auto-enqueuuje generování výstupu přes async worker (SessionService +OutputService forwardRef, bez DI cyklu); (3) tlačítko „Import konzultace" v ClientDetail (cíl předvyplněn). db_change=none, 0 migrací, čistý fast-forward 1bf067b→4938dd8 (7 souborů). Hub QA gate PASSED 15/15 genuine, prod VERIFIED, OutputQueueService worker ACTIVE (žádný DI cyklus), render / + /app + /admin 200, health R=0. Dev 1457/1457, reviewer PASS. | 2026-06-22 19:54 UTC | billit | hub |
ef516b6| feat(billit): CR-041 — suppressEmails na checkout (Pulse = email master) | ⚠️ hub kód OK, MIGRACE BLOKOVÁNY (prod NEnasazen) |Pozn. ef516b6 (REQ-046 e-shop + 6 CR + 8 migrací) — DRESS REHEARSAL ZACHYTIL MIGRAČNÍ BUG, PROD NENASAZEN: Velká billit dávka (security CR-038, REQ-046 stavové sety/fulfillment, 8 migrací vč. seed-per-tenant + 2 backfilly + RepairPhantomRefunds). Dress rehearsal clone prod billit→hub (orders 38, refunded 2/phantom, refunds 0, tenants 14): hub kód ef516b6 deploynut (handlebars build OK), ale 8 migrací NEPROBĚHLO —
1772780000000-SeedDefaultOrderStatusSetpadáPostgresError 42P08 text versus character varying(position 133, variable_coerce_param_hook, up() line 30); migrace běží v 1 transakci → všech 8 rollbacknuto, 0 aplikováno. Příčina: param type inference (tenants.id=uuid; prod schema column typy varchar vs text) — prošlo na dev (886/886), padá na prod-schema clonu. By spadlo i na produ → prod ZABLOKOVÁN. Doporučený fix billitu: explicitní casty$1::uuid/$2::varcharv seed migraci. Eskalováno billit (T-20260622-041). Bonus nález: hub billit-api[ioredis] WRONGPASS(Redis auth, BullMQ, non-blocking). Hub drží ef516b6 kód + prod-mirror schema (e-shop featury nefunkční) — čeká na billit fix → re-run dress rehearsal. Prod billit zůstává f15d743 (CR-031/032/033, beze změny). | 2026-06-22 20:22 UTC | billit | hub |3ec94ad| fix(billit): SeedDefaultOrderStatusSet — explicitní ::casty na params (42P08 fix) | ⚠️ fail (qa=skipped) | | 2026-06-22 20:26 UTC | billit | hub |3ec94ad| fix(billit): SeedDefaultOrderStatusSet — explicitní ::casty na params (42P08 fix) | ✅ done (qa=skip) | | 2026-06-23 03:58 UTC | billit | hub |3d82f3a| fix(billit): RepairPhantomRefunds — safety backfill status_set_id/status_id (sentinel nález) | ⚠️ fail (qa=skipped) | | 2026-06-23 04:08 UTC | billit | hub |3d82f3a| fix(billit): RepairPhantomRefunds — safety backfill status_set_id/status_id (sentinel nález) | ✅ done (qa=skip) | | 2026-06-23 04:11 UTC | billit | prod |3d82f3a| fix(billit): RepairPhantomRefunds — safety backfill status_set_id/status_id (sentinel nález) | ✅ done (qa=skipped) |Pozn. 3d82f3a (REQ-046 e-shop engine + CR-034/036/038/039/040/041 + 8 migrací) hub+prod — VYŘEŠENO po 2 dress-rehearsal nálezech: Velká billit dávka (security CR-038 ApiKeyTenantGuard cross-tenant leak fix, REQ-046 stavové sety/orchestrátor/fulfillment/Handlebars emaily/refund↔order, CR-034 přijaté faktury, CR-040 admin bulk-grant, CR-041 suppressEmails). 8 migrací vč. seed-per-tenant + 2 backfilly + RepairPhantomRefunds. Nová dep handlebars. Cesta: ef516b6 → dress rehearsal #1 zachytil 42P08 (SeedDefaultOrderStatusSet text-vs-varchar param inference) → billit fix 3ec94ad (explicitní ::casty) → dress rehearsal #2 zachytil status_id gap (2 repaired phantomy paid bez status_id, LEGACY_STATUS_MAP nemapoval refunded) → billit fix 3d82f3a (safety backfill v RepairPhantomRefunds) → dress rehearsal #3 ZELENÝ. Prod ověřeno: 8 migrací, order_status_sets=14 (per tenant), status_id NULL=0 (38/38), orders_refunded 2→0 (phantomy paid+status_id), order_events/shipments+refunds.order_id, labely 2/2, oba containery healthy R=0. Prod gate: hub-ok refresh (re-run kvůli stale stamp >2h) + QA override (X-User backdoor blocker, qa ApiKey pending). Pre-upgrade dump billit-prod-pre-ef516-.dump. POST-DEPLOY (billit/Libor):* CR-038 cross-tenant 403 přes debug API + refund E2E z Pulse. Bonus: hub Redis WRONGPASS (separátní infra). Dress rehearsal zachytil 2 prod-breaking/data-integrity bugy PŘED produkcí. | 2026-06-23 04:18 UTC | s60-pulse | hub |
47e5777| chore(pulse): DEPLOY.md — Current 546918d (REQ-043 admin obsah metodik + NFR-008 N2 + checkout fix, mig 148) | ✅ done (qa=skip) | | 2026-06-23 04:28 UTC | s60-pulse | prod |47e5777| chore(pulse): DEPLOY.md — Current 546918d (REQ-043 admin obsah metodik + NFR-008 N2 + checkout fix, mig 148) | ✅ done (qa=skipped) |Pozn. 47e5777 (kód 546918d — REQ-043 + checkout fix + REQ-042 warning) hub+prod: Delta nad 4938dd8 (4938dd8 ancestor → bez regrese): 50b4cea (REQ-042 questionnaire warning + admin URL-tab), 9894058 (checkout potvrzení fix — /app/pricing už nevytvoří objednávku bez potvrzení v CheckoutDialog), 546918d (REQ-043 admin download/upload obsahu metodik + NFR-008 N2 cache). db_change=yes: migrace 148 REQ043MethodologyContentFiles (CREATE TABLE methodology_content_files + RLS, additive DDL; HEXACO items/config/norms self-seed z assetů onModuleInit idempotentní). Bez dress rehearsal (nová prázdná tabulka). Ověřeno hub+prod: migrace 148 aplikována, tabulka methodology_content_files vytvořena, HEXACO active v3 intact, health R=0, render / + /app + /admin + /app/pricing 200. QA gate: deploy-time inline FAIL byl TRANSIENT (gate běžel během boot self-seedu/migrace) → sentinel-local i inline re-run 15/15 PASS genuine, stamp written. Dev 1481/1481. | 2026-06-23 05:28 UTC | billit | hub |
0bf1b3d| feat(billit): CR-037 — cross-tenant:read bypass v ApiKeyTenantGuard (Cortex parity) | ✅ done (qa=skip) | | 2026-06-23 05:31 UTC | billit | prod |0bf1b3d| feat(billit): CR-037 — cross-tenant:read bypass v ApiKeyTenantGuard (Cortex parity) | ✅ done (qa=skipped) |Pozn. 0bf1b3d (CR-037 cross-tenant:read bypass + DES-001 web menu + public faktura fix) hub+prod: Pro Cortex↔Ucto banking parity (REQ-043) — Cortex potřebuje cross-tenant READ, ale CR-038 ApiKeyTenantGuard to blokoval. Řešení (sentinel návrh, bez migrace): ApiKeyTenantGuard bypassuje tenant-match když
apiKeyPermissions['cross-tenant:read']===true(+ audit warn log; CR-039 TenantTripwire taky loguje). Billit interní-only → trusted system klíč napříč tenanty OK. Delta nad 3d82f3a veze i DES-001 (billit-web menu restrukturalizace) + public faktura „Zpět do obchodu" fix (Liborem odsouhlaseno). db_change=none. Hub+prod VERIFIED labely 2/2. Bypass ověřen hub i prod: test cross-tenant klíč → cizí slugpulse/bank-accounts → 200 (ne 403), guard log potvrzen; normální klíč na cizí slug dál 403. Prod gate: hub-ok refresh + QA override (X-User blocker). Cortex klíč VYTVOŘEN na prod DB (api_keys: tenant studio-60, name cortex-banking-parity-REQ043, permissions {cross-tenant:read, read:invoices, read:accounting}, READ-only, prefix blt_2200…) — ověřen externě (ucto.studio60.cz/api/v1/accounts/{slug}/bank-transactions → 200 cross-tenant, bez auth 401). Raw klíč doručen cs přes Runner relay (Tailscale, [[feedback_relay_safe]]) → UCTO_API_KEY na Cortex /opt/s60-cs/.env (auth headerAuthorization: ApiKey, NE X-Api-Key). REQ-043 API key task UZAVŘEN ze sentinel strany.Hub Redis WRONGPASS FIX (2026-06-23): billit hub container hlásil
[ioredis] WRONGPASS— billit hub.env.hubměloREDIS_PASSWORD=7fb7703d…ale hubs60-redisrequirepass=changeme123(z compose). Fix:/root/secrets/billit/.env.hubREDIS_PASSWORD→changeme123 (backup.env.hub.bak-20260623-redis; MAIL_REDIS_PASSWORD už správné),deploy.sh billit hub --skip-buildre-sync env + restart → WRONGPASS pryč, BullMQ queues connected (Email/BankEmail/Export workers listening), health R=0. Prod billit Redis byl OK (PONG), rozbitý jen hub. | 2026-06-23 05:40 UTC | billit | hub |0bf1b3d| feat(billit): CR-037 — cross-tenant:read bypass v ApiKeyTenantGuard (Cortex parity) | ✅ done (qa=skip) | | 2026-06-23 13:35 UTC | s60-pulse | hub |a469dd1| chore(pulse): DEPLOY.md — Current b2589a1 (review fixy: 11 nálezů, mig 148+149+150) | ✅ done (qa=pass) | | 2026-06-24 01:44 UTC | s60-pulse | hub |a469dd1| chore(pulse): DEPLOY.md — Current b2589a1 (review fixy: 11 nálezů, mig 148+149+150) | ✅ done (qa=pass) | | 2026-06-24 01:47 UTC | s60-pulse | prod |a469dd1| chore(pulse): DEPLOY.md — Current b2589a1 (review fixy: 11 nálezů, mig 148+149+150) | ✅ done (qa=skipped) |Pozn. a469dd1 (kód b2589a1 — CR-208 email master + REQ-043 + 11 review fixů) hub+prod — dress rehearsal + adversariální workflow: Nahrazuje buggy 12ee26a (ultracode review 31+12 agentů odhalil 3 high bugy). Delta nad nasazený 47e5777 (ancestor → bez regrese): CR-208 (Pulse=email master, suppressEmails:true → Billit + faktura v mailu), checkout CTA, ceník back-link, 11 review fixů. db_change: 2 nové migrace (148 už dřív): 149 CR208ResetOrderCreatedEmail (DATA: DELETE+reseed order-created email per tenant, admin-edits chráněné updatedBy!=NULL), 150 REQ043OneActiveContentFile (partial unique index uq_mcf_one_active). Dress rehearsal prod→hub + 7-dimenzní adversariální verifikační workflow (7/7 PASS): mig149 reseed (invoice_url HTML, 6/6 šablon intaktních), mig150 index (UNIQUE partial, 0 aktivních duplicit, RLS FORCED), CR-208 (suppressEmails obě cesty + faktura v mailu), review H1 cizí-faktura (CheckoutDialog key-remount + clientId server-side), H2 SD=0 (norms positive().finite() validace), H3 cross-tenant HEXACO (per-tenant cache + DEFAULT-tenant-only bridge + fail-fast), health/render. Prod ověřeno: mig 149+150 aplikovány, order-created reseednut (invoice_url, updatedBy NULL), email_templates 6/6, uq_mcf_one_active live, 0 aktivních duplicit, health R=0, render / + /app + /admin + /p/pricing 200. Hub QA gate genuine PASS (bez override). Defense-in-depth concerny (ne blockery, eskalováno pulse): SD=0 guard jen na validační vrstvě (ne inline u dělení hexaco-scoring.ts:177,196); cross-tenant HEXACO fix spoléhá na guardy kolem procesově-globálního
_overridebridge (OK pro single-DEFAULT-tenant). CR-208 suppressEmails účinný (billit CR-041 nasazený). Dev 1493/1493. | 2026-06-24 03:04 UTC | s60-pulse | hub |f8844eb| chore(pulse): DEPLOY.md — Current aa159ae (REQ-044 Ecomail sync + REQ-035 F2 consent + GTM, mig 151) | ✅ done (qa=pass) | | 2026-06-24 03:07 UTC | s60-pulse | prod |f8844eb| chore(pulse): DEPLOY.md — Current aa159ae (REQ-044 Ecomail sync + REQ-035 F2 consent + GTM, mig 151) | ✅ done (qa=skipped) |Pozn. f8844eb (kód aa159ae — REQ-044 Ecomail + REQ-035 F2 consent + GTM) hub+prod: Nad nasazený a469dd1 (ancestor → bez regrese): REQ-044 Ecomail contact sync PRODUCER (queue ecomail-contact-sync; s60-mail consumer z REQ-006), REQ-035 F2 email-marketing consent (Settings opt-in toggle), GTM purchase event v app checkoutu (de460de, CR-187 AC#3, client-only). db_change: migrace 151 REQ035REQ044ClientConsentLastSeen — clients ADD COLUMN marketingEmailConsent (default false) + marketingEmailConsentAt + lastSeenAt (čistě additive DDL). Bez dress rehearsal (additive DDL, žádná data-migrace). Hub QA gate genuine PASS. Ověřeno hub+prod: mig 151 + 3 sloupce na clients, prod 57 clientů marketingEmailConsent=false (opt-in default), health R=0, render / + /app + /admin + /p/pricing 200. ⚠️ F5 NEzahrnuto — admin Ecomail provider config přes s60-mail chybí S60_MAIL_URL → producer emituje, s60-mail bez per-tenant configu no-opne (bezpečné); end-to-end Ecomail sync až po nastavení s60-mail configu. CR-208 suppressEmails účinný (billit CR-041 live). Dev 1504+11+9 testů. | 2026-06-25 04:05 UTC | billit | hub |
e527e01| feat(billit): CR-045 — editor faktury: referenční číslo objednávky + render nového kontaktu | ✅ done (qa=skip) | | 2026-06-25 04:12 UTC | billit | hub |e527e01| feat(billit): CR-045 — editor faktury: referenční číslo objednávky + render nového kontaktu | ✅ done (qa=skip) | | 2026-06-25 04:14 UTC | billit | prod |e527e01| feat(billit): CR-045 — editor faktury: referenční číslo objednávky + render nového kontaktu | ✅ done (qa=skipped) |Pozn. e527e01 (MAJOR batch: REQ-043 Fio + CR-042/044/045 + 3 migrace vč. DESTRUKTIVNÍ) hub+prod — dress rehearsal + 6-dim adversariální workflow: Konsolidovaný pending batch nad live 0bf1b3d (ancestor → bez regrese). 3 migrace: 148-Fio SeedFioParityTenantsAccounts (2 tenanti alteredu+byznys-partak + 7 Fio účtů), DropPlanAndStripeSubscriptionFields (CR-044 DESTRUKTIVNÍ — DROP 5 subscription sloupců na tenants: plan + 4 stripe_subscription*; nevratná ztráta, záměr Účto interní-only), FixSettlementTenantFkCascade (CR-045 — 5 FK order_vendor_splits/payouts/platform_invites → ON DELETE CASCADE). Kód: CR-042 (refund→opravný daňový doklad, enum REFUNDED), CR-044 (odstranění předplatného api+web), CR-045 (order_number+kontakt editor). Povinný pre-deploy prod backup
billit-prod-PRE-e527e01-040228Z.dump. Dress rehearsal prod→hub + 6-dim adversariální workflow (6/6 PASS): drop-correct (PŘESNĚ 5 subscription pryč, 4 platební KEEP intaktní, žádný collateral), keep-invariants (stripe-payments modul + webhook raw parser + stripe_events + /i/:token/pay routy intaktní — CR-044 smazal modules/billing/ NE payments), fio-seed (2 tenanti + 7 účtů token NULL), fk-cascade (5 FK CASCADE 0 orphanů), idempotence (guarded SQL), health. Prod ověřeno: 5 DROP sloupců=0, 4 platební KEEP, 3 migrace, 2 tenanti, 7 Fio účtů, oba containery healthy R=0, api 200. REQ-043 Fio token write HOTOVÝ:* 8 Fio tokenů z Cortexu /opt/s60-cs/.env → prod bank_accounts.fio_api_token (Cortex→prod psql přes pipe, hodnota nikdy zprávou/logem), všech 8 účtů connection_type=fio_api + token přítomný. ⚠️ Funkční validace tokenů (/fio/test-connection + cs parity guard) = billit/cs. Prod gate QA override (X-User blocker). Pozn.: CR-037 v batchi už live z 0bf1b3d. | 2026-06-25 05:15 UTC | s60-pulse | hub |a0829e8| feat(pulse): REQ-044 — týdenní cron pro segment neaktivni-90d (Ecomail) | ✅ done (qa=pass) | | 2026-06-25 05:18 UTC | s60-pulse | prod |a0829e8| feat(pulse): REQ-044 — týdenní cron pro segment neaktivni-90d (Ecomail) | ✅ done (qa=skipped) |Pozn. a0829e8 (REQ-044 týdenní cron neaktivni-90d) hub+prod — čistý fast-forward: Reálná delta nad prod LIVE
f8844eb(=aa159ae+ DEPLOY.md doc commit, obsahově identické) = 2 commity:a0829e8cron feat +0a86c46spec doc. Žádná NOVÁ migrace (git diff f8844eb..a0829e8 čistý), env/build beze změny. Obsah: cronsyncInactiveSegment(@Cron '0 4 * * 1', po 04:00 UTC) v EcomailContactSyncService — per aktivní tenant (findAllActiveIds + runWithTenant RLS-scoped) re-sync souhlasících klientů s lastSeenAt>90d → ecomail-contact-sync tagpulse:neaktivni-90d; idempotent, fail-soft, @Optional deps. Nesoulad deploy.shdb_change:yes mig 151: DEPLOY.md @ a0829e8 má ještě hlavičku## Current: aa159ae(bump na a0829e8 je až ve follow-up a330546, nedeployován) → deploy.sh četl aa159ae deklaraci;migration:run= no-op ("No migrations are pending", mig 151 už LIVE z aa159ae 2026-06-24). Hub QA 15/15 PASS genuine, prod ScheduleModule initialized + Nest started bez chyb, oba healthy R=0, commit+source-hash VERIFIED, labely 1/1. ⏳ Funkční efekt cronu až po per-tenant Ecomail configu (REQ-006, čeká mail ric + Liborovy Ecomail creds). | 2026-06-25 05:33 UTC | billit | hub |ec40274| fix(billit-api): REQ-043 korekce — Studio 60 EUR účet 2503366812 → 2402440913 (cs ověřeno proti Fio) | ✅ done (qa=skip) | | 2026-06-25 05:37 UTC | billit | prod |ec40274| fix(billit-api): REQ-043 korekce — Studio 60 EUR účet 2503366812 → 2402440913 (cs ověřeno proti Fio) | ✅ done (qa=skipped) |Pozn. ec40274 (REQ-043 korekce Studio 60 EUR Fio účtu + web titulek) hub+prod — OPRAVA e527e01 Fio chyby: Delta nad LIVE e527e01 = 2 commity:
ec40274fix(api) +faa4161fix(web) (HTML titulek 'Fakturace jednoduše' → 'Studio 60 Účto', rebrand). Migrace1772870000000-FixStudio60EurFioAccount(db_change minor, idempotentní, dev-validovaná): e527e01 Fio seed přidal omylem PRÁZDNÝ studio-60 EUR účet2503366812/2010(0 €, nepoužívaný); cs/Cortex ověřil proti Liborovu úplnému Fio seznamu, že aktivní Studio 60 EUR je2402440913/2010(4,18 €, IBAN CZ26…2402440913, FIOBCZPPXXX). Migrace: DELETE2503366812(scoped slug+číslo) + INSERT2402440913(fio_api, token NULL, pairing_enabled);down()no-op. Dopad na e527e01 token write: v e527e01 jsemFIO_TOKEN_S60_EURomylem zapsal na špatný2503366812— migrace ten účet smazala (i s misplaced tokenem), takže chyba auto-opravena. Post-deploy: přepsánFIO_TOKEN_S60_EURz Cortexu →2402440913(Cortex→prod psql přes pipe, hodnota nikdy zprávou/logem). Ověřeno hub+prod:2503366812PRYČ,2402440913přítomný; prod = přesně 8 fio_api účtů všechny s tokenem (Studio 60 EUR teď míří na aktivní účet), ostatních 7 nedotčeno. QA gate FAIL = známý X-User backdoor blocker (CR-033, T-020) → prod gate override (migrace se auth netýká). Pozn.: další cs korekce (smazat inner-sense2801584621, proxinia tenant status) NEjsou v této migraci — řeší cs/sentinel přes Libora separátně. ⚠️ Funkční validace 8 tokenů (/fio/test-connection) zůstává na billit ric. | 2026-06-26 04:55 UTC | s60-mail | hub |204f084| fix(mail): Ecomail v2 API endpoints (host + tagy + delete) [CR-002] | ✅ done (qa=pass) | | 2026-06-26 05:02 UTC | s60-mail | prod |204f084| fix(mail): Ecomail v2 API endpoints (host + tagy + delete) [CR-002] | ✅ done (qa=skipped) |Pozn. s60-mail 204f084 (REQ-006 multi-provider gateway + CR-001 + CR-002) hub+prod — velký backlog z dubna: LIVE bylo
6a3a41ez 2026-04-25. Delta nese REQ-006 multi-provider gateway (Ecomail+Resend + kontakt sync), CR-001 reply_to + dual-domain inbound (in.studio60.cz/in.billit.cz), CR-002 Ecomail v2 API fixy. Nová env:PROVIDER_ENCRYPTION_KEY(sentinel vygenerovalopenssl rand -hex 32per env, různý hub/prod, do/root/secrets/mail/.env.{hub,prod}, hodnota nikdy v logu),RESEND_ADMIN_API_KEY(už byl). MigraceCreateEmailProviderConfigs(tabulkaemail_provider_configs, 8 sloupců + unique + index) ověřena aplikovaná hub+prod. ⚠️ DVA tooling bugy (nezpůsobily škodu, reportovány): (1) deploy.ymlmigration_command: npm run migration:run→node dist/run-migrations.jskterý se NEkompiluje do dist → každý mail deploy hlásí migrace WARNMODULE_NOT_FOUND; migrace se reálně aplikuje přes app bootmigrationsRun(proto tabulka existuje) — TODO mail; (2) prod gate name+location mismatch — qa-gate.sh resolvuje s60-mail→mail (services.json) a píšemail-qa-passNA HUB, deploy.sh hledá sentinel-locals60-mail-qa-pass→ false block; QA genuinně prošel 3/3 → zapsán správně-pojmenovaný lokální stamp (ne override failu) — TODO qa/infra. Odblokovává pulse REQ-044. ⚠️ Ecomail provider config SEED (api_key/list_id/sender) = separátní post-deploy krok, čeká na Liborovy Ecomail creds bezpečným kanálem (NE relay). | 2026-06-26 05:10 UTC | billit | hub |ec941bf| fix(billit-api): GET /v1/accounts 500 pro API klíč — cross-tenant:read list tenantů (cs/Cortex) | ⚠️ fail (qa=skipped) | | 2026-06-26 05:14 UTC | billit | hub |ec941bf| fix(billit-api): GET /v1/accounts 500 pro API klíč — cross-tenant:read list tenantů (cs/Cortex) | ✅ done (qa=skip) | | 2026-06-26 05:17 UTC | billit | prod |ec941bf| fix(billit-api): GET /v1/accounts 500 pro API klíč — cross-tenant:read list tenantů (cs/Cortex) | ⚠️ fail (qa=skipped) | | 2026-06-26 05:18 UTC | billit | prod |ec941bf| fix(billit-api): GET /v1/accounts 500 pro API klíč — cross-tenant:read list tenantů (cs/Cortex) | ✅ done (qa=skipped) |Pozn. billit ec941bf (3 service bugfixy, db_change none) hub+prod — odblokuje cs REQ-043: Delta nad LIVE
ec40274= 3 commity, ŽÁDNÁ migrace (Fio migrace už živá z ec40274):ec941bfGET /v1/accounts 500 fix (cross-tenant:read klíč teď vylistuje VŠECHNY tenanty +?ico filtr, běžný klíč jen svůj → odblokuje cs/Cortex REQ-043 parity) +0fa054dmazání bank účtu FK 500 fix + abecední řazení seznamu účtů +97f927fdocs. Label false-positive (selective_recreate) na hub i prod: delta celá v billit-api → composebillit-web(FE beze změny) nerecreatnul → web držel starý ec40274 label → label check FAIL (1/2) → HEALTH_OK=false. Workaround: re-run--skip-build(po partial deploy je SNAP_MANIFEST tagovaný ec941bf → prázdný diff → SELECTIVE prázdné → force-recreate obou) → labely 2/2 na obou env. Ověřeno prod: oba containery ec941bf healthy R=0, /v1/accounts 401 (route up, ne 500), /health 200. QA FAIL = X-User blocker (CR-033) → prod override. ⚠️ Funkční validace 500 fixu (GET /v1/accounts 200 s cross-tenant klíčem = list tenantů) na cs (mají klíč cortex-banking-parity-REQ043). | 2026-06-26 05:32 UTC | billit | hub |e625e4f| feat(billit-web): DES-002 inc2 — akční blok 'Co tě dnes čeká' na dashboardu | ⚠️ fail (qa=skipped) | | 2026-06-26 05:34 UTC | billit | hub |e625e4f| feat(billit-web): DES-002 inc2 — akční blok 'Co tě dnes čeká' na dashboardu | ✅ done (qa=skip) | | 2026-06-26 05:35 UTC | billit | prod |e625e4f| feat(billit-web): DES-002 inc2 — akční blok 'Co tě dnes čeká' na dashboardu | ⚠️ fail (qa=skipped) | | 2026-06-26 05:37 UTC | billit | prod |e625e4f| feat(billit-web): DES-002 inc2 — akční blok 'Co tě dnes čeká' na dashboardu | ✅ done (qa=skipped) |Pozn. billit e625e4f (DES-002 FE redesign) hub+prod — KOREKCE chybného cíle: Předchozí deploy
ec941bf(T-092) byl jen BE fixy + titulek; FE redesign (DES-002 paleta) je až ve625e4f= 4 commity PO ec941bf, deploy-go T-20260626-073 (byl QUEUED, nezachycen — nasadil jsem starší ec941bf podle T-054 místo kontroly deploy-go fronty → titulek se změnil, paleta ne). Libor to odhalil (prod FE měl pořád #e2b340 gold ×15). Delta ec941bf..e625e4f = 4 billit-web commity: paleta gold→Violet, stone→slate (opuštění hnědé) + dashboard akční blok 'Co tě dnes čeká' + graf ticky/pie. Žádná migrace, db_change none. Label false-positive opět (delta celá FE → billit-api skipnut → api label stale → FAIL 1/2 na hub i prod) → workaround re-run--skip-build→ 2/2. FE rebuild ověřen (full build, ne skip-build, FE se přestavěl). Redesign ověřen END-TO-END na veřejném ucto.studio60.cz (billit.cz 301→ucto): served bundleindex-DhUwLFBK.css,#e2b340 gold = 0 výskytů, Violet8b5cf6/a78bfapřítomný, CF neservíruje stale → koncový uživatel vidí redesign. QA FAIL = X-User blocker → override. Lekce: před billit deployem kontrolovat deploy-go frontu (task-lookup) pro nejnovější cíl, ne slepě commit z poslední INFO zprávy. | 2026-06-26 07:12 UTC | billit | hub |39ef41f| fix(billit): CR-047 — editace faktury v jakémkoli stavu | ✅ done (qa=skip) | | 2026-06-26 07:15 UTC | billit | prod |39ef41f| fix(billit): CR-047 — editace faktury v jakémkoli stavu | ✅ done (qa=skipped) |Pozn. billit 39ef41f (CR-046 security + CR-047 + picker sort) hub+prod — supersede T-112: Release T-115 nahradil T-112/cec1989 (CR-047 přidán navrch) — správně zachyceno přes kontrolu deploy-go fronty (viz [[feedback_check_deploygo_queue]]). Delta nad LIVE
e625e4f= 5 commitů, žádná migrace, db_change none, žádná nová env. CR-046 🔒 SECURITY: bank účet GET/create/update vracelyfioApiTokenv API response (leak — týká se Fio tokenů, co jsem nedávno zapsal do bank_accounts) → nověBankAccountViewallowlist (jenhasFioToken); Fio sync/test čtou token interně z entity. + UX (aktivní kanál, indikátor token nastaven/chybí). CR-047: editace faktury v jakémkoli stavu (BEinvoices.update()bez status guardu,remainingAmount=max(0,total−paidAmount)→ editace zaplacené nerozbije párování, edit nemění status; FE canEdit=true). picker sort 5855c5b (GET /v1/accounts abecedně cs). Delta mění billit-api I billit-web → oba rebuildly → labely 2/2 na hub i prod v jednom kroku (žádný selective-recreate label false-positive). Ověřeno prod: oba 39ef41f healthy R=0, /health 200, /v1/accounts 401 (route up), ucto.studio60.cz 200. QA FAIL = X-User blocker → override. ⚠️ Funkční ověření leak fixu (authed GET bank-account response BEZ fioApiToken) na billit (X-User blokuje můj smoke); kód deployed (commit VERIFIED = CR-046 BankAccountView v dist). | 2026-06-26 07:42 UTC | s60-pulse | hub |283c966| feat(pulse): REQ-035 F2/REQ-044 — soft opt-in (oprávněný zájem) + admin consent management | ✅ done (qa=pass) | | 2026-06-26 07:46 UTC | s60-pulse | prod |283c966| feat(pulse): REQ-035 F2/REQ-044 — soft opt-in (oprávněný zájem) + admin consent management | ✅ done (qa=skipped) |Pozn. pulse 283c966 (soft opt-in + admin consent + Ecomail admin trigger) hub+prod — DRESS REHEARSAL (consent data change): Delta nad LIVE
a0829e8(vč. dosud nenasazeného 7b592cf). 3 věci: (1)7b592cfadmin Ecomail triggerPOST /api/admin/ecomail/sync-all(@Roles admin, auditecomail.full_sync_manual) + tlačítko „Přenos do Ecomailu" na Clients page = manuální plný přenos kontaktů; (2) migrace 152 (REQ044MarketingConsentDefaultTrue, DATA): ALTERclients.marketingEmailConsentDEFAULT true + per-tenant RLS backfillUPDATE … WHERE marketingEmailConsent=false AND marketingEmailConsentAt IS NULL(nepřepíše explicitní opt-out); (3) admin consent mgmtPATCH /clients/:id/marketing-consent. Soft opt-in = Liborovo rozhodnutí (oprávněný zájem §7/3 zák. 480/2004 + GDPR; registrovaný zákazník = default ano, může se odhlásit). Dress rehearsal (runbook pulse-hub-dress-rehearsal): clone prod→hub (bit-identical: 57 clients, 148 migrations, 57 false+NULL/0 opt-out/0 true) → deploy 283c966 na hub → migrace ověřena na reálných prod datech: 57 flipnuto false→true, 58. true = nový klient přes nový default (validuje i default), 0 opt-outů dotčeno, per-tenant RLS (5pd-diagnostika 0 klientů → správně netknuto), QA 15/15 PASS genuine. Prod efekt: consent false+NULL 57→0, true 0→57 (čistě), 0 opt-out, migrace 152 zaznamenaná, default=true, container healthy R=0, admin trigger 401 (registrován+chráněný), pulselab.cz 200. migrace se aplikuje boot migrationsRun (deploy.sh [6.5] „no pending"). Řetězec uzavřen: 57 klientů teď consent=true → Libor klikne „Přenos do Ecomailu" v administraci → 57 (+ souhlasící) doteče do Ecomail list 2 (config seednut dříve). Pozn.: hub teď drží prod-mirror data (z dress rehearsalu); hub-rollback dump v/tmp/dress-rehearsal-20260626/. | 2026-06-26 10:15 UTC | s60-pulse | hub |4a41f71| fix(pulse): REQ-044 — štítek pulse:metodika:za každou dokončenou metodiku | ✅ done (qa=pass) | | 2026-06-26 10:18 UTC | s60-pulse | prod | 4a41f71| fix(pulse): REQ-044 — štítek pulse:metodika:za každou dokončenou metodiku | ✅ done (qa=skipped) | Pozn. pulse 4a41f71 (per-metodika Ecomail štítek) hub+prod — drobný inkrement, ŽÁDNÁ nová migrace: Supersede 283c966. Pozor na stale baseline: pulse hlásil release vůči
a0829e8("db_change YES mig 152 + backfill, 283c966 nenasazeno"), ale 283c966 byl už LIVE (mig 152 + 57 consent=true hotové). Reálná delta nad LIVE 283c966 = jen4a41f71(REQ-044 štítekpulse:metodika:<slug>za dokončenou metodiku, pro Ecomail segmentaci) + 2 doc commity. Žádná nová migrace (152 už applied → deploy.shmigration:runno-op); žádný re-backfill — consent stav ověřen netknutý po deployi (true=57, false+NULL=0, idempotentní). Bez dress rehearsalu (žádná data/schema změna). Hub QA 15/15 PASS genuine, prod container 4a41f71 healthy R=0, pulselab.cz 200, commit VERIFIED. Lekce deploy-go fronty + stale-baseline rozpoznání aplikováno ([[feedback_check_deploygo_queue]]). | 2026-06-27 04:07 UTC | billit | hub |a9bfc26| fix(billit-api): cleanup duplicitních Fio tenantů (migrace) — REQ-043 seed dedup | ✅ done (qa=skip) | | 2026-06-27 04:10 UTC | billit | prod |a9bfc26| fix(billit-api): cleanup duplicitních Fio tenantů (migrace) — REQ-043 seed dedup | ✅ done (qa=skipped) |Pozn. billit a9bfc26 (2 crash hotfixy + DATA DELETE Fio tenant cleanup) hub+prod — standardní + pg_dump: Delta nad LIVE
39ef41f= 4 commity, supersede T-128. Část 1 — 2 crash HOTFIXy (billit-web):49a65e4InvoiceEditorPage crash (chybějící importapi) +0d6f2c7bank-accounts crash (inboundDomainprop) — pravděpodobně regrese z mého 39ef41f (CR-046/CR-047 FE) → opraveno. +f35943bregresní test. Část 2 — DATA DELETE migraceCleanupDuplicateFioTenants1772880000000(guarded, Libor schválil): REQ-043 seed (e527e01) založil tenanty po slugu (alteredu, byznys-partak), ale subjekty existovaly pod jinými slugy → duplikáty. Migrace maže prázdné dupyalter-edu+byznys-partak-z-s(guard NOT EXISTS invoices/orders/subjects, CASCADE token-less účty) + studio-60 dup CZK účet. Povinný pre-deploy pg_dump prod+hub (/tmp/billit-pre-a9bfc26/, 4.6M každý) + PITR. Delete scope ověřen na reálných prod datech PŘED i PO: smazány PŘESNĚalter-edu+byznys-partak-z-s(0 inv/ord/subj, 0 fio tokenů);alteredu+byznys-partak(mé Fio tenanty) + 8 fio_api tokenů netknuté; DELETE 2 studio-60 CZK2900144404= NO-OP (guardNOT EXISTS invoices— účet má 270 faktur → billitova intence dedupnout se NEnaplnila, flagnuto). Oba containery a9bfc26 (FE+BE delta → 2/2 labely čistě), api+web 200, ucto.studio60.cz 200, commit VERIFIED. QA FAIL = X-User blocker → override. | 2026-06-27 04:21 UTC | s60-auth | hub |fd88a14| feat(auth): CR-007 + REQ-045 — Ecomail→auth consent inbound consumer + state-diff loop-break | ✅ done (qa=pass) | | 2026-06-27 04:23 UTC | s60-auth | prod |fd88a14| feat(auth): CR-007 + REQ-045 — Ecomail→auth consent inbound consumer + state-diff loop-break | ✅ done (qa=skipped) |Pozn. auth fd88a14 (REQ-044 consent mgmt + CR-007/REQ-045 Ecomail inbound) hub+prod — additivní, kritická služba: Stale baseline zachycen: KB/INDEX tvrdilo LIVE
6c03148, ale prod label =7c994ab(= f398a84 batch, nasazen mezitím) → přepočítáno od skutečné LIVE. Reálná delta nad7c994ab= 4 non-spec commity, 1 migrace, fast-forward. REQ-044 consent management per systém (migraceConsentManagement1750000000000) + CR-007/REQ-045 Ecomail→auth inbound consent consumer (BullMQ Worker naconsent-status-inboundsdílený s60-redis: dedup event_id Redis 7d, email→user, scope source→setConsent / global→revokeAll, per-event try/catch + state-diff loop-break = inbound směr consent syncu, doplňuje pulse outbound). Migrace PLNĚ ADDITIVNÍ (4 ADD COLUMN nasystems: consent_required_enabled/consent_marketing_enabled BOOL NOT NULL DEFAULT false + marketing_url/consent_webhook_url VARCHAR NULL; CREATE TABLE user_consents + index; DROP v down() jen rollback) → zero breaking. Ověřeno: hub 4/4 cols + user_consents + 12/12 systems default false; prod 4/4 cols + user_consents + 15/15 systems default false. Kritické auth ověření: backend /api/health ok, openid issuer https://auth.studio60.cz, oba containery healthy R=0 (FE+BE delta → 2/2 labely čistě), auth.studio60.cz veřejně 200, 0 errors post-deploy. authnpm run migration:runfunguje (executed successfully, ne mail-style broken). QA 2/2 PASS genuine na hub. Bez dress rehearsalu (additivní, žádný data change). | 2026-06-27 04:33 UTC | s60-mail | hub |e38d165| feat(mail): REQ-007 inbound consent webhook (Ecomail → consent-status-inbound → auth) | ✅ done (qa=pass) | | 2026-06-27 04:35 UTC | s60-mail | prod |e38d165| feat(mail): REQ-007 inbound consent webhook (Ecomail → consent-status-inbound → auth) | ✅ done (qa=skipped) |Pozn. mail e38d165 (REQ-007 inbound consent webhook) hub+prod — dokončuje inbound consent loop s auth: Delta nad LIVE
204f084=e38d165(REQ-007) + doc. REQ-007:POST /webhook/ecomail?token=…přijme Ecomail contact-status-change, enrich přes provider config (list_id→oauth_client_id), pushne normalizovaný event do BullMQconsent-status-inbound(kontrakt LOCKED s auth) → authConsentInboundService(fd88a14) zpracuje. echo-cache dedup = loop-break. Mail = relay+enrich, consent politiku řeší auth. MigraceAddOauthClientIdToProviderConfigsADDITIVNÍ (ADD COLUMN oauth_client_id VARCHAR(100), zero breaking) — ověřeno hub+prod (sloupec + migrace; prod provider_configs=1 = list_id=2 seed intact, additivní migrace nedotkla). Rehearsal = hub-first-verify (ne full prod-clone): migrace je additivní (žádný data change) + full clone by rozbil encrypted provider config na hubu (per-env PROVIDER_ENCRYPTION_KEY mismatch) → proporcionální = hub deploy+verify PŘED prod. 3 nová nastavení sentinelem: (1)ECOMAIL_INBOUND_WEBHOOK_TOKENvygenerován per-env (openssl rand -hex 24, do/root/secrets/mail/.env.{hub,prod}, hodnota Liborovi pro Ecomail dashboard) — bez něj token check DISABLED = neautentizovaný webhook; ověřeno aktivní (401 bez/blbým tokenem) hub+prod; (2) veřejná route už existovala —mail.studio60.czvhost málocation /webhook → mail:3010+ LE cert (KB "mail nemá veřejnou doménu" = STALE); ověřenohttps://mail.studio60.cz/webhook/ecomailPOST bez tokenu = 401 (dosažitelný+authed); (3) Ecomail dashboard webhook URLhttps://mail.studio60.cz/webhook/ecomail?token=<prod>předán Liborovi. Migrace WARN = známý mail brokenmigration_command(T-086, boot migrationsRun). QA 3/3 PASS genuine hub. Consent loop teď KOMPLETNÍ obousměrně: pulse/auth→Ecomail (outbound) + Ecomail→mail→fronta→auth (inbound). | 2026-06-27 06:36 UTC | billit | hub |dd2b96d| docs(deploy): pending release HEAD 8714d2a (REQ-047 kompletní + úklid účtů + FE picker) | ✅ done (qa=skip) | | 2026-06-27 06:40 UTC | billit | prod |dd2b96d| docs(deploy): pending release HEAD 8714d2a (REQ-047 kompletní + úklid účtů + FE picker) | ✅ done (qa=skipped) |Pozn. billit dd2b96d (REQ-047 invoice snapshot immutabilita + account cleanup + FE picker) hub+prod — DRESS REHEARSAL (4 migrace, DATA DELETE + backfill 19510): Supersede T-045/3c136f8. REQ-047 = vystavená faktura = úplný immutable snapshot (nemění se při změně podkladů). 4 migrace, pořadí KRITICKÉ (snapshot PŘED cleanup, timestampy garantují): (1)
AddMissingTenantBankAccounts(idempotentní INSERT chybějících účtů + scoped DELETE); (2)SnapshotInvoiceBankDetails(P1 — ADD your_iban/account_number/swift + BACKFILL 19507 faktur z navázaného účtu, WHERE IS NULL); (3)AccountCleanupDATA DELETE — UPDATE 270 faktur (studio-60 CZK 2900144404 'none' dup) → re-point na default keeper, PAK DELETE dup účet (po snapshotu bezpečné); (4)SnapshotInvoiceEmailAndBranding(P2+P3 — ADD client_email/logo/branding + backfill). ŘEŠÍ můj DELETE 2 nález z a9bfc26 (ten 270-fakturový účet teď re-pointnut+smazán, snapshot chrání vystavené faktury). Dress rehearsal: clone prod→hub (bit-identical: invoices 19510, bank_accounts 28, 270-acct 270) → deploy dd2b96d na hub → adversariální verifikace 8/8 PASS na reálných prod datech: 4 migrace, 7/7 snapshot sloupců, backfill 19507, dup smazán, 270 re-pointnuto, 0 orphanů, email backfill 16874, snapshot-před-cleanup ověřeno (19507 faktur drží IBAN vč. 270 re-pointnutých). Povinný pre-deploy pg_dump prod+hub (/tmp/billit-dd2b96d-dr/) + deploy.sh snapshot 51M + PITR. Prod efekt IDENTICKÝ s rehearsalem (8/8): backfill 19507, dup 0, 270→0, orphans 0, email 16874, bank_accounts 28→26, oba containery dd2b96d healthy R=0, ucto.studio60.cz 200. FE+BE → 2/2 labely čistě. QA FAIL = X-User blocker → override. Pozn.: repo HEAD 0f00c61 (security-hooks tooling) nad target dd2b96d — nasazen target. | 2026-06-27 08:15 UTC | s60-pulse | hub |f0601ef| feat(pulse): REQ-047 F3 — consent UI read-only (SoT = S60Auth, var. B) | ✅ done (qa=pass) | | 2026-06-27 08:18 UTC | s60-pulse | prod |f0601ef| feat(pulse): REQ-047 F3 — consent UI read-only (SoT = S60Auth, var. B) | ✅ done (qa=skipped) |Pozn. pulse f0601ef (REQ-047 F1 consent webhook receiver + F3 UI read-only) hub+prod — čistý fast-forward: Delta nad LIVE
4a41f71= 5 commitů (2 feat + doc), žádná migrace, db_change none, env beze změny (využívá existující S60_AUTH_CLIENT_SECRET + REDIS_URL). F1:POST /api/webhooks/consent— HMAC(S60_AUTH_CLIENT_SECRET,${ts}.${rawBody}) timing-safe + timestamp replay 300s + eventId dedup (Redis 7d) → updateclients.marketingEmailConsent(cache) + Ecomail štítky; main.ts NestFactory rawBody:true (billing webhook nedotčen). F3: marketing consent v Pulse READ-ONLY (odebrán PATCH /clients/:id/marketing-consent, admin/klient UI jen indikátory) — auth = source of truth. Tohle je realizace té consent architektury, co Libor předal auth+pulse (řeší ten rozpojený inbound→auth vs outbound→pulse.clients nález): auth je SoT, posílá consent webhook do pulse → pulse updatne svůj clients.marketingEmailConsent cache (= zdroj pro outbound sync) → loop se uzavře. ⚠️ Webhook nikdo nevolá, dokud auth nenastavíconsent_webhook_urlv auth adminu (na auth straně). Ověřeno: hub QA 15/15 PASS genuine, prod container f0601ef healthy R=0,/api/webhooks/consentbez podpisu = 401 (registrován + HMAC chráněný), pulselab.cz 200, commit VERIFIED. Bez dress rehearsalu (žádná data/migrace). | 2026-06-27 08:43 UTC | s60-auth | hub |620bb45| chore: DEPLOY.md — review backlog (16af885), db_change: minor / migration | ✅ done (qa=pass) | | 2026-06-27 08:45 UTC | s60-auth | prod |620bb45| chore: DEPLOY.md — review backlog (16af885), db_change: minor / migration | ✅ done (qa=skipped) |Pozn. auth 620bb45 (=16af885 kód: REQ-047 webhook finalizace + CR-008–012 + review backlog + ConsentHardening) hub+prod — DRESS REHEARSAL (kritická auth, consent migrace): 24-commitový release nad LIVE
fd88a14. Klíčový obsah:65a9c42REQ-047 webhook finalizace (auth→pulse consent webhook + pull endpointy → uzavírá consent loop s pulse f0601ef);bd3f0e3lead auto-create + provider-marketing-only + dedup-on-fail fix + consent date (řeší OBA mé nálezy z T-044);09ecbeaCR-012 API key authz 2× critical security; CR-008/009/010/011 admin UI (detail uživatele/systému, consent filtry);16af885review backlog (DB hardening + dedup atomicity). MigraceConsentHardening1751000000000: CREATE INDEX(system_id,type)+ 2 FK (ON DELETE CASCADE user_id→users, system_id→systems) + orphan cleanup (DELETE před FK). ⚠️ deploy.sh REJECT na 16af885 (DEPLOY.md @ 16af885 staledb_change:noneale migrace v diffu → safety reject) → nasazen620bb45(=16af885 kód + DEPLOY.mddb_change:minormigration_from 09ecbea) [[feedback_check_deploygo_queue]]. Dress rehearsal: clone prod→hub (bit-identical: 106 consents, 96 users, 15 systems, 0 orphanů) → deploy 620bb45 → migrace ověřena na reálných datech: index + 2 FK vytvořeny, orphan cleanup smazal 0, 106 consents zachováno, 0 orphanů, openid OK, 0 errors. Prod efekt identický: index+2FK 3/3, 106 consents, container 620bb45 healthy R=0, openid issuer https://auth.studio60.cz, auth.studio60.cz veřejně 200, 0 errors. Pre-deploy pg_dump prod+hub (/tmp/auth-16af885-dr/). FE+BE → 2/2 labely. QA 2/2 PASS genuine (auth není X-User blokovaný). Po deployi auth ještě nastavíconsent_webhook_urlna PulseLab → reálně uzavře loop (Ecomail→mail→auth→webhook zpět do pulse). | 2026-06-27 11:03 UTC | s60-pulse | hub |083ffbb| chore(pulse): DEPLOY.md — Current 7fcc5d4 (REQ-047 komplet F1+F2+F3, optional env S60_AUTH_CONSENT_API_KEY) | ✅ done (qa=skip) | | 2026-06-27 11:09 UTC | s60-pulse | prod |083ffbb| chore(pulse): DEPLOY.md — Current 7fcc5d4 (REQ-047 komplet F1+F2+F3, optional env S60_AUTH_CONSENT_API_KEY) | ✅ done (qa=skipped) |Pozn. pulse 083ffbb (=7fcc5d4 kód: REQ-047 KOMPLET F1+F2+F3) hub+prod — čistý fast-forward + QA harness incident: Delta nad LIVE
f0601ef= 3 commity, db_change none, ŽÁDNÁ migrace, nový OPTIONAL envS60_AUTH_CONSENT_API_KEY(F2 reconcile pull z auth — bez něj F2 neběží, app boot OK). F2 reconcile pull + F1 retry-aware dedup (doplňuje F1 webhook + F3 read-only z f0601ef). Rehearsal: db_change none → plný clone nemá co ověřit → hub-first-verify (jako mail). ⚠️ QA HARNESS INCIDENT: hub pulse QA FAIL 7× „could not obtain Pulse token" — side-effect mého předchozího auth dress rehearsalu (klonoval prod→hub auth → hub auth QA test user dostal prodové heslo; QA loginPOST auth.s60hub.cz/api/auth/loginemail+heslo selhal). NE pulse/auth regrese (USER login ≠ CR-012 API key; container healthy, prod auth nedotčená). Override prod gate (zdokumentován) → prod deploy. Cleanup: restorováno hub auth z hub-rollback dumpu (test data zpět) + re-aplikována ConsentHardening → pulse hub QA znovu 15/15 PASS genuine. Prod: container 083ffbb healthy R=0, pulselab.cz 200, commit VERIFIED. Lekce: dress rehearsal clone auth (prod→hub) rozbije QA token-acquisition VŠECH služeb (QA bere token z hub auth) → po auth rehearsalu VŽDY restore hub auth (Phase 5). Consent loop kompletní: REQ-047 F1+F2+F3 (pulse) + REQ-047 webhook+ConsentHardening (auth) — zbývá auth nastavit consent_webhook_url. | 2026-06-27 11:11 UTC | s60-auth | hub |620bb45| chore: DEPLOY.md — review backlog (16af885), db_change: minor / migration | ✅ done (qa=pass) | | 2026-06-28 05:29 UTC | s60-auth | hub |6486cdd| chore: DEPLOY.md — CR-013/CR-014 + review fixes + seed (f2c13ba), db_change: none | ✅ done (qa=pass) | | 2026-06-28 05:31 UTC | s60-auth | prod |6486cdd| chore: DEPLOY.md — CR-013/CR-014 + review fixes + seed (f2c13ba), db_change: none | ✅ done (qa=skipped) |Pozn. auth 6486cdd (CR-013 + CR-014 + review fixy + REQ-047 seed CLI) hub+prod — čistý deploy + jednorázový consent seed (cesta A): Delta nad LIVE
620bb45= 6 commitů (CR-013 admin system-users page; CR-014 provisioning API + ProvisioningGuard scopeprovisioning:systems; webhook anti-SSRF fix;f2c13baREQ-047 seed-consents CLI; 2 specs), db_change none, ŽÁDNÁ migrace (indexy/FK už z 1751000000000). DEPLOY.md@6486cdd=Current:f2c13ba→ migration cross-check OK (na rozdíl od minulého 16af885 reject). FE+BE → oba rebuild → 2/2 labely čistě, oba env commit VERIFIED, R=0 healthy, openid issuer https://auth.studio60.cz, hub QA gate 6/6 PASS genuine. REQ-047 cesta A SEED (Libor DEPLOY+EXEC OK): auth dodal idempotentnídist/scripts/seed-consents.js(node standalone v containeru, reuse ConsentService state-diff). Sentinel vyexportoval Pulse prod marketing souhlasy (read-only, tenant GUC) → 57 active → filtr test.cz/example.com/demo.pulselab.cz → 51 (vše granted=true), CSV injektnut do containeru přes pipe (žádná host-disk kopie). DRY-RUN → APPLY identické:rows=51, granted=51, created=2 (LEAD), revoked=0, skipped=0, errors=0, sha16=7aca435e integrityOk. Nezávislá DB verifikace: PulseLab marketing souhlasy total 56 = 4 app-source (čerstvé 05:34, mé zápisy) + 52 register-source (pre-existující 2026-02..06 z registrací, netknuté); z mých 51: 47 už mělo register-souhlas (state-diff no-op) + 4 dopsány app-source (2 leadyenabled=true/verified=false+ 2 existující). revoked=0 (nic neodhlášeno). source='app' → bez webhook echa → seed bezpečný. Ordering guard splněn: seed PŘEDconsent_webhook_url. Container /tmp/seed.csv uklizen. Zbývá krok 4 (Libor): nastavitconsent_webhook_url=https://pulselab.cz/api/webhooks/consent + vygenerovatS60_AUTH_CONSENT_API_KEY(PulseLab-bound) → Pulse prod env → reconcile = self-heal. Lze udělat i přes nové CR-014 provisioning API. | 2026-06-28 06:14 UTC | s60-auth | hub |9ce97e6| chore: DEPLOY.md — CR-015 + review fixes (7171d4c), db_change: none | ✅ done (qa=pass) | | 2026-06-28 06:15 UTC | s60-auth | prod |9ce97e6| chore: DEPLOY.md — CR-015 + review fixes (7171d4c), db_change: none | ✅ done (qa=skipped) | | 2026-06-28 06:20 UTC | s60-pulse | hub |083ffbb| chore(pulse): DEPLOY.md — Current 7fcc5d4 (REQ-047 komplet F1+F2+F3, optional env S60_AUTH_CONSENT_API_KEY) | ✅ done (qa=pass) | | 2026-06-28 06:22 UTC | s60-pulse | prod |083ffbb| chore(pulse): DEPLOY.md — Current 7fcc5d4 (REQ-047 komplet F1+F2+F3, optional env S60_AUTH_CONSENT_API_KEY) | ✅ done (qa=skipped) |Pozn. REQ-047 cesta A — KOMPLETNÍ aktivace consent loopu (auth 9ce97e6 + pulse env + krok 4 + revoke) — 2026-06-28: Navazuje na seed (auth 6486cdd výše). (1) auth
9ce97e6(=7171d4c kód) hub+prod — delta nad6486cdd= CR-015 (detail systému taby + security: GET /systems/:id už NEvrací oauth_client_secret) + CR-014 bootstrap skript, db_change none, žádná migrace, cross-check OK, oba env VERIFIED 2/2 labely R=0, hub QA 6/6 PASS, openid OK. (2) Krok 4 aktivace (Libor dal sentinelovi provisioning klíč scopeprovisioning:systems): sentinel přes CR-014POST /api/provisioning/systems/<PulseLab>/consent-integration→ nastavenconsent_webhook_url=https://pulselab.cz/api/webhooks/consent(ověřeno v DB) + vydán consent klíč ({consent:read}, system-bound, no-expiry). (3) pulse prod env: consent klíč →S60_AUTH_CONSENT_API_KEYv/root/secrets/pulse/.env.prod; pulse hub stamp byl 19h starý → refreshpulse hub --skip-build(QA 15/15 PASS) →pulse prod --skip-build(083ffbb, env-only, no migration, health 200). Container má klíč. (4) F2 pull ověřen:GET /api/consents/by-systemconsent klíčem → 200, 56 souhlasů = přesně co pulse reconcile volá. (5) Revoke: provisioning klíč splnil jednorázový účel → cílený DB delete řádku (keyHash sha256, potvrzen přesně 1 řádek{provisioning:systems}name=sentinel) → DELETE 1, ověřeno re-callem 401 (mrtvý). Secret soubory (provisioning-key.txt, consent-integration-response.json) smazány. VÝSLEDEK: consent loop kompletní obousměrně — F1 auth→pulse webhook push (active), F2 pulse→auth reconcile pull (active, ověřeno), F3 read-only UI. SoT = S60Auth. | 2026-06-28 06:42 UTC | s60-auth | hub |49ca6f4| chore: DEPLOY.md — GET /systems authz fix (4bd41fe), db_change: none | ✅ done (qa=pass) | | 2026-06-28 06:44 UTC | s60-auth | prod |49ca6f4| chore: DEPLOY.md — GET /systems authz fix (4bd41fe), db_change: none | ✅ done (qa=skipped) |Pozn. auth 49ca6f4 (=4bd41fe: SECURITY GET /systems admin-gate) hub+prod — malý BE-only security fix: Delta nad LIVE
9ce97e6= 1 commit4bd41fe+ doc, db_change none, žádná migrace. 🔒 GET /systems (list) nově vyžaduje admin roli (byl jen JwtAuthGuard → info-disclosure konfigurace VŠECH systémů každému přihlášenému; oauth_client_secret už strippnut z 9ce97e6). Sjednoceno s ostatními /systems endpointy. BE-only změna, ale label false-positive se NEobjevil — 2/2 labely čistě oba env, commit VERIFIED, R=0 healthy, hub QA 6/6 PASS, openid OK, GET /api/systems no-token → 401 (route chráněná). Admin-gate 403 pro non-admin = auth dev-verified AC (smoke bez non-admin tokenu neověří handler, viz [[feedback_smoke_auth_blocker]]). Uzavírá auth backlog CR-013/014/015 + security (vše od 16af885 nasazeno). | 2026-06-28 07:22 UTC | s60-auth | hub |eb43e9c| chore: DEPLOY.md - row proklik na detail systemu (8404551) | ✅ done (qa=pass) | | 2026-06-28 07:23 UTC | s60-auth | prod |eb43e9c| chore: DEPLOY.md - row proklik na detail systemu (8404551) | ✅ done (qa=skipped) |Pozn. auth eb43e9c (=8404551: CR-015 follow-up řádek-proklik) hub+prod — triviální FE-only UX: Delta nad LIVE
49ca6f4= 1 commit8404551(frontend/src/pages/Admin.tsx— řádek v seznamu systémů = proklik na detail) + doc, db_change none, žádná migrace. FE-only, ale 2/2 labely čistě oba env (žádný BE-stale false-positive), commit VERIFIED, R=0 healthy, hub QA 6/6 PASS, auth.studio60.cz 200, openid OK. Kosmetika, žádný funkční dopad na API. | 2026-06-28 14:13 UTC | s60-auth | hub |9096bef| chore: DEPLOY.md + REQ-048 impl note (83c9120), db_change: none | ✅ done (qa=pass) | | 2026-06-28 14:15 UTC | s60-auth | prod |9096bef| chore: DEPLOY.md + REQ-048 impl note (83c9120), db_change: none | ✅ done (qa=skipped) |Pozn. auth 9096bef (=83c9120: REQ-048 legacy migrace + red-team hardening) hub+prod — BE-only, db_change none, ALE ne behavior-neutral + tooling false-positive fix: Delta nad LIVE
eb43e9c= REQ-048 + specs, žádná migrace (souborlegacy-migration.service.ts= NestJS service, NE TypeORM migrace). ⚠️ deploy.sh REJECT (false-positive): migration cross-check (ř.388) grepovalmigratv NÁZVU souboru → matchnullegacy-migration.service.ts→ REJECT při db_change=none. Root cause:MIGRATION_DIRSse počítal, ale grep ho nepoužil. Fix0a9be1c: grep teď matchuje adresářový segment(^|/)migrations?/(reálné migrace jsou vždy v migrations/ dir); ověřeno = chytá ConsentHardening, ignoruje legacy service; schema-hint (@Column/@Entity/ALTER) backstop zůstává. Po fixu re-deploy prošel cross-check OK. REQ-048 (lazy legacy login přes BadWolf) za flagemBW_LEGACY_LOOKUP_ENABLEDDEFAULT OFF → BW chování beze změny (aktivace až po BW endpointu + env). ⚠️ AKTIVNÍ HNED (red-team hardening, i s flag OFF): (1) rate-limit login/register/forgot/otp per-EMAIL 15/5min→429 (per-IP off, čeká na trust proxy); (2) social auto-link k existujícímu účtu jen při provider emailVerified===true → Facebook auto-link k existujícímu účtu ZAKÁZÁN (401), Google default false; nové social účty (bez kolize) OK. Oba env VERIFIED 2/2 labely R=0, hub QA 6/6 PASS, openid OK, auth.studio60.cz 200, 0 errors post-deploy. Libor flagnut na FB změnu před DEPLOY OK. | 2026-06-29 04:27 UTC | billit | hub |928161d| chore(deploy): DEPLOY.md — release f80d3bb (katalog inc1-4 + REQ-051 + CR-048) | ✅ done (qa=skip) | | 2026-06-29 04:32 UTC | billit | prod |928161d| chore(deploy): DEPLOY.md — release f80d3bb (katalog inc1-4 + REQ-051 + CR-048) | ✅ done (qa=skipped) |Pozn. billit 928161d (=f80d3bb: katalog DEC-015 + REQ-051 settlement + CR-048) hub+prod — DRESS REHEARSAL (2 additivní migrace) + override-fix + recovery z přerušeného deploye: Delta nad LIVE
dd2b96d= REQ-048/049 katalog datový model + Category API, REQ-050 FE katalog, REQ-051 settlement routing přes katalog, CR-048 migrations glob fix. db_change minor — 2 migrace (additivní, idempotentní IF NOT EXISTS/DO-guard, BEZ destrukce):1772930000000 CatalogInc1DataModel(CREATE categories strom + products +category_id/+commission_rate + order_lines/invoice_lines +product_id FK SET NULL + backfill product_ref→product_id) +1772940000000 CatalogInc2ApiKeySystem(api_keys +system). 🔧 Override-fix (z mého minulého HOLDu): billit odstranildocker-compose.override.yml(kolidoval s rezervovaným sentinel deploy.sh názvem) → přesunul dev auto-migrate dodocker-compose.dev.yml+ dev-DB guard (DB!=s60_billit_dev→no-op). [[reference_compose_override_reserved]]. Dress rehearsal (mám SU na pg-alfa): clone prod→hub (pg_dump prod 4.8M → restore s60_billit_hub jako hub_user; pre-deploy backup hub+prod vpg-alfa:/var/lib/postgresql/billit-rehearsal-20260629-042439/). Baseline: categories/category_id/product_id/api_keys.system chybí, commission_rate už existoval (idempotence přeskočí), products=0 (katalog nový, backfill minimální). Hub deploy 928161d → migrace OK (dist cestadist/database/data-source.js), adversariální verifikace 8/8: 6/6 schema, 2 FK SET NULL, data preservation (invoices 19508/19508, invoice_lines 22992, order_lines 36, bank_accounts 26, subjects 8922), 0 orphanů, migrace 2/2. ⚠️ Recovery: prod deploy jsem omylem pustil stimeout 60 | head→ SIGPIPE/timeout zařízl na [4/8] (PŘED rsync/migrace); prod ověřen NETKNUTÝ (commit dd2b96d, categories=false, 0/2) → re-run správně na pozadí. [[feedback_deploy_run_in_background]]. Prod efekt identický s rehearsalem: 6/6 schema, data preservation 19508/22992/8922/36/26, migrace 2/2, orphans 0/0, containery R=0 healthy, ucto.studio60.cz 200, billit.cz 301→ucto. QA gate = známý X-User blocker (CR-033, billit QA non-blocking) → override stamp (stale z dd2b96d, ale reasoning platí + migrace dress-rehearsnuté). | 2026-06-29 05:55 UTC | badwolf | hub |619c55b| chore(hooks): preflight gate — hard-block sentinel/deploy-go bez Liborova pokynu | ✅ done (qa=pass) | | 2026-06-29 05:57 UTC | badwolf | prod |619c55b| chore(hooks): preflight gate — hard-block sentinel/deploy-go bez Liborova pokynu | ✅ done (qa=skipped) | | 2026-06-29 06:29 UTC | badwolf | hub |619c55b| chore(hooks): preflight gate — hard-block sentinel/deploy-go bez Liborova pokynu | ⚠️ fail (qa=skipped) | | 2026-06-29 06:33 UTC | badwolf | prod |619c55b| chore(hooks): preflight gate — hard-block sentinel/deploy-go bez Liborova pokynu | ⚠️ fail (qa=skipped) | | 2026-06-29 ~08:1x UTC | badwolf | hub+prod |619c55b| DES-003 v1.2 — dev→prod KLON (fresh baseline) + correct-image release (sentinel build) | ✅ funkční (/api/courses 200) |Pozn. badwolf DES-003 v1.2 (dev→prod KLON fresh baseline + REQ-048/DES-002/DES-003 app) hub+prod — 2026-06-29, Libor DEPLOY+per-grant OK, fáze 0 hotová: NE migrace (031-043 superseded) — prod baseline = klon prověřeného devu. Stará prod data (duben, disposable experiment) zahozena. DB klon (sentinel SU na pg-alfa): safety dump prod+hub → wipe →
pg_restore dev-dump --role=*_userdo prod i hub → counts=dev (clients 23552, orders 4310, applications 7193, order_items 4893, online_course_enrollments 26542, course_dates 352), 48/48 tabulek app-role, tenant_id=0, 10 row_hash triggerů, 0 orphanů. App release — 2 badwolf config issues vyřešeny workaroundem: (1) build context symlink — deploy.yml build.context=/root/projects/bw, ale badwolf//s60-auth-sdk jsou symlinky → BuildKit nenásleduje → deploy build na targetu použil STARÝ cached image (duben, course.entity stenant_id) →/api/courses500 „column Course.tenant_id does not exist" (schema tenant_id nemá). Workaround: build na sentinelu z reálných kopií (rsync -aLderef symlinků do /tmp/bw-build,docker build --no-cache, dist tenant_id=0) →docker save | ssh docker loadna prod+hub → recreatedeploy.sh --skip-build --skip-ci. (2) stale healthcheck path — app má global prefix/api(/api/health, /api/courses), ale Dockerfile HEALTHCHECK + deploy.yml health míří na/health(404) → container „unhealthy" + deploy.sh „health check failed", ale app FUNGUJE (/api/health 200, /api/courses 200 s reálnými daty). Výsledek: prod+hub LIVE na fresh klonu, /api/courses 200, build hash bc4ed13a (nový, ne stale 03c9e61b), commit 619c55b VERIFIED. CI 1 stale test (jenkins-sync, dormant) + 1 teardown-flaky → --skip-ci (Libor OK). Oba config fixy nahlášeny badwolfovi (build symlink + healthcheck /api/health). Ongoing Model 1 applier (Fáze D) = zvlášť. Lekce: [[feedback_deploy_run_in_background]] (přerušený billit deploy předtím), build-context symlink, --skip-build neskipuje CI. | 2026-06-29 11:13 UTC | s60-pulse | hub |3cc218c| chore(pulse): DEPLOY.md — Current 45a6afa (REQ-048 evidence objednávky, db_change mig 153) | ✅ done (qa=pass) | | 2026-06-29 11:17 UTC | s60-pulse | prod |3cc218c| chore(pulse): DEPLOY.md — Current 45a6afa (REQ-048 evidence objednávky, db_change mig 153) | ✅ done (qa=skipped) |Pozn. pulse 3cc218c (=45a6afa: REQ-048 evidence pokusu o objednávku) hub+prod — additivní migrace 153, hub-first-verify: Delta nad LIVE
083ffbb= REQ-048 (objednávka vznikánewPŘED Billit push → success=pending / fail=error flag hasError/errorInfo/errorAt; admin „Odeslat do účta" re-push) + specs. Migrace 153 (REQ048OrderFailureCapture) = čistě ADDITIVNÍ: 3×ALTER TABLE orders ADD COLUMN IF NOT EXISTS(hasError bool NOT NULL DEFAULT false, errorInfo text, errorAt timestamptz), žádný backfill, žádná data change, consent data (clients) netknutá → hub-first-verify (ne full dress rehearsal, jako u additivních auth migrací). Hub: migrace OK (3 sloupce na s60_pulse_hub ověřeny), health 200, QA 15/15 PASS genuine, commit VERIFIED. Prod: první pokus padl na docker race (removal of container already in progress[[feedback_deploy_docker_race]]) → workaround re-run--skip-build→ DEPLOYED, migrace 153 na s60_pulse_prod ověřena (hasError/errorAt/errorInfo), health 200 R=0, pulselab.cz 200, commit VERIFIED. Happy-path platby beze změny (CheckoutResult identický, markPaid webhook OK). | 2026-06-29 11:24 UTC | billit | hub |960af11| chore(deploy): DEPLOY.md — release 64d70ea (REQ-052 inc1+inc2 complete) | ✅ done (qa=skip) | | 2026-06-29 11:26 UTC | billit | prod |960af11| chore(deploy): DEPLOY.md — release 64d70ea (REQ-052 inc1+inc2 complete) | ✅ done (qa=skipped) |Pozn. billit 960af11 (=64d70ea: CR-049 + REQ-052 inc1+inc2) hub+prod — BE-only/BE+FE, delta BEZ nové migrace: Delta nad LIVE
928161d= CR-049 (system-scoped API klíč pro katalogovou větev — admin-gate + privilege-escalation guard + FE generování z editoru kategorie; sloupce api_keys.system/allowed_ips už live z 928161d), REQ-052 inc1 (jednotný error contract {statusCode,code,message,field?,detail?,requestId,timestamp,path} + DB QueryFailedError→čisté 4xx dle PG SQLSTATE — řeší Pulse 500 incident u overflow — + X-Request-Id correlationId + GlitchTip tag, NO-LEAK), REQ-052 inc2 (DTO validation sweep, overflow→400 ve ValidationPipe, orderNumber cap 50). DEPLOY.md db_change=minor je KUMULATIVNÍ (2 katalog migrace 1772930/1772940) — ty ale už LIVE z 928161d → migration:run no-op ("No migrations pending"), delta 928161d..960af11 bez nové migrace. BE (23 billit-api) + FE (3 billit-web) → 2/2 labely čistě, oba env commit VERIFIED, R=0 healthy, ucto.studio60.cz 200, billit.cz 301→ucto. Override clean (docker-compose.dev.yml). Standardní hub→prod (žádný dress rehearsal — žádná nová migrace/data change). QA FAIL = známý X-User blocker → override (stale dd2b96d stamp). Žádný docker race tentokrát. | 2026-06-29 12:50 UTC | s60-auth | hub |4cb9df6| chore: DEPLOY.md — RegisterDto consents fix (98efcbd), db_change: none | ✅ done (qa=pass) | | 2026-06-29 12:51 UTC | s60-auth | prod |4cb9df6| chore: DEPLOY.md — RegisterDto consents fix (98efcbd), db_change: none | ✅ done (qa=skipped) |Pozn. auth 4cb9df6 (=98efcbd: REQ-044 RegisterDto consents fix) hub+prod — malý BE-only bugfix: Delta nad LIVE
9096bef= 1 commit98efcbdfix(auth) RegisterDto whitelistconsents(oprava 400 při registraci — poleconsentsnebylo ve whitelistu DTO validace → ValidationPipe odmítala registraci) + CLAUDE.md rules + DEPLOY.md. db_change none, žádná migrace. BE-only, ale 2/2 labely čistě oba env (FE recreatnul taky), commit VERIFIED, R=0 healthy, openid issuer https://auth.studio60.cz, auth.studio60.cz 200, hub QA PASS. Bez dress rehearsalu (žádná data/schema změna). | 2026-06-30 06:34 UTC | s60-pulse | hub |d8af612| chore(pulse): DEPLOY.md — Current 27b1f20 (BUNDLE CR-187 transaction_id + CR-209 GA4 refund, mig 154 + GA4 env) | ✅ done (qa=pass) | | 2026-06-30 06:37 UTC | s60-pulse | prod |d8af612| chore(pulse): DEPLOY.md — Current 27b1f20 (BUNDLE CR-187 transaction_id + CR-209 GA4 refund, mig 154 + GA4 env) | ✅ done (qa=skipped) |Pozn. pulse d8af612 (=27b1f20: BUNDLE CR-187 transaction_id + CR-209 GA4 refund) hub+prod — additivní mig 154, hub-first-verify: Delta nad LIVE
3cc218c= CR-187 (purchase event → ecommerce.transaction_id = Billit orderId) + CR-209 (GA4 refund server-side přes Measurement Protocol, trigger na webhook processTermination + admin applyTerminalRefund, idempotence refund-${id}, gaClientId z _ga cookie pro atribuci, fail-soft) + specs. Migrace 154 (CR209OrderGaClientId) = čistě ADDITIVNÍALTER TABLE orders ADD COLUMN IF NOT EXISTS "gaClientId" varchar, žádný backfill/data change → hub-first-verify (jako mig 153). ⚠️ NOVÝ OPTIONAL envGA4_MEASUREMENT_ID+GA4_API_SECRET— bez nich refund event skipne (fail-soft), deploy boot OK; Libor aktivuje z GA4 adminu (Data Streams → MP API secrets) → prod env post-deploy. Hub: mig 154 OK (gaClientId ověřen), QA 15/15 PASS genuine, VERIFIED. Prod: VERIFIED, migrace 154 na s60_pulse_prod (gaClientId), health 200 R=0, pulselab.cz 200, žádný docker race. Happy-path platby beze změny. tsc 0, 1542+10 testů, reviewer PASS 2 kola. | 2026-06-30 15:23 UTC | billit | hub |0dbf854| chore(deploy): DEPLOY.md pending bundle f93608a (REQ-054+REQ-053, 1 migrace) + module SPEC sync | ✅ done (qa=skip) | | 2026-06-30 15:26 UTC | billit | prod |0dbf854| chore(deploy): DEPLOY.md pending bundle f93608a (REQ-054+REQ-053, 1 migrace) + module SPEC sync | ✅ done (qa=skipped) |Pozn. billit 0dbf854 (=f93608a: tripwire fix + REQ-054 payment konsolidace + REQ-053 unikátní VS) hub+prod — 1 additivní migrace, hub-first-verify: Delta nad LIVE
960af11= 624fada (tenant tripwire vyloučit ApiKey, GlitchTip 15 false-positive) + 2fbb310 REQ-054 inc1 (konsolidace platebních přechodů — duplikátníbanking.service.recordPaymentBEZ kaskády smazán → deleguje na kanonickouinvoicesService.recordPayment: status PAID → tryAutoSettle + order.paid/invoice.paid webhook + email + Pulse notifikace; idempotence externalId) + f93608a REQ-054 inc2 FE (OrderDetail settlementStatus + „Zaznamenat platbu") + REQ-053 unikátní VS. Migrace1772950000000-Req053VsUniqueness= čistě ADDITIVNÍ:tenants ADD COLUMN inherit_vs_from_proforma bool NOT NULL DEFAULT false+number_formats ADD COLUMN vs_prefix varchar(10), IF NOT EXISTS, žádný backfill, jen config tabulky, defaulty=dnešní chování (CON-B kompat) → hub-first-verify. Hub: migrace executed, 2 sloupce ověřeny, health 200/200, VERIFIED. Prod: migrace executed (1+1 sloupce), oba containery R=0 healthy, ucto.studio60.cz 200, žádný docker race. BE(13)+FE(5) → 2/2 labely. QA FAIL = X-User blocker → override (stale dd2b96d stamp). POST-DEPLOY (Libor): zaseklá objednávka PF-2026-0006 (studio-60, 200 Kč, platba před REQ-054 fixem bez kaskády) → srovnat přes „Zaznamenat platbu" (ověří, že fix kaskáduje). Payment-path X-User-blokovaná pro QA → reálná validace = billit testy + reviewer + Liborův PF-2026-0006 test. | 2026-06-30 17:03 UTC | billit | hub |4602906| chore(deploy): DEPLOY.md — pending bundle dc6de4b (Fio auto-match + refund prefill, bez migrace) | ✅ done (qa=skip) | | 2026-06-30 17:05 UTC | billit | prod |4602906| chore(deploy): DEPLOY.md — pending bundle dc6de4b (Fio auto-match + refund prefill, bez migrace) | ✅ done (qa=skipped) |Pozn. billit 4602906 (=dc6de4b: Fio auto-match fix + refund prefill) hub+prod — BE+FE, BEZ migrace: Delta nad LIVE
0dbf854=8ddbe23(kritický fix: Fio platby se auto-nepárovaly —FioApiService.syncAccountteď po importu volábankingService.matchTransactions(tenantId)→ Fio platby z 10min cronu i manuálu se auto-párují VS+částka+nezaplaceno vč. backlogu → kanonická recordPayment REQ-054 → kaskáda settle + order.paid/invoice.paid webhook → Pulse; email/Stripe fungovaly, Fio kanál ne; DI FioApiService→BankingService bez cyklu, match-fail neshodí sync try/catch, +2 regresní testy) +dc6de4b(refund prefill — předvyplní účet odesílatele ze spárované bankovní transakce, BE+FE). db_change none, žádná migrace. Oba env VERIFIED, 2/2 labely, R=0 healthy, ucto.studio60.cz 200, žádný docker race. ⚠️ Po deployi první Fio sync auto-spáruje backlog dosud nespárovaných Fio plateb (dávka recordPayment → settle + Pulse webhooky) — záměr fixu. QA FAIL = X-User blocker → override. Payment path X-User-blokovaná pro QA → reálná validace = billit testy (+2 regresní) + reviewer + sledování po deployi. Navazuje na REQ-054 payment konsolidaci (0dbf854). | 2026-07-02 17:50 UTC | billit | hub |4602906| chore(deploy): DEPLOY.md — pending bundle dc6de4b (Fio auto-match + refund prefill, bez migrace) | ✅ done (qa=skip) | | 2026-07-02 17:51 UTC | billit | prod |4602906| chore(deploy): DEPLOY.md — pending bundle dc6de4b (Fio auto-match + refund prefill, bez migrace) | ✅ done (qa=skipped) |Pozn. billit 4602906 re-deploy hub+prod 2026-07-02 17:50 — APP_URL STOPGAP (env-only, --skip-build, URGENT customer-facing): NE nová verze (4602906 už LIVE) — re-deploy kvůli env změně. Billit TODO T-20260702-023 (na Liborův pokyn): prod potvrzovací e-maily z Účta odkazovaly na dev doménu
billit.s60dev.cz(zákazník to už dostal, čekala se platba od velkého klienta) — buggyauto-email.service.tsčteprocess.env.APP_URL(prázdné → dev default) místoAPP_BASE_URL. Stopgap: přidánAPP_URL=https://ucto.studio60.czdo/root/secrets/billit/.env.prod(backup.env.prod.bak-20260702-1748-pre-appurl) → refresh billit hub (--skip-build, gate) → billit prod --skip-build → env načtena. Ověřeno v běžícím containeru:APP_URL=https://ucto.studio60.cz(R=0 healthy, ucto.studio60.cz 200). E-maily teď odkazují správně. FOLLOW-UP: po billit trvalém batch fixu (kód pak čte APP_BASE_URL) odstranit redundantní APP_URL z .env.prod ([[project_open_ops_threads]]). | 2026-07-03 05:59 UTC | billit | hub |bb6e0cd| chore(deploy): DEPLOY.md — pending batch 41cde2c (BUG-001+CR-050+auto-email, 2 migrace, db_change major) | ⚠️ fail (qa=skipped) | | 2026-07-03 06:02 UTC | billit | hub |bb6e0cd| chore(deploy): DEPLOY.md — pending batch 41cde2c (BUG-001+CR-050+auto-email, 2 migrace, db_change major) | ✅ done (qa=skip) | | 2026-07-03 06:29 UTC | billit | hub |4c9b500| chore(deploy): DEPLOY.md — pending batch e82af6e (+ BUG-002 split allocation, bez migrace) | ✅ done (qa=pass) | | 2026-07-03 07:39 UTC | billit | prod |4c9b500| chore(deploy): DEPLOY.md — pending batch e82af6e (+ BUG-002 split allocation, bez migrace) | ✅ done (qa=skipped) | | 2026-07-03 07:51 UTC | billit | prod |4c9b500| chore(deploy): DEPLOY.md — pending batch e82af6e (+ BUG-002 split allocation, bez migrace) | ✅ done (qa=skipped) | | 2026-07-03 08:06 UTC | s60-pulse | hub |4c9bcb6| chore(pulse): DEPLOY.md — Current b81750b (+ CR-024 delete v detailu klienta) | ✅ done (qa=pass) | | 2026-07-03 08:10 UTC | s60-pulse | prod |4c9bcb6| chore(pulse): DEPLOY.md — Current b81750b (+ CR-024 delete v detailu klienta) | ✅ done (qa=skipped) | | 2026-07-03 08:25 UTC | billit | hub |6c5f966| docs(spec): doplnit poslední chybějící SPECy — bank-accounts (CR-046) + config (CR-028) | ✅ done (qa=pass) | | 2026-07-03 08:26 UTC | billit | prod |6c5f966| docs(spec): doplnit poslední chybějící SPECy — bank-accounts (CR-046) + config (CR-028) | ✅ done (qa=skipped) | | 2026-07-03 13:31 UTC | badwolf | hub |21da0db| docs(deploy): DEPLOY.md Current → 90762dc (CR-004 + DES-004 release, migrace 044) | ✅ done (qa=skip) | | 2026-07-03 14:01 UTC | badwolf | prod |21da0db| docs(deploy): DEPLOY.md Current → 90762dc (CR-004 + DES-004 release, migrace 044) | ✅ done (qa=skipped) | | 2026-07-03 20:58 UTC | billit | hub |f734d52| chore(deploy): DEPLOY.md — REQ-055 migrace defenzivní (varianta B), HEAD 881e4d2 | ✅ done (qa=pass) | | 2026-07-03 21:01 UTC | billit | prod |f734d52| chore(deploy): DEPLOY.md — REQ-055 migrace defenzivní (varianta B), HEAD 881e4d2 | ✅ done (qa=skipped) | | 2026-07-04 04:08 UTC | billit | hub |4bc882f| chore(deploy): DEPLOY.md — + CR-052 (webhook scope UI), HEAD a8f90f9 | ✅ done (qa=pass) | | 2026-07-04 04:11 UTC | billit | prod |4bc882f| chore(deploy): DEPLOY.md — + CR-052 (webhook scope UI), HEAD a8f90f9 | ✅ done (qa=skipped) | | 2026-07-04 04:48 UTC | billit | hub |464ab01| chore(deploy): DEPLOY.md — + BUG-003 Safari toast fix, HEAD 00836d7 | ⚠️ fail (qa=skipped) | | 2026-07-04 04:50 UTC | billit | hub |464ab01| chore(deploy): DEPLOY.md — + BUG-003 Safari toast fix, HEAD 00836d7 | ✅ done (qa=pass) | | 2026-07-04 04:51 UTC | billit | prod |464ab01| chore(deploy): DEPLOY.md — + BUG-003 Safari toast fix, HEAD 00836d7 | ⚠️ fail (qa=skipped) | | 2026-07-04 04:52 UTC | billit | prod |464ab01| chore(deploy): DEPLOY.md — + BUG-003 Safari toast fix, HEAD 00836d7 | ✅ done (qa=skipped) | | 2026-07-04 05:07 UTC | badwolf | hub |21da0db| docs(deploy): DEPLOY.md Current → 90762dc (CR-004 + DES-004 release, migrace 044) | ✅ done (qa=pass) | | 2026-07-04 05:08 UTC | badwolf | prod |21da0db| docs(deploy): DEPLOY.md Current → 90762dc (CR-004 + DES-004 release, migrace 044) | ✅ done (qa=skipped) | | 2026-07-04 05:25 UTC | billit | hub |77ee095| chore(deploy): DEPLOY.md — admin Systém/accept-invite/select-all, HEAD 6e1be2b | ✅ done (qa=pass) | | 2026-07-04 05:29 UTC | billit | prod |77ee095| chore(deploy): DEPLOY.md — admin Systém/accept-invite/select-all, HEAD 6e1be2b | ✅ done (qa=skipped) | | 2026-07-04 19:06 UTC | badwolf | hub |21da0db| docs(deploy): DEPLOY.md Current → 90762dc (CR-004 + DES-004 release, migrace 044) | ✅ done (qa=pass) | | 2026-07-04 19:07 UTC | badwolf | prod |21da0db| docs(deploy): DEPLOY.md Current → 90762dc (CR-004 + DES-004 release, migrace 044) | ✅ done (qa=skipped) | | 2026-07-05 07:35 UTC | s60-auth | hub |a9f2388| chore: DEPLOY.md — CR-016 docasny admin API pristup (f3169db), db_change: none | ✅ done (qa=pass) | | 2026-07-05 07:38 UTC | s60-auth | prod |a9f2388| chore: DEPLOY.md — CR-016 docasny admin API pristup (f3169db), db_change: none | ✅ done (qa=skipped) | | 2026-07-05 08:11 UTC | s60-auth | hub |a9f2388| chore: DEPLOY.md — CR-016 docasny admin API pristup (f3169db), db_change: none | ✅ done (qa=pass) | | 2026-07-05 08:15 UTC | s60-auth | hub |d14901d| chore: DEPLOY.md — login e-mail button (8881031) | ✅ done (qa=pass) | | 2026-07-05 08:17 UTC | s60-auth | prod |d14901d| chore: DEPLOY.md — login e-mail button (8881031) | ✅ done (qa=skipped) | | 2026-07-05 08:57 UTC | billit | hub |50fabda| docs(runbook): Learnia webhook — potvrzený stav (plugin na forge.learnia.cz, config→DEV/studio-60) | ✅ done (qa=pass) | | 2026-07-05 09:00 UTC | billit | prod |50fabda| docs(runbook): Learnia webhook — potvrzený stav (plugin na forge.learnia.cz, config→DEV/studio-60) | ✅ done (qa=skipped) | | 2026-07-05 09:06 UTC | badwolf | hub |832fc08| fix(billit-sync): online kurz type 'digital' → 'online_course' (DEC-001 canon) | ✅ done (qa=pass) | | 2026-07-05 09:07 UTC | badwolf | prod |832fc08| fix(billit-sync): online kurz type 'digital' → 'online_course' (DEC-001 canon) | ✅ done (qa=skipped) | | 2026-07-05 20:41 UTC | s60-pulse | hub |0b81dac| feat(pulse): CR-210 — admin správa speciálních nabídek (viditelnost, editor s preview, statistiky) | ✅ done (qa=pass) | | 2026-07-05 20:44 UTC | s60-pulse | prod |0b81dac| feat(pulse): CR-210 — admin správa speciálních nabídek (viditelnost, editor s preview, statistiky) | ✅ done (qa=skipped) | | 2026-07-06 ~09:30 UTC | pulse (nginx) | prod ops | — | www.pulselab.cz fix: cert expandován o www SAN (certbot certonly --nginx, cert-name pulselab.cz, exp 2026-10-04), vhost přepsán — www:80/443 → 301 https://pulselab.cz$request_uri (samostatný 443 blok), apex beze změny; hygiena: 2× pulselab .bak + 1× auth .bak přesunuty z sites-enabled → /etc/nginx/vhost-backups (konfliktní server_name warns pryč); rollback: /etc/nginx/vhost-backups/pulselab.cz.bak-20260706-pre-www301. Verify: www http+https 301→apex, apex 200, ssl_verify=0 | ✅ | sentinel | | 2026-07-06 | badwolf jenkins-sync | prod+hub ops (Fáze D CR-004 B6 DOKONČENA) |832fc08| Guarded catch-up applier + trvalý cron — Jenkins→BW sync LIVE na obou env (Libor GO krok 1 + krok 2). Prod běh 06:14–09:15 UTC: {applied 131307, guardConflict 0, deferred 20}; hub běh ~09:5x–13:0x: {applied 131345, guardConflict 0, deferred 87→67 needs_review (sdílený defer_count napříč env — prod cron retry eskalovaly čítač)}. Parita dev↔prod i dev↔hub ověřena (orders/course_dates/closed 58=58; delty = jen vadné řádky). Granty s60_sentinel_sync doplněny per Libor OK: SELECT sync_config+sync_suppressions, UPDATE defer sloupců, UPDATE status_hub/applied_hub_at/hub_applied_hash. Cron: prod20 * * * *, hub25 * * * *(log /var/log/jenkins-sync/ + logrotate; single-flight advisory lock). DEVIACE od PROD_REQUIREMENTS §1.4: bez stop-tik + prod-baseline.ts (dle T-20260630-009; empiricky guardConflict=0 → ekvivalence; reportováno badwolf T-012/T-053). Datové anomálie (needs_review): clients j26788 dup email + FK kaskáda, order_items FK product_id, order_vouchers FK — badwolf řeší. | ✅ | sentinel | | 2026-07-06 18:09 UTC | billit | hub |6290b86| feat(billit): detail objednávky — vendor routing + DPH na řádcích | ✅ done (qa=pass) | | 2026-07-06 18:11 UTC | billit | prod |6290b86| feat(billit): detail objednávky — vendor routing + DPH na řádcích | ✅ done (qa=skipped) | | 2026-07-06 ~19:3x UTC | billit | hub |6290b86| feat(billit): detail objednávky — vendor routing + DPH na řádcích (delta od 50fabda, bez migrace) | ✅ done (qa=pass 4/4 genuine, served bundle ověřen: OrderDetailPage chunk obsahuje Vendor+DPH) | | 2026-07-06 ~19:4x UTC | billit | prod |6290b86| feat(billit): detail objednávky — vendor routing + DPH na řádcích | ✅ done (VERIFIED source hash match, labely 2/2, ucto health 200, served bundle ověřen) | | 2026-07-06 18:46 UTC | badwolf | hub |db477fa| docs(deploy): DEPLOY.md Current → ca57707 (DEC-004 + E2E fixy, bez migrace) | ✅ done (qa=pass) | | 2026-07-06 18:47 UTC | badwolf | prod |db477fa| docs(deploy): DEPLOY.md Current → ca57707 (DEC-004 + E2E fixy, bez migrace) | ✅ done (qa=skipped) | | 2026-07-06 18:54 UTC | venom | hub |d64b2f0| fix: DEC-002 — zapracování nálezů adversarial review | ✅ done (qa=pass) | | 2026-07-06 19:00 UTC | venom | hub |d64b2f0| fix: DEC-002 — zapracování nálezů adversarial review | ✅ done (qa=pass) | | 2026-07-06 19:06 UTC | venom | hub |d64b2f0| fix: DEC-002 — zapracování nálezů adversarial review | ✅ done (qa=pass) | | 2026-07-06 19:07 UTC | venom | prod |d64b2f0| fix: DEC-002 — zapracování nálezů adversarial review | ✅ done (qa=skipped) | | 2026-07-06 ~19:2x UTC | badwolf | hub+prod |db477fa| DEC-004 OpenAPI kontrakt + 4 E2E enrollment fixy (BullMQ jobId, /online-courses 500, retry re-enqueue, payload.lines fallback); kód=ca57707 | ✅ done (hub qa=pass 4/4; prod VERIFIED; MOODLE_URL+TOKEN do prod containeru, PUSH flag OFF) | | 2026-07-06 ~19:5x UTC | badwolf | prod+hub ops (seedy) |db477fa| 3 seedy aplikovány + verify: moodle_id 34/34 oba env, kmedin2_all, orders backfill (total 4315/4315 prod, 4314/4314 hub); zálohy env.env.prod.bak-20260706-moodle| ✅ | | 2026-07-06 ~21:1x UTC | venom | hub+prod |d64b2f0| DEC-002 OpenAPI codegen + orders/DTO fixy. INCIDENT: všechny venom deploye od 29.3. byly silent no-op — deploy.shbuild.commandz deploy.yml NIKDY nespouští a venom compose nemá build sekci → recyklace dubnového image (labely lhaly, odhalil served-bundle check). Fix: build na sentinelu z reálných kopií (rsync -aL, per-env VITE args: hub api/auth.s60hub.cz, prod api/auth.studio60.cz) → docker save/load → retag latest → deploy.sh --skip-ci recreate. Served bundle ověřen: hub index-faAe_HHb.js, prod index-CqId8s0N.js (orderNumber ✓). Stale kopie zálohována /root/backups/bw-venom-stale-copy-20260329; sentinel /root/projects/bw/venom nyní symlink. CI --skip-ci (Libor OK, pre-existing vitest×Playwright misconfig → venom TODO T-128). Systémová oprava (compose build sekce) → venom TODO | ✅ done (qa=pass) | | 2026-07-07 03:25 UTC | billit | hub |a804756| chore(deploy): DEPLOY.md — CR-043 voucher engine batch (delta od LIVE 50fabda, 2 migrace) | ✅ done (qa=pass) | | 2026-07-07 03:27 UTC | billit | prod |a804756| chore(deploy): DEPLOY.md — CR-043 voucher engine batch (delta od LIVE 50fabda, 2 migrace) | ✅ done (qa=skipped) | | 2026-07-07 ~03:2x UTC | billit | hub ops (dress rehearsal, Libor DEPLOY OK) |a804756| Dress rehearsal před CR-043 prod deployem: clone s60_billit_prod → s60_billit_hub na pg-alfa (runbook pg-alfa-db-clone.md; pre-clone backup + prod dump v/var/lib/postgresql/billit-clone-20260707-032210/, ownership 44/44). Live secrets v clonu scrubnuty (9× fio_api_token, inbound_email_token → NULL). Migrace CR043P1 realignproducts.typeověřen nad prod daty: course 9→online_course, digital 15→ebook, physical 3→other — identický výsledek pak na produ. Pozn.: skutečná delta byla 6290b86→a804756 (billit uváděl LIVE 50fabda — o deploy pozadu, bez dopadu, TypeORM migrace idempotentní). Deploy gate pro WP/Pulse voucherCode/productType odblokován. | ✅ | | 2026-07-07 03:41 UTC | venom | hub |63f447c| fix(venom): exclude e2e specs from vitest to prevent Playwright collision [no-spec bugfix] | ✅ done (qa=pass) | | 2026-07-07 03:43 UTC | venom | prod |63f447c| fix(venom): exclude e2e specs from vitest to prevent Playwright collision [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-07-07 ~03:5x UTC | badwolf | hub+prod ops (seed, Libor DEPLOY OK) |ae25e90| Seedprod-seeds/2026-07-07_products_49_50.sqlaplikován na s60_badwolf_hub + s60_badwolf_prod (pg-alfa SU): products 49 buy_kmedin2_all (online_course→kmedin2_all, FK ověřen předem) + 50 buy_velikonoce (archived bundle) — FK cíle pro order_items anomálii T-20260706-053. Idempotentní INSERTy, verify SELECT 2/2 na obou env. Žádný app deploy (DEPLOY.md Current = ca57707 beze změny, kontejnery netknuty). Released tasky dožene guarded cron (prod :20, hub :25). Pozn.: badwolf neposlal formální deploy-go — akce dle commitu ae25e90 + Libor OK; badwolfovi připomenuto poslat request příště. | ✅ | | 2026-07-07 04:45 UTC | s60-auth | hub |0f1f0ee| chore: DEPLOY.md — Google login fix (230154c) | ✅ done (qa=pass) | | 2026-07-07 04:46 UTC | s60-auth | prod |0f1f0ee| chore: DEPLOY.md — Google login fix (230154c) | ✅ done (qa=skipped) | | 2026-07-07 04:51 UTC | billit | hub |f2852a2| feat(billit-api): CR-053 — import Jenkins voucherů (inner-sense) + per-person quote fix | ⚠️ fail (qa=skipped) | | 2026-07-07 04:53 UTC | billit | hub |f2852a2| feat(billit-api): CR-053 — import Jenkins voucherů (inner-sense) + per-person quote fix | ✅ done (qa=pass) | | 2026-07-07 04:55 UTC | billit | prod |f2852a2| feat(billit-api): CR-053 — import Jenkins voucherů (inner-sense) + per-person quote fix | ✅ done (qa=skipped) | | 2026-07-07 ~04:5x UTC | billit | hub+prod ops (CR-053 SQL import, Libor DEPLOY OK) |f2852a2| Manuální SQLCR-053-import-jenkins-vouchers.sqlaplikován PO app deployi (pořadí dle DEPLOY.md — per-person fix nutný pro importované vouchery): hub i prod 256 imported / used_count_sum 777 (přesně dle očekávání, idempotentní ON CONFLICT, tenant guard inner-sense ověřen předem na obou DB). Hub apply = zároveň rehearsal nad prod clonem z rána. Pozn. deploy: hub 1. běh label FAILbillit-web=a804756(selective_recreate false-positive dle [[selective-recreate-label-check]]) → workaround force-recreate web + re-run → ✅ qa=pass; prod prošel čistě 2/2. REPLY badwolfovi na T-20260707-009 posílá billit. | ✅ | | 2026-07-07 05:48 UTC | badwolf | hub |b101364| docs(deploy): Current → 2ffd0b8 (+ migrace 045 REQ-009 search) | ✅ done (qa=pass) | | 2026-07-07 05:50 UTC | badwolf | prod |b101364| docs(deploy): Current → 2ffd0b8 (+ migrace 045 REQ-009 search) | ✅ done (qa=skipped) | | 2026-07-07 05:51 UTC | badwolf | prod |b101364| docs(deploy): Current → 2ffd0b8 (+ migrace 045 REQ-009 search) | ✅ done (qa=skipped) | | 2026-07-07 05:57 UTC | venom | hub |3d81fe1| feat(orders): REQ-008 — taby Položky a Dokumenty v OrderDetail | ✅ done (qa=pass) | | 2026-07-07 05:58 UTC | venom | prod |3d81fe1| feat(orders): REQ-008 — taby Položky a Dokumenty v OrderDetail | ✅ done (qa=skipped) | | 2026-07-07 06:02 UTC | billit | hub |9816bc1| feat(billit): CR-054 — vouchery UI: Vystaven, řazení, hledání, editace kódu (409 dup), generátor | ✅ done (qa=pass) | | 2026-07-07 06:04 UTC | billit | prod |9816bc1| feat(billit): CR-054 — vouchery UI: Vystaven, řazení, hledání, editace kódu (409 dup), generátor | ✅ done (qa=skipped) | | 2026-07-07 ~06:0x UTC | badwolf | hub+prod ops + INCIDENT (release 2ffd0b8/b101364, Libor DEPLOY OK) |b101364| INCIDENT: všechny badwolf deploye 29.6.–6.7. byly silent no-op — compose bezbuild:sekce (deploy.shbuild.commandmrtvý, stejná třída jako venom 6.7.) + /opt zdrojáky z 29.6. → prod/hub běžely image z 29.6., proto/api/online-courses500 (phantom sloupce, fix ca57707 nikdy neběžel) a DES-004 moodle kód nebyl live. Odhaleno: image built timestamp + prod logOnlineCourse.base_price_czk does not exist. Náprava: (1) migrace 045 hub+prod (pg-alfa SU: unaccent + pg_trgm + f_unaccent + 4× GIN idx clients — verify 4/4 obě env); (2) ruční builds60-badwolf:b101364z git archive (kód 2ffd0b8 REQ-009 search; ověřeno v dist: phantom pryč, f_unaccent 4×, moodle modul in) → save/load → retag → deploy.sh --skip-build hub (QA 4/4 PASS) + prod; (3) verify běžícím kódem, ne labely: /api/online-courses 200 obě env, image built 2026-07-07; (4) MOODLE_PUSH_ENABLED=true na PRODU (přes /root/secrets/badwolf/.env.prod — pozn.: append na /opt/.env deploy.sh přepíše!, backup .bak-20260707-moodle-flip; force-recreate compose servicebadwolf), hub flip NEproveden (reálný Moodle token + test data = side-effect risk, dotaz badwolfovi). Seedy 4/4 už aplikované dřív. Systémový fix compose build → TODO badwolf. Kosmetické: invalid Sentry DSN v prod logu. | ✅ | | 2026-07-07 ~06:0x UTC | venom+billit | hub+prod ops pozn. |3d81fe1/9816bc1| venom 3d81fe1 (REQ-008 taby, Liborův pokyn via venom T-048): ruční build z git archive per-env VITE args, served bundle ověřen (Dokumenty 3× hub i prod, žádný cross-env leak). billit 9816bc1 (CR-054 vouchery UI): CR-053 část byla už LIVE (billit request psán proti staré LIVE — 2. výskyt dnes), SQL import NEopakován (data verify 256/777 netknuto); hub 1. běh docker race „name already in use" (double-run + hash-prefixed container, viz [[deploy-docker-race]]) → rm 3 kontejnerů + re-run --skip-build → healthy, QA PASS; prod čistě. CR-054 v served assets ověřen (Vouchers chunk). | ✅ | | 2026-07-07 06:49 UTC | venom | hub |191ad8e| feat(applications): REQ-010 — efektivní cena přihlášky (fallback na cenu termínu) | ✅ done (qa=pass) | | 2026-07-07 06:50 UTC | venom | prod |191ad8e| feat(applications): REQ-010 — efektivní cena přihlášky (fallback na cenu termínu) | ✅ done (qa=skipped) | | 2026-07-07 11:06 UTC | badwolf | hub |2ef5f0a| feat(applications): ?courseId= filtr na GET /applications (Libor approve, DEC-004 rozšíření) | ✅ done (qa=pass) | | 2026-07-07 11:08 UTC | badwolf | prod |2ef5f0a| feat(applications): ?courseId= filtr na GET /applications (Libor approve, DEC-004 rozšíření) | ✅ done (qa=skipped) | | 2026-07-07 ~11:0x UTC | badwolf | hub+prod DB ops |2ef5f0a| Migrace 046 (CR-005):sync_hash_columns.applications+= status/payment/presence — pg-alfa SU, hub i prod, PŘED app deployem. Guard arming: re-backfillUPDATE applications SET row_hash=row_hash(7220 řádků hub i prod) + resetsync_state.prod_applied_hash/hub_applied_hash=NULLpro applications na s60_badwolf_dev (7221 řádků) — guard se doarmuje dalším sync cronem. App: ruční build z git archive (compose build fix stále u badwolfa), image 13:04 ověřen na obou env. Prod verify:?courseId=00f77009…→ meta.total=34 ✓, MOODLE_PUSH_ENABLED=true přežil (secrets). | ✅ | | 2026-07-07 13:09 UTC | venom | hub |7f43ed8| feat: DES-001 — detail ve dvou rámech: boční panel nad seznamem + plná stránka | ✅ done (qa=pass) | | 2026-07-07 13:10 UTC | venom | prod |7f43ed8| feat: DES-001 — detail ve dvou rámech: boční panel nad seznamem + plná stránka | ✅ done (qa=skipped) | | 2026-07-07 ~13:1x UTC | venom | hub+prod ops pozn. |7f43ed8| Finální balík (venom T-077, Liborův deploy-go „sentinel hub+prod"): BW část (2ef5f0a) už byla LIVE, reálná delta venom = 191ad8e..7f43ed8 (8 commitů: REQ-011/012 stránky s URL, DES-001 dva rámy, server-side stránkování + courseId) — venom request psán proti 63f447c (stale LIVE pointer, 2. výskyt u venoma). Ruční per-env buildy z git archive, bundle check v image PŘED přenosem (hub→api.s60hub.cz, prod→api.studio60.cz,orders/newmarker, žádný leak). Served: hub index-D4rugwr2.js, prod index-B6dZEHAw.js. Balík verify: online-courses 200, courseId total=34. Authed E2E sweep delegován na test agenta. | ✅ | | 2026-07-08 04:12 UTC | billit | hub |5b3bba7| feat(billit): CR-055 — order delivery/shipping model + plná editace + rozšířený webhook snapshot (kontrakt BW+WC) | ✅ done (qa=pass) | | 2026-07-08 04:14 UTC | billit | prod |5b3bba7| feat(billit): CR-055 — order delivery/shipping model + plná editace + rozšířený webhook snapshot (kontrakt BW+WC) | ✅ done (qa=skipped) | | 2026-07-08 ~04:1x UTC | billit | hub |5b3bba7| CR-055 order delivery/shipping + rozšířený webhook snapshot + CR-054 vouchery UI (migrace 1773030000000 additivní) | ✅ done (qa=pass 4/4, migrace applied=1, delivery_method col ok, served bundle index-BdI4Nt38) | | 2026-07-08 ~04:2x UTC | billit | prod |5b3bba7| CR-055 + CR-054 (migrace 1773030000000) | ✅ done (VERIFIED, labely 2/2, migrace applied=1, ucto/health 200, served bundle index-KYum3YID) | | 2026-07-08 ~04:2x UTC | billit | prod ops (webhook config) | — | Learnia webhookd12d1280rozšířen z [order.paid, invoice.created] → [order.created, order.paid, order.updated, order.cancelled, order.refunded, invoice.created, invoice.paid] (PATCH 200, re-GET ověřen; billitem vyžádaný post-deploy CR-055). BASELINE korekce: reálně běželo9816bc1(ne6290b86můj záznam /a804756billitův migration_from) — CR-053 (256 voucherů hub+prod) i CR-054 už live; delta = 1 commit CR-055, 1 migrace | ✅ | sentinel | | 2026-07-08 04:35 UTC | badwolf | hub |1c160ee| feat(orders): CR-006 — order mirror read-only + delivery + orderUrl (companion billit CR-055) | ✅ done (qa=skip) | | 2026-07-08 04:37 UTC | badwolf | prod |1c160ee| feat(orders): CR-006 — order mirror read-only + delivery + orderUrl (companion billit CR-055) | ✅ done (qa=skipped) | | 2026-07-08 ~04:35 UTC | badwolf | prod+hub ops (migrace 047) |1c160ee| CR-006 order mirror — migrace 047 (ADD COLUMN IF NOT EXISTS: orders.order_url/delivery jsonb + order_items.product_type/category/is_discount) aplikována psql hub+prod PŘED app release; 5 sloupců ověřeno | ✅ | | 2026-07-08 ~04:36 UTC | badwolf | hub |1c160ee| CR-006 order mirror read-only + delivery + orderUrl (companion billit CR-055) | ✅ done (RUČNÍ build na sentinelu — compose bez build sekce; label 1c160ee healthy, /api/health 200, PATCH /orders→405 zámek, delivery v api-docs). QA gate SKIP (no config), funkčně ověřeno | | 2026-07-08 ~04:37 UTC | badwolf | prod |1c160ee| CR-006 order mirror (companion billit CR-055) | ✅ done (VERIFIED source hash match, label 1c160ee healthy, /api/health 200, PATCH /orders→405, delivery v api-docs). Reálná delta od běžícího 2ef5f0a = 3 commity | | 2026-07-08 05:20 UTC | venom | hub |516c002| spec: REQ-009 → implemented (BW unaccent+víceslovné search live, venom používá) | ✅ done (qa=pass) | | 2026-07-08 05:21 UTC | venom | prod |516c002| spec: REQ-009 → implemented (BW unaccent+víceslovné search live, venom používá) | ✅ done (qa=skipped) | | 2026-07-08 ~05:20 UTC | venom | hub+prod |516c002| CR-001 objednávky READ-ONLY (Účto autorita) + REQ-013 komunikace autor + REQ-009 client search. Čistě FE, bez migrace. RUČNÍ build na sentinelu (compose bez build sekce), per-env VITE, save/load. Served bundle ověřen: hub index-DmJD0gr4 / prod index-CULMou5Y (orderUrl přítomen, prod API=api.studio60.cz). Reálná delta od běžícího 7f43ed8 = 4 commity | ✅ done | | 2026-07-08 ~05:1x UTC | badwolf webhook | prod ops (config) | — | Enrollment webhook440f4e40(inner-sense) rozšířen [order.created, order.paid] → [+order.updated, order.cancelled, order.refunded] (PATCH 200, badwolf T-035 žádost — CR-006 mirror handler potřebuje eventy) | ✅ | sentinel | | 2026-07-08 05:29 UTC | billit | hub |5dd0a4b| feat(billit): CR-057 — plná editace objednávky: katalog picker + vendor per řádek + Packeta výběr výdejny + 2 bugy | ✅ done (qa=pass) | | 2026-07-08 05:31 UTC | billit | prod |5dd0a4b| feat(billit): CR-057 — plná editace objednávky: katalog picker + vendor per řádek + Packeta výběr výdejny + 2 bugy | ✅ done (qa=skipped) | | 2026-07-08 ~05:3x UTC | billit | hub+prod |5dd0a4b| CR-057 — plná editace objednávky: BUG-B data-loss fix (editace mazala vendor split) + BUG-A carrier scope + katalog/vendor picker per řádek. Bez migrace, delta od 5b3bba7 = 1 commit. hub qa=pass, prod labely 2/2 healthy, served bundle hub BM6SlYnc / prod B0OO-P4H. ⚠️ Packeta map widget SKRYTÝ — billit nezadrátoval VITE_PACKETA_WIDGET_API_KEY do Dockerfile ARG ani compose build args → TODO billit; klíč (Klíč API 2f7d…) uložen/root/secrets/billit/packeta-innersense.env+ připraven ve .env.hub/.env.prod (zapne se automaticky po wiring + rebuild) | ✅ | sentinel | | 2026-07-08 06:23 UTC | venom | hub |c0b4485| fix(orders): DataCloneError při otevření objednávky — chybějící useLocation | ✅ done (qa=pass) | | 2026-07-08 06:24 UTC | venom | prod |c0b4485| fix(orders): DataCloneError při otevření objednávky — chybějící useLocation | ✅ done (qa=skipped) | | 2026-07-08 ~06:25 UTC | venom | hub+prod |c0b4485| HOTFIX DataCloneError při otevření objednávky (chybějící useLocation → window.location do history.pushState). 1-řádkový fix nad 516c002, bez migrace. RUČNÍ build, served bundle fresh: hub BOovYkLO / prod CZrA0jI_, prod API=api.studio60.cz. Opravuje live prod bug z 516c002 (nasazeno o ~1h dřív) | ✅ done | | 2026-07-08 13:51 UTC | billit | hub |e31d980| fix(billit): CR-057 — protlačit Packeta widget key do Docker buildu (build ARG, ne .env) | ✅ done (qa=pass) | | 2026-07-08 13:53 UTC | billit | prod |e31d980| fix(billit): CR-057 — protlačit Packeta widget key do Docker buildu (build ARG, ne .env) | ✅ done (qa=skipped) | | 2026-07-08 ~10:1x UTC | billit | hub+prod |e31d980| CR-057 Packeta wiring fix — VITE_PACKETA_WIDGET_API_KEY přes build ARG (Dockerfile+compose), compose default = veřejný widget key2f7d875ae6571325(client-side, ships v bundlu; REST heslo v repu NENÍ). Bez migrace. hub qa=pass, served bundle ověřen: OrderEditorPage chunk obsahuje widget.packeta.com + zapečený key na hub i prod → Packeta výběr výdejny z mapy teď funguje. Řeší T-053 | ✅ | sentinel | | 2026-07-08 21:31 UTC | billit | hub |c289cb7| feat(billit): CR-057 rev — odstranit pole Dopravce u doručení na adresu + REQ-058 approved | ⚠️ fail (qa=skipped) | | 2026-07-08 21:34 UTC | billit | hub |c289cb7| feat(billit): CR-057 rev — odstranit pole Dopravce u doručení na adresu + REQ-058 approved | ✅ done (qa=pass) | | 2026-07-08 21:35 UTC | billit | prod |c289cb7| feat(billit): CR-057 rev — odstranit pole Dopravce u doručení na adresu + REQ-058 approved | ⚠️ fail (qa=skipped) | | 2026-07-08 21:37 UTC | billit | prod |c289cb7| feat(billit): CR-057 rev — odstranit pole Dopravce u doručení na adresu + REQ-058 approved | ✅ done (qa=skipped) | | 2026-07-08 ~21:37 UTC | billit | hub+prod |c289cb7| CR-057 rev — u „Doručení na adresu" se pole Dopravce NEzobrazuje (FE only,shippingCarrierz WC se zachová) + REQ-058 approved doc. Bez migrace, bez BE změny. Reálná delta od běžícíhoe31d980= 1 commit (billit v heads-upu počítal od 5b3bba7, ale 5dd0a4b+e31d980 už byly live → docker inspect). Selective recreate (jediný build context = billit-web) → label FAIL 1/2 na billit-api = known false-positive ([[feedback_selective_recreate_label_check]]), align přes--skip-buildre-run → 2/2 c289cb7. Ověřeno naostro: served bundle markerPPL, DPD(odstraněný input) GONE + nový chunk hub OrderEditorPage-Cuio3_qE / prod -ChhAymEz; hub qa=pass 4/4, ucto/health 200 | ✅ | sentinel | | 2026-07-09 03:12 UTC | billit | hub |4151427| fix(billit-api): order edit — null order_id (cascade re-insert stale Order.lines) | ✅ done (qa=pass) | | 2026-07-09 03:14 UTC | billit | prod |4151427| fix(billit-api): order edit — null order_id (cascade re-insert stale Order.lines) | ✅ done (qa=skipped) | | 2026-07-09 ~03:1x UTC | billit | hub+prod |4151427| PROD-BLOCKING bugfix + batch. Delta od LIVEc289cb7= 5 commitů: order-edit NULL order_id fix (cascade re-insert stale Order.lines → PG 23502, GlitchTip #32) + REQ-058 order versioning (BE jádro+endpointy+revert, FE panel „Verze objednávky") + REQ-035 deep health + CR-050 AC3 order.paid dedup. Full-stack build (BE+FE), labels 2/2 na obou. Migrace1773040000000-CreateOrderVersions(CREATE TABLE IF NOT EXISTS order_versions + dormant RLS ENABLE bez FORCE, additivní) — executed hub+prod, tabulka + migration záznam ověřeny v obou DB. Served bundle prod obsahuje „Verze objednávky" (OrderDetailPage-GKrHT3AZ). QA hub PASS 4/4, ucto/health 200. Autorizace: explicitníDEPLOY OK billit hub+prod(Libor), oba tokeny reálně vynuceny opraveným deploy-guardem ([[feedback_deploy_guard_hole_fixed]]) | ✅ | sentinel | | 2026-07-09 03:51 UTC | billit | hub |2da008d| docs(deploy): 4151427 batch nasazen (per Libor), Current = 89d7635 FE panel dopracování | ⚠️ fail (qa=skipped) | | 2026-07-09 04:00 UTC | billit | hub |2da008d| docs(deploy): 4151427 batch nasazen (per Libor), Current = 89d7635 FE panel dopracování | ✅ done (qa=pass) | | 2026-07-09 04:01 UTC | billit | prod |2da008d| docs(deploy): 4151427 batch nasazen (per Libor), Current = 89d7635 FE panel dopracování | ⚠️ fail (qa=skipped) | | 2026-07-09 04:13 UTC | billit | prod |2da008d| docs(deploy): 4151427 batch nasazen (per Libor), Current = 89d7635 FE panel dopracování | ✅ done (qa=skipped) | | 2026-07-09 ~04:1x UTC | billit | hub+prod |2da008d| FE-only redeploy (delta od LIVE 4151427 = 2 commity:89d7635REQ-058 inc3 dopracování FE panelu „Verze objednávky" = hodnoty verze + diff vůči aktuální, klientsky ze snímku bez nového BE endpointu;2da008dDEPLOY.md doc). Bez migrace, BE beze změny. Selective recreate (jen billit-web) → známý label false-positive na billit-api → relabel--skip-build(labels 2/2 na obou). Ověřeno: billit-web 2da008d rebuilt (nový chunk hub CGCj96yA / prod B4mmHsj3), billit-api správně beze změny, health 200, hub QA PASS 4/4. Autorizace: 3×DEPLOY OK(build hub+prod, relabel hub, relabel prod) — FE-only dvojitost kvůli one-time tokenu → follow-up: fix deploy.sh label-check tolerovat selective-skipped kontejner | ✅ | sentinel | | 2026-07-09 11:37 UTC | billit | hub |be95d5e| fix(billit): faktury — hledání dle obsahu (položky/VS/pozn.) + stránkování v detailu kontaktu | ✅ done (qa=pass) | | 2026-07-09 11:39 UTC | billit | prod |be95d5e| fix(billit): faktury — hledání dle obsahu (položky/VS/pozn.) + stránkování v detailu kontaktu | ✅ done (qa=skipped) | | 2026-07-09 ~11:3x UTC | billit | hub+prod |be95d5e| BE+FE, full-stack (delta od LIVE 2da008d = 2 commity:312fff0REQ-058 panel → side-by-side srovnávací tabulka Pole|Tato verze|Aktuální;be95d5ebugfix faktury: BE/invoicessearch rozšířen o variableSymbol+orderNumber+note+názvy položek EXISTS invoice_lines, FE stránkování faktur v detailu kontaktu). Bez migrace, bez DB. Oba build kontexty → full-stack recreate → labels 2/2 na jeden běh (žádný selective false-positive, žádná dvojitost). Ověřeno: billit-api + billit-web rebuilt (image.created 11:36 hub / 11:38 prod), FE marker „Tato verze" v bundlu (hub DXOuKI3M / prod D0JZjelo), hub QA PASS 4/4 RELEASE, health 200. AutorizaceDEPLOY OK billit hub+prod. ⏳ BE search naostro ověří billit (auth) | ✅ | sentinel | | 2026-07-09 13:26 UTC | venom | hub |be35bf4| fix(orders): detail objednávky zobrazí jméno klienta (dohledání přes clientId) | ✅ done (qa=pass) | | 2026-07-09 14:26 UTC | badwolf | hub |99010d6| feat: 3 venom TODO — Order client embed + applications search + communication time/author | ✅ done (qa=skip) | | 2026-07-09 14:30 UTC | badwolf | prod |99010d6| feat: 3 venom TODO — Order client embed + applications search + communication time/author | ✅ done (qa=skipped) | | 2026-07-09 ~14:3x UTC | badwolf | hub+prod |99010d6| RUČNÍ build (compose bez build sekce). Delta od LIVE 1c160ee = 4 commity: CR-007 Moodle (09bd7b4 — manuál enrol/unenrol push +/internal/moodle/reconcile) + 99010d6 (3 venom featury: Order.client embed,/applications?search, ClientCommunication od/do/autor). Migrace 048 (client_communications +started_at/ended_at/author_id, ADD COLUMN IF NOT EXISTS) aplikována psql hub+prod PŘED app release (047 už dřív). Env-agnostic image (1× build, ship hub+prod). Ověřeno naostro: rev 99010d6 healthy, /api/health 200, client embed PŘÍTOMEN,/applications?search=Stanameta.total=8, labels 1/1 (nový selective-aware check). ⚠️ MOODLE_PUSH_ENABLED=true na produ (od 7.7. flip) → s CR-007 kódem je Moodle push LIVE (idle, 0 aktivity). ⚠️ QA gate scoping: badwolf --tier MAJOR pustil billit-spec testy (401 = billit auth šum, ne badwolf) → nahlásit qa | ✅ | sentinel | | 2026-07-09 15:24 UTC | venom | prod |be35bf4| fix(orders): detail objednávky zobrazí jméno klienta (dohledání přes clientId) | ✅ done (qa=skipped) | | 2026-07-09 ~15:2x UTC | venom | hub+prod |be35bf4| RUČNÍ build (compose bez build sekce). Delta od LIVE c0b4485 = 2 FE bugfixy:da3f983online-courses enroll (clientId chybělo v těle DTO → přiřazení online kurzu klientovi funguje) +be35bf4detail objednávky zobrazí jméno klienta (přes clientId). Bez migrace, bez BE. Per-env buildy (hub VITE→api.s60hub.cz, prod→api.studio60.cz). Ověřeno served bundle: hub index-CCCSfhun (api.s60hub.cz) / prod index-lkjLHVQs (api.studio60.cz), labels 1/1 (nový selective-aware check), health 200. Prod token vypršel po hub verify → re-auth (DEPLOY OK venom prod). Klíč: MOODLE/deploy-guard write-op gating teď žije (po ranním fixu) — write-method curl/ssh na hub/prod potřebuje WRITE OK | ✅ | sentinel | | 2026-07-09 17:16 UTC | billit | hub |ce2dffb| feat(billit): CR-058 — konsolidace e-mailů při platbě proformy (potlačit duplicitní „Platba přijata") | ✅ done (qa=pass) | | 2026-07-09 17:18 UTC | billit | prod |ce2dffb| feat(billit): CR-058 — konsolidace e-mailů při platbě proformy (potlačit duplicitní „Platba přijata") | ✅ done (qa=skipped) | | 2026-07-09 ~17:1x UTC | billit | hub+prod |ce2dffb| BE+FE full-stack (delta od LIVE be95d5e = 4 commity: DES-003 per-tenant odesílatel e-mailů fáze 1 — jméno+from+reply-to na ověřené doméně; CR-058 konsolidace e-mailů při platbě proformy). Migrace 1773050000000 (tenants +mail_from_name/address/reply_to, ADD COLUMN IF NOT EXISTS) executed hub+prod, ověřeno v obou DB. Full-stack → labels 2/2 na jeden běh. hub QA PASS 10/10 (billit-spec pod billit gate OK — authed SKIP, žádné false FAIL). health 200. Baseline korekce: billit hlásil delta od 2da008d, reálně LIVE be95d5e → delta 4 commity (docker inspect). Pozn.: e-maily jdou přes s60-mail (STOPPED) → efekt až po jeho spuštění; DES-003 může chtít MAIL_VERIFIED_DOMAINS env (dotaz billitu) | ✅ | sentinel | | 2026-07-10 14:42 UTC | billit | hub |7668bc2| fix(billit): AUDIT X6/X7/M1/M2/M3/M4/I6 — recurring/exports/migrace/health/DTO | ✅ done (qa=pass) | | 2026-07-10 14:47 UTC | billit | prod |7668bc2| fix(billit): AUDIT batch (X1 CRITICAL JWT izolace) + CR-059 | ✅ done (qa=skipped; deploy.sh abort po recreate — docker race, ověřeno manuálně) | | 2026-07-10 ~14:4x UTC | billit | hub+prod |7668bc2| BE+FE full-stack (delta od LIVE ce2dffb = 12 commitů; billit hlásil „od 2da008d" = stale baseline, korekce dle docker inspect). Obsah: kompletní AUDIT cluster 24 nálezů — X1 CRITICAL: JwtTenantGuard cross-tenant JWT izolace (živá díra → prioritní deploy), S1/S4 Stripe (ztracená platba, špatná částka), X2/X3 (cizí banka na faktuře, path traversal příloh), X4/X5 (dobropisy v DPH/KH), B1/B2/B3/B5/B6 (banking dedup/měna/refund/over-allocate), O1/O3/O4/O6/O7 (objednávky vendor split/atomicita), I1/I2/I3/I5/I6/I8, M1–M4 + CR-059 Stripe webhook secret UI. Žádná nová migrace (1773050000000 už executed s ce2dffb — ověřeno v obou DB před deployem; 2 upravené staré migrace = jen replay-safety pro fresh bootstrap, dle názvu se nererunují). Hub: QA PASS 10/10, labels 2/2, health 200, bundle BkIRMgPV. Prod: deploy.sh ABORT na docker race (name conflict20470f677cb1_billit-billit-web-1, známý pattern [[feedback_deploy_docker_race]]) PO úspěšném recreate → stav ověřen manuálně: labels 2/2 rev=7668bc2 (deploy_id 1783694675), oba kontejnery healthy, health 200×3, FE bundle BqjIcYMm servírovaný, žádné orphan kontejnery; deploys.log doplněn ručně (fail+done). Vedlejší nález: pre-deploy DB snapshoty byly od migrace na pg-alfa (04-10) PRÁZDNÉ (20 B gzip) napříč službami — deploy.sh pg_dump mířil na deprecated DO Managed PG (hardcoded doadmin URL), chyba maskovaná|| true→ opraveno v deploy.sh (dump přes pg-alfa SSH + size check). ⏳ X1 authed flows ověří billit | ✅ | sentinel | | 2026-07-11 05:33 UTC | badwolf | hub |de21990| docs(deploy): Current → 50b3ebf (komunikace na přihlášce + soft/hard delete) | ✅ done (qa=pass) | | 2026-07-11 06:01 UTC | badwolf | prod |de21990| docs(deploy): Current → 50b3ebf (komunikace na přihlášce + soft/hard delete) | ✅ done (qa=skipped) | | 2026-07-11 ~06:0x UTC | badwolf | hub+prod |de21990| RUČNÍ build na sentinelu (compose bezbuild:sekce — workaround jako vždy; image479edbaa6d65@ app 50b3ebf,docker save→ssh docker loadhub+prod). Delta od LIVE99010d6= 15 commitů: kumulativní audit 07-09/10 (order mirror unknown-paid→conflict + cancelled fallback + HMAC fail-closed + order_number sequence + POST /orders 405, moodle jobId dedup + by-s60-user deleted_at + reconcile count, enum filtr 500, KVT applications, jenkins status canon, backfill GREATEST, fulfillmentRef UUID guard) + CR-001 PII za JWT (applications/orders/clients — venom gate CLEARED) + REQ-014 komunikace na přihlášce (GET/POST/DELETE) + soft/hard DELETE přihlášky + billit order status mapa (payload.semantic) + enrolledCount (DEC-004) + telefon národní match + price number + bulk payment. Migrace 049 (order conflict typy +order_paid_unmatched/order_unresolved_client) + 050 (oce indexy client_id/online_course/composite-active) — idempotentní, pg-alfa SU hub+prod PŘED app (pre-check: constraint 10→12 typů, oce 2→5 idx obě env; oce 26 683 řádků → CREATE INDEX sub-second). CR-005 guard-arming (046) už z 07-07 → přeskočeno. ENV (do/root/secrets/badwolf/.env.{hub,prod}, backup.bak-20260711-072040-de21990):WEBHOOKS_FAIL_CLOSED=true(defense-in-depth po HMAC fix, Liborovo rozhodnutí) +ANTHROPIC_API_KEY(org key reuse z pulse pro REQ-014 Haiku parser — běží jen když klíč je, jinak appka OK); MOODLE_PUSH_ENABLED=true na produ zachován (ověřeno v containeru). Ověřeno naostro: prod VERIFIED (source hash618f2cc…local=remote + build hash690c9b3…), labely 1/1 @ de21990, oba env/api/health200 + externíapi.studio60.cz200, REQ-014 route/applications/:id/communications→ 401 (nový kód; staré 99010d6 by dalo 404), OnlineCourse phantombase_price_czkpryč (žádné opakování incidentu 7.7.), kontejnery Up healthy. Hub QA gate genuine 4/4 PASS (PATCH), prod gate na čerstvémbadwolf-qa-pass @ de21990. Systémový build-fix (přidatbuild:sekci do compose, aťdeploy.shbuildí sám) → TODO badwolf T-20260711-019 (Libor vyžádal). Deploy-guard pozn.: tokenDEPLOY OK badwolf prodmusí přijít čistým promptem (mid-turn zpráva ho user-prompt-capture hook nezachytí); guardcurl.*--formgreedy match false-posituje nacurl+docker inspect --formatv jednom příkazu → verify rozdělit. | ✅ | sentinel | | 2026-07-11 06:15 UTC | venom | hub |ff16371| chore(types): regenerovat z kontraktu — app-comms, enrolledCount, delete přihlášky | ✅ done (qa=pass) | | 2026-07-11 06:17 UTC | venom | prod |ff16371| chore(types): regenerovat z kontraktu — app-comms, enrolledCount, delete přihlášky | ✅ done (qa=skipped) | | 2026-07-11 ~06:1x UTC | venom | hub+prod |ff16371| FE companion k badwolf de21990 (venom T-20260711-016, Liborův pokyn). 🎉 PRVNÍ deploy přesdeploy.sh --buildbez ručního shipu — build-fixf2a66e9(composebuild:context./+@s60/auth-sdkvendored jakovendor/s60-auth-sdk-0.1.0.tgz) → self-contained, build na cíli, žádné WRITE OK ssh tokeny. Řeší systémový venom TODO T-20260706-134 (kontrast k badwolfovi, kde build-fix teprve TODO T-20260711-019). Delta od LIVEbe35bf4~20 commitů: REQ-013 (čas hovoru od/do), REQ-014 (úprava přihlášky inline + money/note — párový k BW REQ-014), REQ-015 (filtr termínů dle kurzu+období), REQ-016 (idempotentní hromadné odebrání kurzu), server-side search přihlášek, audit fixy (security: CSV formula injection escaping, Sentry PII masking; REQ-007 terms CRUD critical). db_change none (FE, 0 migrací). VITE per-env přes compose build.args z.env.<env>. Ověřeno served bundlem naostro: hubindex-B7_12d2T.js→api.s60hub.cz×2 / studio60 ×0; prodindex-Cgs5gGiG.js→api.studio60.cz×2 / s60hub ×0 (per-env buildy různé hashe = žádná záměna env). Prod VERIFIED (source hash10918f5…match), labely 1/1, oba/health200, hub QA gate 2/2 PASS. Pozn.:/version.json404 (kosmetika nginx, bez vlivu); venom INDEX.md „ruční build" poznámka opravena. | ✅ | sentinel | | 2026-07-11 06:39 UTC | s60-auth | hub |77b0d12| fix(auth): CR-018 dodatek D — PKCE end-to-end na SPA login cestě (F1+F2+F3) | ✅ done (qa=pass) | | 2026-07-11 06:41 UTC | s60-auth | prod |77b0d12| fix(auth): CR-018 dodatek D — PKCE end-to-end na SPA login cestě (F1+F2+F3) | ✅ done (qa=skipped) | | 2026-07-11 ~06:4x UTC | s60-auth | hub+prod |77b0d12| CR-018 security (venom clientSecret leak T-20260709-072) + CR-017 (rolesByClient — role dle client_id, zpětně kompat.). Delta od LIVE0f1f0ee= 7 commitů, db_change none, 0 migrací (cross-check OK). Čistýdeploy.sh --build— oba containery (s60-auth-backend + s60-auth-frontend) build na cíli, žádný ruční ship. ⚠️ Deploy NIC neflipuje — venom klient zůstává confidential; PKCE S256 +POST /systems/:id/convert-to-public(superadmin, atomicky auth_method='none'+secret=NULL) jsou připravené, flip = pozdější admin akce po venom PKCE. Ověřeno naostro:/api/versioncommit=77b0d12 obě env (hub buildTime 06:37Z, prod 06:39Z — fresh), openid-config 200, oba containery healthy, prod labely 2/2. Hub QA gate 4/4 PASS (RELEASE tier); prod-gate stamp name-mismatch fix funguje (auth-qa-pass@ 77b0d12 zapsán lokálně na sentinel,auth-hub-okfresh). Repo hygiena flagnuta auth (T-046): DEPLOY.md hlavička stale (Current: 2360458ne 77b0d12 → migration_from vzat z archivní sekce09ecbea, db_change=none neškodí) + origin/main =bfd2c60„Initial commit" (master vypadá reinicializovaný → pinoval jsem 77b0d12 explicitně). | ✅ | sentinel | | 2026-07-11 07:03 UTC | billit | hub |74d273f| fix(billit): voucher kód case-insensitive + FE filtry a vymazání platnosti [no-spec bugfix, Liborův pokyn] | ✅ done (qa=pass) | | 2026-07-11 07:06 UTC | billit | prod |74d273f| fix(billit): voucher kód case-insensitive + FE filtry a vymazání platnosti [no-spec bugfix, Liborův pokyn] | ✅ done (qa=skipped) | | 2026-07-11 ~07:0x UTC | billit | hub+prod |74d273f| 3 no-spec bugfixy (delta od LIVE7668bc2, db_change none, 0 migrací → bez dress rehearsal): (1) hotfix/health/deep— redis check neposílal heslo → NOAUTH na sdíleném s60-redis (falešnýredis: fail+ 503 degraded na prod) → fixQUEUE_REDIS_PASSWORD ?? REDIS_PASSWORD; s60auth check volal neexistující/api/auth/health(404) → opraveno na/api/health; (2) Stripe per-tenant bez platform klíče —handleWebhookověřuje podpis dummy-key instancí (čisté HMAC),getPaymentStatusbere per-tenant apiKey; (3) voucher case-insensitive (exact→LOWER fallback, ci dup-check 409) + FE filtry/vymazání platnosti + FE bulk toast fix (zelený jen při 0 chybách) + Debug (CR-022) přesunut z tenant Settings na/admin/debug. Čistýdeploy.sh --build(billit-api + billit-web na cíli), žádný docker race (na rozdíl od 7668bc2). Ověřeno naostro: prod VERIFIED (source hash7a975ca…match), labely 2/2, oba containery healthy, billit.cz 301→ucto.studio60.cz,ucto.studio60.cz/health200; /health/deep potvrdil hotfix: redis=ok 2ms + s60auth=ok 14ms (dřív oba fail). Hub QA gate 10/10 PASS. POST-DEPLOY (DEPLOY.md) HOTOVO: deep health byl „degraded" jen kvůli placeholderuSTRIPE_SECRET_KEY=sk_live_***lder→ smazán z.env.{prod,hub}(WRITE OK secrets billit; backup.bak-20260711-091314-stripe-cleanup; reálnýSTRIPE_WEBHOOK_SECRETprod zachován — 38 znaků, bez placeholder markerů) + env-refresh--skip-buildredeploy hub+prod → prod/health/deep=ok(stripeskip), hubok, 4/4 containery healthy. billit DEPLOY.md hygiena flagnuta (T-050):db_changev markdown bold (**none**) → deploy.sh parser nepřečetl čistě → migration cross-check přeskočen (0 migrací ověřeno ručně dopředu);/health/deepcommit=„dev" (GIT_COMMIT se nepropisuje). | ✅ | sentinel | | 2026-07-11 07:17 UTC | billit | hub |74d273f| fix(billit): voucher kód case-insensitive + FE filtry a vymazání platnosti [no-spec bugfix, Liborův pokyn] | ✅ done (qa=pass) | | 2026-07-11 07:19 UTC | billit | prod |74d273f| fix(billit): voucher kód case-insensitive + FE filtry a vymazání platnosti [no-spec bugfix, Liborův pokyn] | ✅ done (qa=skipped) | | 2026-07-11 07:41 UTC | badwolf | hub |10b3ca6| docs: CR-008 implemented — DEPLOY.md ac19094 + implementation log | ✅ done (qa=pass) | | 2026-07-11 07:48 UTC | badwolf | prod |10b3ca6| docs: CR-008 implemented — DEPLOY.md ac19094 + implementation log | ✅ done (qa=skipped) | | 2026-07-11 ~07:4x UTC | badwolf | hub+prod |10b3ca6| CR-008 — self-contained Docker build (konec ručního shipu u badwolfa!). Reakce na dnešní TODO T-20260711-019.ac19094přidal composebuild:sekci (context., dockerfile Dockerfile) + auth-sdk vendored dovendor/s60-auth-sdk/→ deploy.shdocker compose up -d --buildreálně buildí na cíli (dřív bez build sekce = tichý no-op recyklace image, incident 29.6.–6.7.). Nasazen10b3ca6= ac19094 + docs-only fix stale DEPLOY.md (Current: ac19094, db_change: none) → čistý parse, cross-check OK, 0 migrací. Poprvé badwolf přesdeploy.sh --buildBEZ --skip-build a BEZ ručníhodocker save|ssh docker load. CR-008 potvrzeno naostro (image freshness, ne labely): hub image00fb5cd1df66+ prod11a913d7c83doba „created About a minute ago" = čerstvý build na cíli (ne recyklace de21990479ed…). /api/health 200 obě env, REQ-014 route 401 (kód intact), MOODLE_PUSH_ENABLED=true + WEBHOOKS_FAIL_CLOSED + ANTHROPIC zachovány, prod labely 1/1, hub QA gate 4/4 PASS. Provozní: 1. pokus abortoval na git pullu kvůli stray necommitnutémupackage-lock.jsonv sentinel checkoutu → stashnuto (git stash, není moje); abort ale spotřeboval hub token (guard konzumuje při startu) → potřeba re-issue. Systémový build-fix hotový pro badwolf i venom → ruční-ship workaround ([[feedback_deploy_build_command_dead]]) je minulostí. | ✅ | sentinel | | 2026-07-11 08:19 UTC | billit | hub |4b01c3f| fix(billit): po platbě redirect na daňový doklad + Refundovat/Zrušit přes kanonický cancel flow [no-spec bugfix, Liborův pokyn] | ✅ done (qa=pass) | | 2026-07-11 08:21 UTC | billit | prod |4b01c3f| fix(billit): po platbě redirect na daňový doklad + Refundovat/Zrušit přes kanonický cancel flow [no-spec bugfix, Liborův pokyn] | ✅ done (qa=skipped) | | 2026-07-11 ~08:2x UTC | billit | hub+prod |4b01c3f| 2. billit dnes (supersedes 74d273f — billit pushnul dál po prvním deployi; T-064). Delta 74d273f..4b01c3f = 3 commity: voucher release při smazání/storno objednávky (obě cesty —used_count+ per-personvoucher_redemptionsse vrací; Libor narazil na „voucher navždy použit" u per-person=1) + kritický refund/cancel přes kanonický cancel flow + redirect na daňový doklad po platbě + ProductType+music(odblokoval wp Learnia hudba resync T-056). db_change MINOR — 1 DATOVÁ migrace1773060000000-RepairOrphanVoucherRedemptions(žádné schema změny, idempotentní: smaže sirotčí voucher_redemptions + vrátí used_count). Aplikováno přes deploy.sh [6.5] typeormmigration:run(deploy.yml migration_container=billit-billit-api-1) — „executed successfully" na hub i prod DB (Libor: bez ověření sirotků). Čistýdeploy.sh --build. Ověřeno: prod VERIFIED (source hash match), labely 2/2, oba containery 200, prod/health/deep=ok(stripe skip — cleanup z 1. deploye přetrval, redis/db ok). Hub QA gate PASS. (Pozn.: billit DEPLOY.md pořáddb_changev markdown bold → deploy.sh parser messy, non-blocking — opakovaný flag.) | ✅ | sentinel | | 2026-07-11 10:10 UTC | billit | hub |6af469b| fix(billit): import IČO guard + adresné duplicity + ISE wipe SQL [no-spec bugfix, Liborův pokyn] | ✅ done (qa=pass) | | 2026-07-11 10:12 UTC | billit | prod |6af469b| fix(billit): import IČO guard + adresné duplicity + ISE wipe SQL [no-spec bugfix, Liborův pokyn] | ✅ done (qa=skipped) | | 2026-07-11 ~12:1x UTC | billit | hub+prod + PROD DB ops |6af469b| 3. billit dnes (supersedes 4b01c3f; T-079). Reálná delta nad LIVE 4b01c3f = 1 commit: import IČO guard (Fakturoid XML z cizího účtu → 400 před zápisem, dodavatelská IČO vs IČO tenanta) + skippedDuplicities v Import UI. db_change none nad 4b01c3f (migrace1773060000000už proběhla, typeorm re-run no-op). Čistýdeploy.sh --build, prod VERIFIED (source hash match), labely 2/2, health 200, deepok. 🔴 NÁVAZNÁ PROD DB OPS — ISE invoice wipe (scripts/2026-07-11-ise-invoice-wipe.sql, přímýWIPE OK iseod Libora — relay od billitu NEstačil): březnový import 2026-03-27 kontaminoval tenant inner-sense (8b12f477…) XML z cizího Fakturoid účtu. pg_dump PŘED (/var/lib/postgresql/billit-prod-pre-ise-wipe-20260711-121258.sql.gz, 4.97 MB). Skript BEGIN/COMMIT, tenant-scoped, idempotentní:DELETE 6628inner-sense faktur (CASCADE invoice_lines/payments/refunds/order_invoices/reminder_log; UPDATE 0×3 bank_transactions+order_vendor_splits = žádné napojení, čistá test data). Post-wipe ověřeno naostro: inner-sense 6628→0, TOTAL 19615→12987 (−6628 přesně), matched bank_tx inner-sense=0, ostatních 8 tenantů (7306/1777/1149/1036/652/587/355/125) BEZE ZMĚNY (studio-60/Pulse netknuti), app health 200 + deepok. Hub NEwipnut (billit: stačí prod). ▶️ Krok 3 (Libor reimport čistých XML přes UI, guard live) + krok 4 (billit parity re-check) navazují. | ✅ | sentinel | | 2026-07-11 10:21 UTC | venom | hub |5432215| fix(applications): zachovat courseDate/client embed po PATCH — konec crashe při změně stavu | ✅ done (qa=pass) | | 2026-07-11 10:22 UTC | venom | prod |5432215| fix(applications): zachovat courseDate/client embed po PATCH — konec crashe při změně stavu | ✅ done (qa=skipped) | | 2026-07-11 ~10:2x UTC | venom | hub+prod |5432215| PROD crash fix (2. venom dnes). Delta od LIVE ff16371 = 2 commity:5432215— zachovat courseDate/client embed po PATCH → konec crashe při změně stavu přihlášky (prod crash) +904a004(napojení 2 největších mocků na BW API: app-komunikace + delete→storno). db_change none (FE, 0 migrací). Čistýdeploy.sh --build(self-contained). Ověřeno served bundlem naostro: hubindex-Dxcd9kye.js→ api.s60hub.cz ×2/studio60 ×0; prodindex-j5v4om5W.js→ api.studio60.cz ×2/s60hub ×0 (per-env, žádná záměna). Prod VERIFIED (source hash match), oba /health 200, hub QA gate PASS. Flag venom (T-084): DEPLOY.md stale hlavička (Current: 628387d, opakovaně). | ✅ | sentinel | | 2026-07-11 10:38 UTC | billit | hub |3c4047c| fix(billit): import — per-kontakt izolace chyb + IČO guard na přepis + ISE full wipe v2 [no-spec bugfix] | ✅ done (qa=pass) | | 2026-07-11 10:40 UTC | billit | prod |3c4047c| fix(billit): import — per-kontakt izolace chyb + IČO guard na přepis + ISE full wipe v2 [no-spec bugfix] | ✅ done (qa=skipped) | | 2026-07-11 ~12:4x UTC | billit | hub+prod + PROD DB ops (wipe v2) |3c4047c→1ed5ae3| 4. billit dnes (T-085). Reálná delta nad LIVE 6af469b = 1 commit (3c4047c, billit-api only): import hardening kontaktů — per-kontakt izolace chyb (1 kolize neshodí celý soubor) + IČO se nepřepíše, když ho drží jiný kontakt. db_change none, 0 migrací. Čistýdeploy.sh --build, prod VERIFIED (source hash match), health 200. 🔴 NÁVAZNÁ PROD DB OPS — ISE full wipe v2 (WIPE OK ise v2přímo od Libora): re-import po v1 wipe spadl, protože březnová kontaminace žila i v KONTAKTECH (subjects, v1 mazal jen faktury) → kolize UQ_subjects. BUG-INCIDENT: 1. pokus wipe v2 spadl nanotifications.entity_id IN (SELECT id::text FROM orders)→operator does not exist: uuid = text(entity_id je uuid) → transakce ROLLBACKnuta v BEGIN, 0 škoda (invoices/subjects nezměněny, žádný lock, ověřeno). Sentinel nahlásil billitu přesný diff (ověřen proti prod information_schema) → billit push1ed5ae3(odstraněn::text, bank_accounts verifikace srovnána 5→4; jen SQL, žádný app kód → 3c4047c zůstává release). Re-run z 1ed5ae3 PROŠEL: DELETE 5903 invoices + DELETE 2537 subjects (kontakty) + 0 orders/notifications, UPDATE 0 na FK. Fresh pg_dump PŘED (billit-prod-pre-ise-wipe-v2fix-20260711-124858.sql.gz, 4.73 MB; předtím i pre-fix dump). Post-wipe ověřeno: inner-sense invoices/subjects/orders = 0, bank_accounts = 4 ZACHOVÁNO (Fio tokeny), TOTAL invoices 18890→12987, ostatních 8 tenantů beze změny, app health 200. ▶️ Krok 3 (Libor reimport 8 ročníků XML přes UI) + krok 4 (billit parity). | ✅ | sentinel | | 2026-07-11 12:17 UTC | venom | hub |9785be1| fix(auth): handlovat OAuth callback i na /callback — konec login loopu na prod | ✅ done (qa=pass) | | 2026-07-11 12:18 UTC | venom | prod |9785be1| fix(auth): handlovat OAuth callback i na /callback — konec login loopu na prod | ✅ done (qa=skipped) | | 2026-07-11 ~12:1x UTC | venom | hub+prod |9785be1| PRIORITNÍ PROD login loop fix (3. venom dnes). 1 commit nad LIVE 5432215: route OAuth callback i na/callback(nejen/auth/callback) → AuthCallback. Loop vznikal, protože venom posíláredirect_uri=…/callback(baked z secretsVITE_CALLBACK_URL), ale handler znal jen/auth/callback→ code se nezpracoval → nekonečný redirect login↔callback. db_change none, 0 migrací, čistě FE, self-containeddeploy.sh --build. Ověřeno: prod VERIFIED (source hash match), served bundle hubindex-C11_BrVOapi.s60hub.cz / prodindex-5_67Ii4bapi.studio60.cz (per-env), /callback serves SPA 200 obě env, /health 200. Config-note (venom): build argVITE_CALLBACK_URL(secrets=/callback) ≠ committed repo.env.prod(/auth/callback) — fix zvládá obě cesty, nechán secrets/callback(auth to akceptuje); sjednocení = kosmetika/follow-up (příp. koordinace s auth redirect_uri). Reálný test = Libor login na prod. | ✅ | sentinel | | 2026-07-11 16:19 UTC | billit | hub |50cba9c| feat(billit): order.completed webhook (WP/WC parita) + PDF názvy slug-číslo [Liborův pokyn, wp T-20260711-106] | ✅ done (qa=pass) | | 2026-07-11 16:21 UTC | billit | prod |50cba9c| feat(billit): order.completed webhook (WP/WC parita) + PDF názvy slug-číslo [Liborův pokyn, wp T-20260711-106] | ✅ done (qa=skipped) | | 2026-07-11 ~16:2x UTC | billit | hub+prod + PROD DB ops (fibonacci wipe) |50cba9c| 5. billit dnes (T-126). Kód delta nad LIVE 3c4047c = 1 commit50cba9c(346ff4a/1ed5ae3 = SQL skripty): order.completed webhook (WC digitální objednávky visely na 'processing' → při COMPLETED emit navíc order.completed, kanonický snapshot+semantic:'completed', obě cesty; order.paid beze změny; wp T-106) + jednotné PDF názvy<slug>-<číslo>.pdf(download/e-mail/ZIP). db_change none, 0 migrací, billit-api only. Čistýdeploy.sh --build, prod VERIFIED (source hash match), health 200, deepok. 🔴 NÁVAZNÁ PROD DB OPS — fibonacci-production full wipe (WIPE OK fibonaccipřímo od Libora): stejný vzor jako ISE, s opraveným::text(poučení z T-087 zapracováno → bez bugu napoprvé). pg_dump PŘED (billit-prod-pre-fibonacci-wipe-20260711-182204.sql.gz, 4.85 MB). Tenant73df2ee8:DELETE 587invoices +DELETE 509subjects, orders/notifications/voucher_redemptions 0. Post-wipe ověřeno: fibonacci invoices/subjects = 0, bank_accounts = 2 ZACHOVÁNO (EUR 2701871350 Fio token), TOTAL invoices 19580→18993, ostatní tenanti netknuti (8 s fakturami), app health 200. ▶️ Libor reimport fibonacci XML přes UI (IČO guard 09536264) + UI akce (webhook d12d1280 order.completed, forge→learnia URL) + billit parity. | ✅ | sentinel | | 2026-07-11 18:59 UTC | s60-auth | hub |e519cdf| chore: DEPLOY.md — REQ-048 (98a4d9b, db_change: none, aktivační kroky pro prod) | ✅ done (qa=pass) | | 2026-07-11 19:03 UTC | s60-auth | prod |e519cdf| chore: DEPLOY.md — REQ-048 (98a4d9b, db_change: none, aktivační kroky pro prod) | ✅ done (qa=skipped) | | 2026-07-11 19:09 UTC | s60-auth | prod |e519cdf| chore: DEPLOY.md — REQ-048 (98a4d9b, db_change: none, aktivační kroky pro prod) | ✅ done (qa=skipped) | | 2026-07-11 20:07 UTC | badwolf | hub |56fbfba| docs(deploy): REQ-018 — Current 4565b76, db_change none + post-deploy batch kroky | ✅ done (qa=pass) | | 2026-07-11 20:09 UTC | badwolf | prod |56fbfba| docs(deploy): REQ-018 — Current 4565b76, db_change none + post-deploy batch kroky | ✅ done (qa=skipped) | | 2026-07-11 20:32 UTC | badwolf | hub |57a6d0a| docs(deploy): Current bd067f5 (autolink fix) — db_change none | ✅ done (qa=pass) | | 2026-07-11 20:34 UTC | badwolf | prod |57a6d0a| docs(deploy): Current bd067f5 (autolink fix) — db_change none | ✅ done (qa=skipped) | | 2026-07-11 21:10 UTC | s60-auth | hub |b1fcd2c| chore: DEPLOY.md — Current 48e60de (FE login toast fix, db_change: none) | ✅ done (qa=pass) | | 2026-07-11 21:12 UTC | s60-auth | prod |b1fcd2c| chore: DEPLOY.md — Current 48e60de (FE login toast fix, db_change: none) | ✅ done (qa=skipped) | | 2026-07-11 21:28 UTC | billit | hub |087ea51| fix(billit): z paid proformy VŽDY faktura — žádné DDP [Liborovo definitivní rozhodnutí] | ✅ done (qa=pass) | | 2026-07-11 21:30 UTC | billit | prod |087ea51| fix(billit): z paid proformy VŽDY faktura — žádné DDP [Liborovo definitivní rozhodnutí] | ✅ done (qa=skipped) | | 2026-07-12 06:30 UTC | billit | hub |abd4531| spec(billit): CR-061 fáze 1+2 hotové (E2E ověřeno), fáze 3 zbývá | ✅ done (qa=pass) | | 2026-07-12 06:43 UTC | billit | prod |abd4531| spec(billit): CR-061 fáze 1+2 hotové (E2E ověřeno), fáze 3 zbývá | ✅ done (qa=skipped) | | 2026-07-12 08:12 UTC | badwolf | hub |ed219fd| feat(billit): DEC-005 Fáze 1 — BW producer fulfillment events do BullMQ fronty badwolf-to-billit | ✅ done (qa=pass) | | 2026-07-12 08:14 UTC | badwolf | prod |ed219fd| feat(billit): DEC-005 Fáze 1 — BW producer fulfillment events do BullMQ fronty badwolf-to-billit | ✅ done (qa=skipped) | | 2026-07-12 08:18 UTC | badwolf | hub |fc8a27d| feat(billit): DEC-005 — manuální oprava fulfillmentu s evidencí (list + resolve → flip) | ✅ done (qa=pass) | | 2026-07-12 08:20 UTC | badwolf | prod |fc8a27d| feat(billit): DEC-005 — manuální oprava fulfillmentu s evidencí (list + resolve → flip) | ✅ done (qa=skipped) | | 2026-07-12 08:44 UTC | billit | hub |92cd66c| feat(billit): CR-063 — fulfillment consumer (pilot fronty badwolf-to-billit) + badge zaplaceno/nedoručeno | ✅ done (qa=pass) | | 2026-07-12 08:46 UTC | billit | prod |92cd66c| feat(billit): CR-063 — fulfillment consumer (pilot fronty badwolf-to-billit) + badge zaplaceno/nedoručeno | ✅ done (qa=skipped) | | 2026-07-12 08:50 UTC | badwolf | hub |292798e| fix(fulfillment): JwtOrApiKeyGuard místo ApiKeyGuard na /internal/fulfillment/ (Venom = browser SPA) | ✅ done (qa=pass) | | 2026-07-12 08:54 UTC | badwolf | prod |292798e| fix(fulfillment): JwtOrApiKeyGuard místo ApiKeyGuard na /internal/fulfillment/ (Venom = browser SPA) | ✅ done (qa=skipped) | | 2026-07-12 08:58 UTC | venom | hub |7f1a791| feat(fulfillment): REQ-018 — pohled Nepřidělené kurzy + ruční vyřešení | ✅ done (qa=pass) | | 2026-07-12 09:00 UTC | venom | prod |7f1a791| feat(fulfillment): REQ-018 — pohled Nepřidělené kurzy + ruční vyřešení | ✅ done (qa=skipped) | | 2026-07-12 09:16 UTC | badwolf | prod |292798e| fix(fulfillment): JwtOrApiKeyGuard místo ApiKeyGuard na /internal/fulfillment/ (Venom = browser SPA) | ✅ done (qa=skipped) | | 2026-07-12 10:05 UTC | venom | hub |d0f19bd| feat(clients+fulfillment): hledání kurzů při přiřazení + čitelný důvod selhání | ✅ done (qa=pass) | | 2026-07-12 10:07 UTC | venom | prod |d0f19bd| feat(clients+fulfillment): hledání kurzů při přiřazení + čitelný důvod selhání | ✅ done (qa=skipped) | | 2026-07-12 10:19 UTC | billit | hub |45b3d74| feat(billit): CR-064 — přehled expedice/plnění (per-řádek stav + order souhrn + filtr „Čeká na expedici") | ✅ done (qa=pass) | | 2026-07-12 10:21 UTC | billit | prod |45b3d74| feat(billit): CR-064 — přehled expedice/plnění (per-řádek stav + order souhrn + filtr „Čeká na expedici") | ✅ done (qa=skipped) | | 2026-07-12 11:13 UTC | billit | hub |b38ea76| feat(billit): CR-065 — expedice fyzického produktu (UI zásilka + mail o odeslání) + fix hlášky mazání | ✅ done (qa=pass) | | 2026-07-12 11:24 UTC | billit | prod |b38ea76| feat(billit): CR-065 — expedice fyzického produktu (UI zásilka + mail o odeslání) + fix hlášky mazání | ✅ done (qa=skipped) | | 2026-07-12 11:37 UTC | billit | hub |dc1c81d| fix(billit): CR-065 — „Expedovat" jako samostatné tlačítko vázané na fyzické položky (ne stav objednávky) | ✅ done (qa=pass) | | 2026-07-12 11:40 UTC | billit | prod |dc1c81d| fix(billit): CR-065 — „Expedovat" jako samostatné tlačítko vázané na fyzické položky (ne stav objednávky) | ✅ done (qa=skipped) | | 2026-07-12 11:45 UTC | badwolf | hub |d5a6ad3| fix(email): REQ-015 — magic-link pryč z copy (Libor); přihlášení řeší auth login page | ✅ done (qa=pass) | | 2026-07-12 11:47 UTC | badwolf | prod |d5a6ad3| fix(email): REQ-015 — magic-link pryč z copy (Libor); přihlášení řeší auth login page | ✅ done (qa=skipped) | | 2026-07-12 11:58 UTC | venom | hub |8316d68| feat: dotáhnout balík po BW deploy — Dashboard, header počty, editor šablon, orders multi-select | ✅ done (qa=pass) | | 2026-07-12 12:00 UTC | venom | prod |8316d68| feat: dotáhnout balík po BW deploy — Dashboard, header počty, editor šablon, orders multi-select | ✅ done (qa=skipped) | | 2026-07-12 12:59 UTC | venom | hub |2965a23| feat(dashboard+email-templates): widget proklik/max-width + editor highlighting/formát | ✅ done (qa=pass) | | 2026-07-12 13:01 UTC | venom | prod |2965a23| feat(dashboard+email-templates): widget proklik/max-width + editor highlighting/formát | ✅ done (qa=skipped) | | 2026-07-13 04:11 UTC | venom | hub |b4f006f| feat(dashboard): kompaktní flexibilní widget — w-fit, ikony místo nadpisů, kurz=kód | ✅ done (qa=pass) | | 2026-07-13 04:15 UTC | venom | prod |b4f006f| feat(dashboard): kompaktní flexibilní widget — w-fit, ikony místo nadpisů, kurz=kód | ✅ done (qa=skipped) | | 2026-07-13 04:51 UTC | venom | hub |f7a33df| feat(dashboard): barevná mapa řádků dle počtu potvrzených (per kurz, okno 0d–6M) | ✅ done (qa=pass) | | 2026-07-13 04:55 UTC | venom | prod |f7a33df| feat(dashboard): barevná mapa řádků dle počtu potvrzených (per kurz, okno 0d–6M) | ✅ done (qa=skipped) | | 2026-07-13 05:00 UTC | badwolf | hub |ae51969| feat(settings): REQ-022 internal settings store + fix(052): communications.created_by UUID→VARCHAR | ✅ done (qa=pass) | | 2026-07-13 05:04 UTC | badwolf | prod |ae51969| feat(settings): REQ-022 internal settings store + fix(052): communications.created_by UUID→VARCHAR | ✅ done (qa=skipped) | | 2026-07-13 05:24 UTC | venom | hub |1eb510e| feat(dashboard): barevná mapa v2 — dvě okna (0-3M pozadí, 3-6M text) + settings-driven | ✅ done (qa=pass) | | 2026-07-13 05:30 UTC | venom | prod |1eb510e| feat(dashboard): barevná mapa v2 — dvě okna (0-3M pozadí, 3-6M text) + settings-driven | ✅ done (qa=skipped) | | 2026-07-13 05:42 UTC | venom | hub |66ea9b4| fix(comms+console): mazání komunikace v timeline + úklid konzolových errorů | ✅ done (qa=pass) | | 2026-07-13 05:43 UTC | venom | prod |66ea9b4| fix(comms+console): mazání komunikace v timeline + úklid konzolových errorů | ✅ done (qa=skipped) | | 2026-07-13 20:13 UTC | venom | hub |1e37120| feat(clients): REQ-022 — email komunikace v timeline klienta (Cortex→BW→Venom, v1 read) | ✅ done (qa=pass) | | 2026-07-13 20:15 UTC | venom | prod |1e37120| feat(clients): REQ-022 — email komunikace v timeline klienta (Cortex→BW→Venom, v1 read) | ✅ done (qa=skipped) | | 2026-07-13 20:19 UTC | badwolf | hub |5027a87| docs(deploy): Current aa48acf — REQ-023 v1 email ingest (migrace 054, REDIS_BUS_URL po deployi) | ✅ done (qa=pass) | | 2026-07-13 20:21 UTC | badwolf | prod |5027a87| docs(deploy): Current aa48acf — REQ-023 v1 email ingest (migrace 054, REDIS_BUS_URL po deployi) | ✅ done (qa=skipped) | | 2026-07-14 03:45 UTC | badwolf | hub |5027a87| docs(deploy): Current aa48acf — REQ-023 v1 email ingest (migrace 054, REDIS_BUS_URL po deployi) | ✅ done (qa=pass) | | 2026-07-14 03:57 UTC | badwolf | prod |5027a87| docs(deploy): Current aa48acf — REQ-023 v1 email ingest (migrace 054, REDIS_BUS_URL po deployi) | ✅ done (qa=skipped) | | 2026-07-14 04:40 UTC | badwolf | hub |721a788| docs(deploy): Current a8e71b6 — RFC adresa fix, po deployi cs replay | ✅ done (qa=pass) | | 2026-07-14 04:43 UTC | badwolf | prod |721a788| docs(deploy): Current a8e71b6 — RFC adresa fix, po deployi cs replay | ✅ done (qa=skipped) | | 2026-07-14 05:07 UTC | badwolf | hub |de28964| docs(deploy): Current e5a48e9 — REQ-024 application_number (migrace 055) | ✅ done (qa=pass) | | 2026-07-14 05:10 UTC | badwolf | prod |de28964| docs(deploy): Current e5a48e9 — REQ-024 application_number (migrace 055) | ✅ done (qa=skipped) | | 2026-07-14 05:13 UTC | venom | hub |8239135| feat(applications): REQ-024 — lidská čísla přihlášek (#8142 místo #uuid) + sloupec v seznamu | ✅ done (qa=pass) | | 2026-07-14 05:17 UTC | venom | prod |8239135| feat(applications): REQ-024 — lidská čísla přihlášek (#8142 místo #uuid) + sloupec v seznamu | ✅ done (qa=skipped) | | 2026-07-14 07:39 UTC | badwolf | hub |c07d85c| docs(deploy): Current 2cf7dec — +migrace 058 + CI test fix (NON_HASH výjimka) | ✅ done (qa=pass) | | 2026-07-14 07:49 UTC | badwolf | prod |c07d85c| docs(deploy): Current 2cf7dec — +migrace 058 + CI test fix (NON_HASH výjimka) | ✅ done (qa=skipped) | | 2026-07-14 13:18 UTC | venom | hub |0eb0a7e| feat(clients): REQ-021 B — checkbox „poslat e-mail s přístupy" u ručního přidělení kurzů | ✅ done (qa=pass) | | 2026-07-16 03:49 UTC | venom | hub |0eb0a7e| feat(clients): REQ-021 B — checkbox „poslat e-mail s přístupy" u ručního přidělení kurzů | ✅ done (qa=pass) | | 2026-07-16 03:52 UTC | venom | prod |0eb0a7e| feat(clients): REQ-021 B — checkbox „poslat e-mail s přístupy" u ručního přidělení kurzů | ✅ done (qa=skipped) | | 2026-07-16 09:11 UTC | badwolf | hub |b42b1fa| docs(deploy): Current cc4a98a (search fix) + flag deploy drift (prod app c07d85c vs DB 058, 059 pending) | ✅ done (qa=pass) | | 2026-07-16 09:18 UTC | badwolf | prod |b42b1fa| docs(deploy): Current cc4a98a (search fix) + flag deploy drift (prod app c07d85c vs DB 058, 059 pending) | ✅ done (qa=skipped) | | 2026-07-18 05:17 UTC | s60-pulse | hub |c6ddc13| chore(pulse): DEPLOY.md — RELEASE 0829163 (audit+CR-211+bugfixy+CR-212+REQ-049) | ✅ done (qa=skip) | | 2026-07-18 05:12 UTC | s60-pulse | hub |c6ddc13| RELEASE bundle 0b81dac→c6ddc13 (audit 18 fixů + CR-211 digest + CR-212 F1 shadow JWT + REQ-049 recenze; migrace 155–157 při bootu, verify DB OK) — dress rehearsal: hub DB = prod-mirror (parita 1:1, rollback dump na pg-alfa), telegram na hubu OFF; QA RELEASE 15/15 PASS po hub UFW fixu (172.17+172.18/16 → 443, JWKS hairpin na auth.s60hub.cz dropoval → +10s latence každého authed requestu); čeká Liborova kontrola hubu → prod | ✅ done (qa=pass) | | 2026-07-18 05:56 UTC | s60-pulse | prod |c6ddc13| chore(pulse): DEPLOY.md — RELEASE 0829163 (audit+CR-211+bugfixy+CR-212+REQ-049) | ✅ done (qa=skipped) | | 2026-07-18 05:58 UTC | s60-pulse | prod |c6ddc13| RELEASE bundle 0b81dac→c6ddc13 na prod po dress rehearsal (hub QA 15/15 + Libor check) — migrace 155–157 při bootu ✅ (154 rows, uq_clients_tenant_authuser, review tabulky), duplicitní pre-check 0 řádků (05:53), commit VERIFIED source+build hash, health+/app/review+/admin/reviews 200, telegram prod enabled (správně), JWKS shadow 0 warnings (prod hairpin OK); fx_rate NENASTAVEN → fallback 23 (čeká kurz od Libora); video upload degradovaný do Storage Box mount + compose bind (pulse T-20260718-030, infra T-20260718-031) | ✅ done (qa=hub-gate) | | 2026-07-18 06:12 UTC | billit | hub |a017411| fix(billit): splatnost faktury se při každé editaci prodlužovala od aktuálního data | ⚠️ fail (qa=skipped) | | 2026-07-18 06:27 UTC | billit | hub |a017411| fix(billit): splatnost faktury se při každé editaci prodlužovala od aktuálního data | ✅ done (qa=pass) | | 2026-07-18 06:32 UTC | billit | prod |a017411| fix(billit): splatnost faktury se při každé editaci prodlužovala od aktuálního data | ⚠️ fail (qa=skipped) | | 2026-07-18 06:38 UTC | billit | prod |a017411| fix(billit): splatnost faktury se při každé editaci prodlužovala od aktuálního data | ✅ done (qa=skipped) | | 2026-07-18 06:27 UTC | billit | hub |a017411| FE bugfix splatnosti faktury (dueOn se při editaci přepisovala na dnešek+dueDays; auto-doplnění nově jen new/duplicate) — REÁLNÁ delta jen dc1c81d→a017411 (billitova zpráva T-20260718-004 tvrdila baseline abd4531 = STALE, 92cd66c..dc1c81d + migrace CR-063 nasazeny už 07-12); selective-recreate label false-positive na api (1/2) → re-run --skip-build (prázdný diff → full force-recreate) = clean; QA 10/10 PASS | ✅ done (qa=pass) | | 2026-07-18 06:38 UTC | billit | prod |a017411| totéž na prod (ucto.studio60.cz) — bundle BxeIyMBH→CdhFvnIw ověřen, stejný label false-positive → re-run --skip-build clean, labels 2/2, health 200 | ✅ done (qa=hub-gate) | | 2026-07-18 06:48 UTC | s60-pulse | hub |103b47f| feat(pulse): REQ-049 — seznam recenzí: serverové stránkování + hledání + filtr typu | ✅ done (qa=pass) | | 2026-07-18 06:48 UTC | s60-pulse | hub |103b47f| REQ-049 hub-test iterace (c6ddc13→103b47f, 3 commity): returnTo deep-link fix + admin invite našeptávač + UX feedback (59af6b9), záložky schválené/zamítnuté + download video + karta Recenze u klienta (bf5f241), server paging/hledání/filtr seznamu recenzí (103b47f); db_change NONE, QA 15/15; prod zůstává c6ddc13 (iterace pokračuje na hubu) | ✅ done (qa=pass) | | 2026-07-18 07:31 UTC | billit | hub |62a572a| fix(billit): vendor settlement přehled ukazoval dluh i po vyúčtování | ✅ done (qa=pass) | | 2026-07-18 07:33 UTC | billit | prod |62a572a| fix(billit): vendor settlement přehled ukazoval dluh i po vyúčtování | ✅ done (qa=skipped) | | 2026-07-18 07:31 UTC | billit | hub |62a572a| Vendor settlement dluh fix (BE+FE — /settlements ukazoval dluh i po vyúčtování; nově Σ net − Σ payout, data netřeba měnit) — delta jen a017411→62a572a; BE+FE recreate → labels 2/2 na PRVNÍ běh (žádný label lag), QA 10/10 PASS | ✅ done (qa=pass) | | 2026-07-18 07:33 UTC | billit | prod |62a572a| totéž na prod — labels 2/2 první běh, bundle CdhFvnIw→Zv-4fx_3 ověřen, health 200 | ✅ done (qa=hub-gate) | | 2026-07-18 07:50 UTC | s60-pulse | hub |5babaa8| fix(pulse): MCP feedback/errors tools + feedback tlačítko do headeru | ✅ done (qa=pass) | | 2026-07-18 08:01 UTC | s60-pulse | prod |5babaa8| fix(pulse): MCP feedback/errors tools + feedback tlačítko do headeru | ✅ done (qa=skipped) | | 2026-07-18 07:50 UTC | s60-pulse | hub |5babaa8| MCP feedback_list/errors_list crash fix + feedback tlačítko do headeru (delta od hub 103b47f jen 1 commit; pulse zpráva T-056 mylně tvrdila hub=c6ddc13); QA 15/15 | ✅ done (qa=pass) | | 2026-07-18 08:01 UTC | s60-pulse | prod |5babaa8| kumulativně c6ddc13→5babaa8 (4 commity: REQ-049 hub-test iterace 59af6b9+bf5f241+103b47f + MCP/header fix) — bez migrace, VERIFIED, health 200 | ✅ done (qa=hub-gate) | | 2026-07-18 08:48 UTC | s60-pulse | hub |1e77e55| chore(pulse): DEPLOY.md — Current ed44035 (mobilní redesign; prod=5babaa8 delta client-only) | ✅ done (qa=pass) | | 2026-07-18 08:51 UTC | s60-pulse | prod |1e77e55| chore(pulse): DEPLOY.md — Current ed44035 (mobilní redesign; prod=5babaa8 delta client-only) | ✅ done (qa=skipped) | | 2026-07-18 08:48 UTC | s60-pulse | hub |1e77e55| Mobilní redesign (client-only: spodní nav lišta, PWA manifest+ikony/standalone, feedback modal, mobilní chat UX, overflow fixy) — bez migrace/BE/env; QA 15/15 | ✅ done (qa=pass) | | 2026-07-18 08:51 UTC | s60-pulse | prod |1e77e55| totéž na prod — VERIFIED, health 200 | ✅ done (qa=hub-gate) | | 2026-07-18 19:19 UTC | s60-pulse | hub |793ac8e| chore(pulse): DEPLOY.md — Current 5f67d98 (force-complete recovery, prod 1e77e55, db_change NONE) | ✅ done (qa=pass) | | 2026-07-18 19:23 UTC | s60-pulse | prod |793ac8e| chore(pulse): DEPLOY.md — Current 5f67d98 (force-complete recovery, prod 1e77e55, db_change NONE) | ✅ done (qa=skipped) | | 2026-07-18 19:19 UTC | s60-pulse | hub |793ac8e| Admin force-complete recovery pro zaseklé konzultace (POST /api/sessions/:id/force-complete @Roles admin + debug endpoint + admin akce; idempotentní enqueue, kredit netknut) — delta 1 commit 5f67d98, bez migrace/env; QA 15/15 | ✅ done (qa=pass) | | 2026-07-18 19:23 UTC | s60-pulse | prod |793ac8e| totéž na prod — VERIFIED, health 200; use-case: oprava zaseklé session Daniela Karlsson 2d65576a (provede pulse/Libor admin akcí) | ✅ done (qa=hub-gate) | | 2026-07-20 04:33 UTC | billit | hub |d484536| feat(billit): UI dopláček CR-068/CR-069 — fraud UX, přílohy, O11 dialog, filtry, Flexi | ✅ done (qa=pass) | | 2026-07-20 04:43 UTC | billit | prod |d484536| feat(billit): UI dopláček CR-068/CR-069 — fraud UX, přílohy, O11 dialog, filtry, Flexi | ✅ done (qa=skipped) | | 2026-07-20 04:50 UTC | billit | hub+prod |d484536| VERIFIKACE: 8/8 migrací v migrations tab. (hub+prod DB), 4 nové tabulky, FE chunk s Flexi UI servírován (real bundle check), STORAGE_ env nasazeny (klíče rotovány 07-20), prod /health/deep OK. Findings→billit (T-20260720-025): storage check čte jen DO_SPACES_KEY; commit:"dev" (GIT_COMMIT arg). Hub deep degraded = pre-existující MAIL_SERVICE_URL=127.0.0.1 v hub secrets (fix pending, netýká se release). | ✅ verified | | 2026-07-20 04:50 UTC | badwolf | hub |02a005a| feat(tasks): ?worker= filtr + GET /tasks/my-groups (venom gapy, Libor go 2026-07-19) | ✅ done (qa=pass) | | 2026-07-20 05:13 UTC | badwolf | hub |43a5024| fix(sync): DATE sloupce posunuté o −1 den (terms, birthday, vouchers) — dateStrings | ✅ done (qa=pass) | | 2026-07-20 05:23 UTC | billit | hub |d484536| feat(billit): UI dopláček CR-068/CR-069 — fraud UX, přílohy, O11 dialog, filtry, Flexi | ✅ done (qa=pass) | | 2026-07-20 05:25 UTC | billit | hub |d484536| ENV FIX: MAIL_SERVICE_URL 127.0.0.1→s60-mail (pre-existující misconfig, email deep check věčně fail) — secrets + --skip-build re-apply; hub /health/deep nyní zelený (email ok 4ms), QA 10/10. Hub-prod env parity obnovena. | ✅ verified | | 2026-07-20 05:27 UTC | badwolf | prod |43a5024| fix(sync): DATE sloupce posunuté o −1 den (terms, birthday, vouchers) — dateStrings | ✅ done (qa=skipped) | | 2026-07-20 05:40 UTC | badwolf | hub+prod |43a5024| VERIFIKACE task systém v1+v2: migrace 060–070 hub+prod (owner app_user), checklist B od badwolf PASS (health/routy 401/DB/ingest dormant na hubu), prod worker+bus OK, pravidla OFF obě env. FINDING→badwolf (T-20260720-057): S60_DOMAIN chybí na prod → emailIngest.required=false (CR-010 guard tiše off), fix čeká na badwolf potvrzení + tokeny. Krok projekce splatností BLOKOVÁN (JENKINS_LIVE_ creds nejsou na sentinelu, vyžádány). Korektivní upserty ověřím po 06:20 applier běhu (vzorek jenkins_id=363). | ✅ verified + 2 pending | | 2026-07-20 05:35 UTC | badwolf | prod |43a5024| fix(sync): DATE sloupce posunuté o −1 den (terms, birthday, vouchers) — dateStrings | ✅ done (qa=skipped) | | 2026-07-20 05:44 UTC | venom | hub |eec3e0b| feat(tasks): REQ-027 rules admin — okno aplikace + granularita + typy účastníka (BW 02a005a DTO) | ✅ done (qa=pass) | | 2026-07-20 05:56 UTC | venom | prod |eec3e0b| feat(tasks): REQ-027 rules admin — okno aplikace + granularita + typy účastníka (BW 02a005a DTO) | ✅ done (qa=skipped) | | 2026-07-20 05:45 UTC | badwolf | prod |43a5024| ENV FIX: S60_DOMAIN=studio60.cz doplněn (chyběl → CR-010 guard required tiše off) — po fixu required=true a health poctivě degraded (mailboxy stale >24h, poslední ingesty 07-11/06-10/07-19) → posouzení u badwolf (T-20260720-058). | ✅ verified | | 2026-07-20 05:50 UTC | venom | hub+prod |eec3e0b| REQ-027 retrofit na BW kontrakt (worker= fronta, my-groups, rules admin) — FE-only, build-on-target; VERIFIKACE served bundle: hub baked api.s60hub.cz, prod baked api.studio60.cz, my-groups v obou. QA hub PASS. | ✅ verified | | 2026-07-20 07:50 UTC | venom | hub |d6f9e66| fix(tasks): getTasks serializuje pole jako bracket notaci (status[]) — BW @IsArray | ✅ done (qa=pass) | | 2026-07-20 07:56 UTC | venom | prod |d6f9e66| fix(tasks): getTasks serializuje pole jako bracket notaci (status[]) — BW @IsArray | ✅ done (qa=skipped) | | 2026-07-20 08:30 UTC | venom | hub+prod |d6f9e66| HOTFIX: getTasks bracket notace status[]=open (BW @IsArray bez coercion → 400 padaly obrazovky Všechny úkoly/Kanban) — FE-only. VERIFIKACE: fresh bundly (hub Bjct-pEl/api.s60hub.cz, prod BmOKbtcM/api.studio60.cz), bracket literál v obou, badwolf status[]=open→401 ne 400. | ✅ verified | | 2026-07-20 07:58 UTC | badwolf | hub |dc62671| fix(tasks): QueryTasksDto coercion — jednoprvkový ?status/?type string → pole (venom bug) | ✅ done (qa=pass) | | 2026-07-20 08:07 UTC | badwolf | prod |dc62671| fix(tasks): QueryTasksDto coercion — jednoprvkový ?status/?type string → pole (venom bug) | ✅ done (qa=skipped) | | 2026-07-20 08:40 UTC | badwolf | hub+prod |dc62671| fix(tasks): QueryTasksDto coercion (jednoprvkový ?status/?type string → pole) — defenzivní doplněk k venom d6f9e66. Delta 43a5024→dc62671 = 1 commit, žádné migrace/env. Hub QA 4/4 PASS, prod HTTP 200. ⚠️ coercion post-auth chování NEověřeno sentinelem (401 auth stíní DTO) → authed verifikace vyžádána od badwolf (T-20260720-079+). | ✅ deployed, coercion pending authed | | 2026-07-20 08:20 UTC | billit | hub |35c96ff| chore(billit): DEPLOY.md — srovnat hlavičku s plnou F1 delta (7 migrací, MAJOR) | ✅ done (qa=pass) | | 2026-07-20 08:23 UTC | billit | prod |35c96ff| chore(billit): DEPLOY.md — srovnat hlavičku s plnou F1 delta (7 migrací, MAJOR) | ✅ done (qa=skipped) | | 2026-07-20 08:24 UTC | billit | hub+prod |35c96ff| REQ-059 F1: documents/statements/links API + events stream billit-to-cortex (outbox→BullMQ s60-redis) + GET /invoices + Fio KS/SS backfill + F0 hardening. 7 migrací (1773160–1773220), migration_from d484536. VERIFIKACE: 7/7 zapsáno obě env, nové tabulky documents/links/outbox_events, bank_transactions ks/ss/revision+trigger, owner=app user, KS/SS backfill (ss→ks napříč tenanty konzistentní), outbox 0 rows (armed), prod /health/deep OK, FE fresh, QA 10/10. | ✅ verified | | 2026-07-20 09:25 UTC | billit | hub |f69936c| fix(billit): fulltext vydaju (VS+polozky+OCR) + doklad pri zakladani + obrazkove skeny | ✅ done (qa=pass) | | 2026-07-20 09:34 UTC | billit | prod |f69936c| fix(billit): fulltext vydaju (VS+polozky+OCR) + doklad pri zakladani + obrazkove skeny | ✅ done (qa=skipped) | | 2026-07-20 09:30 UTC | billit | hub+prod |f69936c| fulltext výdajů (server-side ?search= přes VS/položky/OCR) + doklad při zakládání výdaje + accept PDF/JPG/PNG/TIFF. migration_from 35c96ff, db_change none. VERIFIKACE: bez migrace (Migration OK), FE fresh (hub CzYGaWfF/prod h7kKZfhu), prod /health/deep OK, 2/2 healthy, QA 10/10. Fulltext = BE za auth → funkční validace na billit (authed). | ✅ verified | | 2026-07-20 14:53 UTC | billit | hub |ae3de87| feat(billit): ADR-026 — events stream billit->cortex na dedikovany cortex bus 6380 | ✅ done (qa=pass) | | 2026-07-20 14:57 UTC | billit | prod |ae3de87| feat(billit): ADR-026 — events stream billit->cortex na dedikovany cortex bus 6380 | ✅ done (qa=skipped) | | 2026-07-20 14:57 UTC | billit | hub+prod |ae3de87| ADR-026: events stream billit-to-cortex přepnut z s60-redis na dedikovaný cortex bus 6380 (per-env: prod→100.78.87.88:6380, hub→100.68.138.14:6380, izolace). CORTEX_BUS_REDIS_URL do secrets (per-env heslo z cortex-redis). VERIF: log "stream connected (cortex-bus 6380)" obě env, prod bus 4 klienti + queue meta, mail/interní na s60-redis beze změny, QA 10/10. ⚠️ 45 pre-switch eventů uvázlo na s60-redis:6379 (replay decision → billit). db_change none. | ✅ verified + 1 finding | | 2026-07-20 15:15 UTC | billit | prod | ops | REPLAY pre-switch eventů (Libor přímý go): UPDATE outbox_events reset dispatched_at pro 6 non-heartbeat (3 statement_item.created + mirror.failed + document.created + statement_item.linked), transakce+rowcount guard=6; drain re-published na prod bus 6380 (message_id ověřeno). AKCE 2: UNLINK 50 orphan bull:billit-to-cortex: na s60-redis (6379), ostatní fronty netknuté. Heartbeaty (41) ponechány. | ✅ done | | 2026-07-20 15:54 UTC | s60-auth | hub |fe92bbd| feat(auth): REQ-049 Fáze A — anti-bot registrace (email kanonizace + trust proxy + grandfather) | ✅ done (qa=pass) | | 2026-07-20 16:00 UTC | s60-auth | prod |fe92bbd| feat(auth): REQ-049 Fáze A — anti-bot registrace (email kanonizace + trust proxy + grandfather) | ✅ done (qa=skipped) | | 2026-07-20 15:59 UTC | s60-auth | hub+prod |fe92bbd| REQ-049 Fáze A anti-bot: L1 email kanonizace (gmail dot/+tag dedup→409), L0 trust proxy (TRUST_PROXY_HOPS default 0=OFF, NEnastaveno), L5 grandfather skript. Migrace AddCanonicalEmail (ADD COLUMN canonical_email + backfill + index, reverzibilní): hub 19/19, prod 276/276 backfill. QA 4/4, health 200/200, /api/version=fe92bbd. Grandfather Learnia s60-learnia-wp: 8 userů emailVerified=true (88/88 po apply). TRUST_PROXY_HOPS čeká infra; Learnia hard flip = Libor admin. | ✅ verified | | 2026-07-20 16:33 UTC | s60-auth | hub |15ffa38| chore: DEPLOY.md — Current 99e9715 (REQ-049 Fáze C) | ✅ done (qa=pass) | | 2026-07-20 16:35 UTC | s60-auth | prod |15ffa38| chore: DEPLOY.md — Current 99e9715 (REQ-049 Fáze C) | ✅ done (qa=skipped) | | 2026-07-20 16:34 UTC | s60-auth | hub+prod |15ffa38| REQ-049 Fáze A+B+C anti-bot (nahradil fe92bbd/jen A). NOVÁ migrace BlockedIps (CREATE TABLE blocked_ips + unique idx_blocked_ips_cidr, reverzibilní, owner=app user); AddCanonicalEmail už z fe92bbd (skip). Flagy OFF (TRUST_PROXY_HOPS=0, TURNSTILE_ENABLED=false, blocklist FAIL-OPEN) → neutrální. QA 4/4, health 200/200, /api/version=15ffa38, prod canonical 277/277. Grandfather Learnia už z fe92bbd (88/88). Pending: Learnia hard flip (Libor admin), TRUST_PROXY_HOPS (infra), Turnstile (CF klíče). | ✅ verified | | 2026-07-20 20:10 UTC | infra | prod-alfa | anti-bot | 3-vrstvá anti-bot obrana (forge playbook replikace, Libor go): (1) dc-block nftables — 11305 prefixů cloud/hosting ASN, ct-state fix, whitelist naše infra+Stripe(15)+Anthropic MCP+Starlink+Tailscale, VYŘAZEN Facebook+Datacamp VPN; systemd boot + týdenní refresh (containment guard). (2) fail2ban 3 jaily (badbots/auth-bruteforce/404, iptables-allports, ignoreip naše IP). (3) reporting sentinel cron /15 → surge Telegram+mail, denní digest 8:00. Containment PASS (login/Google/Stripe/VPN safe), 62% objemu útoků, drops+bany živé. Runbook: runbooks/anti-bot-defense.md | ✅ verified | | 2026-07-20 19:51 UTC | billit | hub |21edc38| fix(billit): oprava kodovani nazvu multipart souboru (Busboy latin-1 mojibake) | ⚠️ fail (qa=skipped) | | 2026-07-20 19:57 UTC | billit | hub |21edc38| fix(billit): oprava kodovani nazvu multipart souboru (Busboy latin-1 mojibake) | ✅ done (qa=pass) | | 2026-07-20 19:59 UTC | billit | prod |21edc38| fix(billit): oprava kodovani nazvu multipart souboru (Busboy latin-1 mojibake) | ⚠️ fail (qa=skipped) | | 2026-07-20 21:57 UTC | billit | hub+prod |21edc38| filename encoding fix (busboy latin-1→UTF-8 mojibake, české názvy souborů) — billit-api only, 0 migrací/env. VERIFIKACE: api verified 21edc38 (source hash match), health 200 obě env, multipart-filename.util v prod dist, QA 10/10. Pozn.: label 1/2 (web=f69936c) = cosmetic selective false-positive (web se neměnil), fix live; hub přeběhnut se SENTINEL_SELECTIVE pro clean stamp. | ✅ verified | | 2026-07-21 00:15 UTC | infra | prod-alfa | anti-bot v2 | dc-block přešel na FEED-BASED (sladěno s forge): raw ASN dump → udržované feedy (blocklist.de+ipsum L3+FireHOL L2+Spamhaus DROP) + malý-hosting ASN, ~28k prefixů, batched loader. VELKÉ CLOUDY VYŘAZENY (AWS/GCP/Azure) → LE HTTP-01 validace projde = LE renewal past ZAVŘENÁ (DNS-01 netřeba), Stripe/OAuth safe (feedy chytnou útočníky per-IP, legit cloud pustí). Whitelist auto z CF DNS (19 zón, RO token). ct-state v chainu (forge nemá — flagnuto). Containment PASS (prod/files/AWS-LE/Stripe/VPN accept, Azure attacker DROP), auth 200. Hodinový refresh cron. Runbook + antibot-research.md pro forge. | ✅ verified | | 2026-07-21 12:01 UTC | s60-mail | hub |36a41f6| chore(mail): DEPLOY.md → 89d1ed5 (audit fixy; NOVÁ ENV MAIL_INTERNAL_API_TOKEN) | ✅ done (qa=pass) | | 2026-07-21 13:24 UTC | s60-mail | prod |36a41f6| chore(mail): DEPLOY.md → 89d1ed5 (audit fixy; NOVÁ ENV MAIL_INTERNAL_API_TOKEN) | ✅ done (qa=skipped) | | 2026-07-21 13:39 UTC | n8n | hub |unknown| manual | ✅ done (qa=skip) | | 2026-07-21 13:54 UTC | n8n | prod |unknown| manual | ✅ done (qa=skipped) | | 2026-07-21 14:00 UTC | vaultwarden | prod |unknown| manual | ✅ done (qa=skipped) | | 2026-07-21 15:12 UTC | badwolf | hub |a378697| docs(specs): REQ-026 — DEC-002 sladění activate/deactivate (var. A) | ✅ done (qa=pass) | | 2026-07-21 17:50 UTC | badwolf | hub |a378697| docs(specs): REQ-026 — DEC-002 sladění activate/deactivate (var. A) | ✅ done (qa=pass) | | 2026-07-21 18:02 UTC | badwolf | prod |a378697| docs(specs): REQ-026 — DEC-002 sladění activate/deactivate (var. A) | ✅ done (qa=skipped) | | 2026-07-21 18:25 UTC | s60-auth | hub |4fcc13a| chore: DEPLOY.md — Current 00dd547 (REQ-050) | ✅ done (qa=pass) | | 2026-07-21 18:41 UTC | s60-auth | prod |4fcc13a| chore: DEPLOY.md — Current 00dd547 (REQ-050) | ✅ done (qa=skipped) | | 2026-07-21 19:00 UTC | venom | hub |2c150a1| docs(config): oprava zastaralých be. URL → api. v .env.example a deploy.yml | ✅ done (qa=pass) | | 2026-07-21 19:04 UTC | venom | prod |2c150a1| docs(config): oprava zastaralých be. URL → api. v .env.example a deploy.yml | ✅ done (qa=skipped) | | 2026-07-21 19:22 UTC | venom | hub |2e19e6f| feat(tasks): přidat libor.webster@gmail.com do TASK_ADMIN_EMAILS | ✅ done (qa=pass) | | 2026-07-21 19:26 UTC | venom | prod |2e19e6f| feat(tasks): přidat libor.webster@gmail.com do TASK_ADMIN_EMAILS | ✅ done (qa=skipped) | | 2026-07-21 19:34 UTC | s60-auth | hub |eafe8ff| chore: DEPLOY.md — Current 242a768 (REQ-050 audit čitelnost, bez nové migrace) | ✅ done (qa=pass) | | 2026-07-21 19:39 UTC | s60-auth | prod |eafe8ff| chore: DEPLOY.md — Current 242a768 (REQ-050 audit čitelnost, bez nové migrace) | ✅ done (qa=skipped) | | 2026-07-21 19:45 UTC | billit | hub |dc69754| fix(billit): GET /v1/accounts pro cross-tenant klic — jeden write klic da Cortexu UUID->slug mapu | ✅ done (qa=pass) | | 2026-07-21 19:49 UTC | billit | prod |dc69754| fix(billit): GET /v1/accounts pro cross-tenant klic — jeden write klic da Cortexu UUID->slug mapu | ⚠️ fail (qa=skipped) | | 2026-07-21 19:57 UTC | s60-pulse | hub |30f9b80| chore(pulse): DEPLOY.md — Current c46b347 (root-cause fix předčasné [SESSION_COMPLETE], bundle s force-complete, db_change NONE) | ✅ done (qa=pass) | | 2026-07-21 20:11 UTC | s60-pulse | prod |30f9b80| chore(pulse): DEPLOY.md — Current c46b347 (root-cause fix předčasné [SESSION_COMPLETE], bundle s force-complete, db_change NONE) | ✅ done (qa=skipped) | | 2026-07-21 20:53 UTC | s60-auth | hub |fd36ecf| chore: DEPLOY.md — Current 23dad3d (geoApi crash fix + tsc gate) | ✅ done (qa=pass) | | 2026-07-22 04:04 UTC | s60-auth | hub |686e879| chore: DEPLOY.md — Current ac317fa (REQ-051 + Turnstile, bez migrace; prod na fd36ecf) | ✅ done (qa=pass) | | 2026-07-22 04:39 UTC | s60-auth | prod |686e879| chore: DEPLOY.md — Current ac317fa (REQ-051 + Turnstile, bez migrace; prod na fd36ecf) | ✅ done (qa=skipped) | | 2026-07-22 04:47 UTC | s60-auth | hub |54e326e| chore: DEPLOY.md — Current 0a7dca4 (REQ-052 directory endpoint, bez migrace) | ✅ done (qa=pass) | | 2026-07-22 04:49 UTC | s60-auth | prod |54e326e| chore: DEPLOY.md — Current 0a7dca4 (REQ-052 directory endpoint, bez migrace) | ✅ done (qa=skipped) | | 2026-07-22 05:04 UTC | billit | hub |ccfbe08| feat(billit): REQ-060 — predkontace polozek vypisu (vlastni ucetni osa, nezavisla na parovani) | ✅ done (qa=pass) | | 2026-07-22 05:21 UTC | billit | prod |ccfbe08| feat(billit): REQ-060 — predkontace polozek vypisu (vlastni ucetni osa, nezavisla na parovani) | ✅ done (qa=skipped) | | 2026-07-22 05:38 UTC | badwolf | hub |3809097| fix(tasks): AUTH_DIRECTORY_URL tolerantní k host i .../api/directory (auth dodal jen host) | ✅ done (qa=pass) | | 2026-07-22 05:39 UTC | badwolf | prod |3809097| fix(tasks): AUTH_DIRECTORY_URL tolerantní k host i .../api/directory (auth dodal jen host) | ✅ done (qa=skipped) | | 2026-07-22 05:43 UTC | venom | hub |23b37e8| feat(tasks): skupiny/lektoři = reální uživatelé {id,name,email} (BW 6912d0c) | ✅ done (qa=pass) | | 2026-07-22 05:45 UTC | venom | prod |23b37e8| feat(tasks): skupiny/lektoři = reální uživatelé {id,name,email} (BW 6912d0c) | ✅ done (qa=skipped) | | 2026-07-22 05:54 UTC | badwolf | prod |3809097| fix(tasks): AUTH_DIRECTORY_URL tolerantní k host i .../api/directory (auth dodal jen host) | ✅ done (qa=skipped) | | 2026-07-22 06:15 UTC | badwolf | hub |36ece72| fix(auth): actor.id z user.id (JWT sub) — prod kanban in_progress nefungoval (Libor test 2026-07-22) | ✅ done (qa=pass) | | 2026-07-22 06:17 UTC | badwolf | prod |36ece72| fix(auth): actor.id z user.id (JWT sub) — prod kanban in_progress nefungoval (Libor test 2026-07-22) | ✅ done (qa=skipped) | | 2026-07-22 06:42 UTC | venom | hub |700c7d3| fix(tasks): MyQueue — sekce 'Rozpracované (držíte)' pro převzaté tasky | ✅ done (qa=pass) | | 2026-07-22 06:43 UTC | venom | prod |700c7d3| fix(tasks): MyQueue — sekce 'Rozpracované (držíte)' pro převzaté tasky | ✅ done (qa=skipped) | | 2026-07-22 06:58 UTC | billit | hub |e6a7084| fix(billit): CR-068 FR-4 — missing=attachment na NOT EXISTS(expense_attachments) + legacy fallback | ✅ done (qa=pass) | | 2026-07-22 07:01 UTC | billit | prod |e6a7084| fix(billit): CR-068 FR-4 — missing=attachment na NOT EXISTS(expense_attachments) + legacy fallback | ✅ done (qa=skipped) | | 2026-07-22 08:03 UTC | badwolf | hub |a385825| feat(tasks): „moje fronta" — scope=mine (převzaté + přiřazené + nepřevzaté mých skupin) (Libor 2026-07-22) | ✅ done (qa=pass) | | 2026-07-22 08:08 UTC | badwolf | prod |a385825| feat(tasks): „moje fronta" — scope=mine (převzaté + přiřazené + nepřevzaté mých skupin) (Libor 2026-07-22) | ✅ done (qa=skipped) | | 2026-07-22 08:10 UTC | venom | hub |b350838| feat(tasks): tlačítko 'Pustit se do toho' (pickup) ve frontě i detailu | ✅ done (qa=pass) | | 2026-07-22 08:14 UTC | venom | prod |b350838| feat(tasks): tlačítko 'Pustit se do toho' (pickup) ve frontě i detailu | ✅ done (qa=skipped) | | 2026-07-22 09:54 UTC | badwolf | hub |4ebf6d4| feat(user-prefs): per-user UI prefs endpoint /api/user-prefs (Libor 2026-07-22) | ✅ done (qa=pass) | | 2026-07-22 10:00 UTC | badwolf | prod |4ebf6d4| feat(user-prefs): per-user UI prefs endpoint /api/user-prefs (Libor 2026-07-22) | ✅ done (qa=skipped) | | 2026-07-22 10:03 UTC | venom | hub |d5000de| feat(tasks): kanban = plné akce (TaskCard v dialogu) + volitelné sloupce | ✅ done (qa=pass) | | 2026-07-22 10:11 UTC | venom | prod |d5000de| feat(tasks): kanban = plné akce (TaskCard v dialogu) + volitelné sloupce | ✅ done (qa=skipped) | | 2026-07-22 10:30 UTC | venom | hub |7ea7c0e| fix(tasks): kanban grid auto-fit místo auto-fill — skryté sloupce nezaberou místo | ✅ done (qa=pass) | | 2026-07-22 10:32 UTC | venom | prod |7ea7c0e| fix(tasks): kanban grid auto-fit místo auto-fill — skryté sloupce nezaberou místo | ✅ done (qa=skipped) | | 2026-07-22 10:43 UTC | s60-pulse | hub |d8a4ff8| chore(pulse): DEPLOY.md — Current 2c7436f (REQ-049 UX batch, db_change mig 158, prod 1e77e55) | ✅ done (qa=pass) | | 2026-07-22 10:46 UTC | s60-pulse | prod |d8a4ff8| chore(pulse): DEPLOY.md — Current 2c7436f (REQ-049 UX batch, db_change mig 158, prod 1e77e55) | ✅ done (qa=skipped) | | 2026-07-22 10:51 UTC | billit | hub |2694192| docs(billit): DEPLOY.md — hotfix 8f5dbdf JwtTenantGuard platform-key 22P02 | ✅ done (qa=pass) | | 2026-07-22 10:54 UTC | billit | prod |2694192| docs(billit): DEPLOY.md — hotfix 8f5dbdf JwtTenantGuard platform-key 22P02 | ✅ done (qa=skipped) | | 2026-07-22 17:22 UTC | s60-pulse | hub |9a92a2f| chore(pulse): DEPLOY.md — Current 870d4d7 (mobile video picker fix, db_change mig 158 kumulativně, prod 1e77e55) | ✅ done (qa=pass) | | 2026-07-22 17:25 UTC | s60-pulse | prod |9a92a2f| chore(pulse): DEPLOY.md — Current 870d4d7 (mobile video picker fix, db_change mig 158 kumulativně, prod 1e77e55) | ✅ done (qa=skipped) | | 2026-07-23 04:39 UTC | badwolf | hub |1b82e72| fix(clients): REQ-030 AC5 — CommunicationAggregatedDto skutečný superset ClientCommunication (Venom nález 2026-07-22) | ✅ done (qa=pass) | | 2026-07-23 04:59 UTC | venom | hub |35c3fdf| docs(specs): REQ-030 implemented (AC1-5 hotové, a38ca7f + a964a13) | ✅ done (qa=pass) | | 2026-07-23 05:03 UTC | badwolf | prod |1b82e72| fix(clients): REQ-030 AC5 — CommunicationAggregatedDto skutečný superset ClientCommunication (Venom nález 2026-07-22) | ✅ done (qa=skipped) | | 2026-07-23 05:22 UTC | venom | prod |35c3fdf| docs(specs): REQ-030 implemented (AC1-5 hotové, a38ca7f + a964a13) | ✅ done (qa=skipped) | | 2026-07-23 07:37 UTC | badwolf | hub |c0eabd9| feat(tasks): REQ-031 — event 'wake' (vrátit ze snoozu) + reopen na done (Libor go 2026-07-23) | ✅ done (qa=pass) | | 2026-07-23 07:40 UTC | badwolf | prod |c0eabd9| feat(tasks): REQ-031 — event 'wake' (vrátit ze snoozu) + reopen na done (Libor go 2026-07-23) | ✅ done (qa=skipped) | | 2026-07-23 07:44 UTC | venom | hub |4c64876| docs(specs): REQ-031 implemented (016dd71) | ✅ done (qa=pass) | | 2026-07-23 07:47 UTC | venom | prod |4c64876| docs(specs): REQ-031 implemented (016dd71) | ✅ done (qa=skipped) | | 2026-07-23 09:54 UTC | s60-pulse | hub |165c3cc| feat(pulse): CR-215 — zápisová cesta metodik + revert fast-pathu předčasného dokončení | ✅ done (qa=pass) | | 2026-07-23 10:00 UTC | s60-pulse | prod |165c3cc| feat(pulse): CR-215 — zápisová cesta metodik + revert fast-pathu předčasného dokončení | ✅ done (qa=skipped) | | 2026-07-25 05:20 UTC | billit | hub |28c5e6b| docs(billit): invoices SPEC.md — Flexi kolej (CR-069 FR-4) záznam | ✅ done (qa=pass) | | 2026-07-25 09:33 UTC | billit | hub |28c5e6b| docs(billit): invoices SPEC.md — Flexi kolej (CR-069 FR-4) záznam | ✅ done (qa=pass) | | 2026-07-25 09:35 UTC | billit | prod |28c5e6b| docs(billit): invoices SPEC.md — Flexi kolej (CR-069 FR-4) záznam | ✅ done (qa=skipped) | | 2026-07-25 10:52 UTC | s60-pulse | hub |8d29f72| chore(pulse): DEPLOY.md + state — Current 3a7f099 (CR-216, db_change NONE, env FREELO_, prod 165c3cc) | ✅ done (qa=pass) | | 2026-07-26 07:16 UTC | s60-pulse | hub |8d29f72| chore(pulse): DEPLOY.md + state — Current 3a7f099 (CR-216, db_change NONE, env FREELO_, prod 165c3cc) | ✅ done (qa=pass) | | 2026-07-26 07:25 UTC | s60-pulse | prod |8d29f72| chore(pulse): DEPLOY.md + state — Current 3a7f099 (CR-216, db_change NONE, env FREELO_, prod 165c3cc) | ✅ done (qa=skipped) | | 2026-07-30 05:07 UTC | s60-pulse | hub |a79a35c| chore(pulse): DEPLOY.md — Current ee637bf (CR-217 obnova metodik, data-only mig 159–166) | ✅ done (qa=pass) | | 2026-07-30 15:48 UTC | badwolf | hub |f987af1| docs: INDEX formátování — CR-013 řádek do tabulky | ✅ done (qa=pass) | | 2026-07-30 16:45 UTC | s60-pulse | hub |628b280| docs(pulse): CR-218 approved — konzultace čte svou připnutou verzi metodiky | ✅ done (qa=pass) | | 2026-07-30 16:55 UTC | s60-pulse | hub |628b280| docs(pulse): CR-218 approved — konzultace čte svou připnutou verzi metodiky | ✅ done (qa=pass) | | 2026-07-30 17:01 UTC | s60-pulse | prod |628b280| docs(pulse): CR-218 approved — konzultace čte svou připnutou verzi metodiky | ✅ done (qa=skipped) | | 2026-07-30 17:14 UTC | badwolf | hub |f987af1| docs: INDEX formátování — CR-013 řádek do tabulky | ✅ done (qa=pass) | | 2026-07-30 17:30 UTC | s60-mail | hub |36a41f6| chore(mail): DEPLOY.md → 89d1ed5 (audit fixy; NOVÁ ENV MAIL_INTERNAL_API_TOKEN) | ✅ done (qa=pass) | | 2026-07-30 17:40 UTC | s60-mail | hub |36a41f6| chore(mail): DEPLOY.md → 89d1ed5 (audit fixy; NOVÁ ENV MAIL_INTERNAL_API_TOKEN) | ✅ done (qa=pass) | | 2026-07-30 17:56 UTC | s60-mail | prod |36a41f6| chore(mail): DEPLOY.md → 89d1ed5 (audit fixy; NOVÁ ENV MAIL_INTERNAL_API_TOKEN) | ✅ done (qa=skipped) | | 2026-07-31 02:03 UTC | s60-auth | hub |54e326e| chore: DEPLOY.md — Current 0a7dca4 (REQ-052 directory endpoint, bez migrace) | ✅ done (qa=pass) | | 2026-07-31 02:07 UTC | s60-auth | prod |54e326e| chore: DEPLOY.md — Current 0a7dca4 (REQ-052 directory endpoint, bez migrace) | ✅ done (qa=skipped) | | 2026-07-31 02:25 UTC | badwolf | hub |74579e7| docs(deploy): Current f36c133 — přibylo CR-015; deploy HEADu = deploy f36c133 | ✅ done (qa=pass) | | 2026-07-31 02:40 UTC | badwolf | prod |74579e7| docs(deploy): Current f36c133 — přibylo CR-015; deploy HEADu = deploy f36c133 | ✅ done (qa=skipped) | | 2026-08-01 05:59 UTC | s60-mail | hub |36a41f6| chore(mail): DEPLOY.md → 89d1ed5 (audit fixy; NOVÁ ENV MAIL_INTERNAL_API_TOKEN) | ✅ done (qa=pass) |⚠️ Pozor na tři starší řádky
s60-mail/36a41f6výš (21. 7. prod, 30. 7. 17:30 + 17:40 hub, 30. 7. 17:56 prod, všechny „✅ done"). Ten kód se nikdy nedostal dovnitř. Před deployem 1. 8. vracel hub/healthprázdnédetails—{"status":"ok","info":{},"error":{},"details":{}}— kdežto 36a41f6 má health reálně pingovat DB+Redis. Po deployi 1. 8. vrací{"database":{"status":"up"},"redis":{"status":"up"}}. Stejný commit, jiný výsledek ⇒ starší běhy zapsaly do changelogu záměr, ne skutečnost. Není to známá díra „chybíbuild:v compose" (s60-mail ji má, ř. 10) — příčina zůstává neobjasněná, viz [[feedback_deploy_build_command_dead]]. Ponaučení: „✅ done" v changelogu není důkaz nasazení. Ověřuj chováním běžícího kódu. | 2026-08-01 06:12 UTC | s60-mail | prod |36a41f6| chore(mail): DEPLOY.md → 89d1ed5 (audit fixy; NOVÁ ENV MAIL_INTERNAL_API_TOKEN) | ✅ done (qa=skipped) | | 2026-08-01 08:34 UTC | s60-mail | hub |36a41f6| chore(mail): DEPLOY.md → 89d1ed5 (audit fixy; NOVÁ ENV MAIL_INTERNAL_API_TOKEN) | ✅ done (qa=pass, build=full) | | 2026-08-01 08:41 UTC | s60-mail | hub |36a41f6| chore(mail): DEPLOY.md → 89d1ed5 (audit fixy; NOVÁ ENV MAIL_INTERNAL_API_TOKEN) | ✅ done (qa=pass, build=skipped) | | 2026-08-01 09:06 UTC | s60-mail | hub |36a41f6| chore(mail): DEPLOY.md → 89d1ed5 (audit fixy; NOVÁ ENV MAIL_INTERNAL_API_TOKEN) | ✅ done (qa=pass, build=full) | | 2026-08-01 09:42 UTC | badwolf | hub |d0fa5e8| docs(deploy): Current 438f315 — access mail + health víkend + clients lookup (bez migrací) | ✅ done (qa=pass, build=full) | | 2026-08-01 09:52 UTC | badwolf | prod |d0fa5e8| docs(deploy): Current 438f315 — access mail + health víkend + clients lookup (bez migrací) | ✅ done (qa=skipped, build=full) | | 2026-08-01 10:28 UTC | s60-auth | hub |cbffa6f| chore: DEPLOY.md — Current 88fded1 (+ REQ-056 fáze 1, třetí migrace) | ✅ done (qa=pass, build=full) | | 2026-08-01 10:33 UTC | s60-auth | prod |cbffa6f| chore: DEPLOY.md — Current 88fded1 (+ REQ-056 fáze 1, třetí migrace) | ✅ done (qa=skipped, build=full) | | 2026-08-01 10:42 UTC | badwolf | hub |d0fa5e8| docs(deploy): Current 438f315 — access mail + health víkend + clients lookup (bez migrací) | ✅ done (qa=pass, build=full) | | 2026-08-01 12:07 UTC | venom | hub |4877d0f| docs(specs): REQ-033 draft — viditelnost termínu (isVisible) + termíny bez data (isDatePlaceholder) | ✅ done (qa=pass, build=full) | | 2026-08-01 12:18 UTC | venom | prod |4877d0f| docs(specs): REQ-033 draft — viditelnost termínu (isVisible) + termíny bez data (isDatePlaceholder) | ✅ done (qa=skipped, build=full) | | 2026-08-01 12:30 UTC | venom | hub |4877d0f| docs(specs): REQ-033 draft — viditelnost termínu (isVisible) + termíny bez data (isDatePlaceholder) | ✅ done (qa=pass, build=full) | | 2026-08-01 12:49 UTC | badwolf | hub |d0fa5e8| docs(deploy): Current 438f315 — access mail + health víkend + clients lookup (bez migrací) | ✅ done (qa=pass, build=full) | | 2026-08-01 12:57 UTC | badwolf | prod |d0fa5e8| docs(deploy): Current 438f315 — access mail + health víkend + clients lookup (bez migrací) | ✅ done (qa=skipped, build=full) | | 2026-08-01 13:59 UTC | badwolf | hub |c26ae42| docs(deploy): Current = f91c759 — přibylo CR-018 (health liveness), migrace 074 beze změny | ✅ done (qa=pass, build=full) | | 2026-08-01 14:01 UTC | badwolf | prod |c26ae42| docs(deploy): Current = f91c759 — přibylo CR-018 (health liveness), migrace 074 beze změny | ✅ done (qa=skipped, build=full) | | 2026-08-01 14:05 UTC | venom | hub |f0f0a60| feat(terms): REQ-033 — viditelnost termínu a termíny bez data | ✅ done (qa=pass, build=full) | | 2026-08-01 14:11 UTC | venom | prod |f0f0a60| feat(terms): REQ-033 — viditelnost termínu a termíny bez data | ✅ done (qa=skipped, build=full) | | 2026-08-01 14:17 UTC | s60-auth | hub |64fe364| chore: DEPLOY.md — Current ee83511 (REQ-056 fáze 2 + pre-flip-check, migrace beze změny) | ✅ done (qa=pass, build=full) | | 2026-08-01 14:21 UTC | s60-auth | prod |64fe364| chore: DEPLOY.md — Current ee83511 (REQ-056 fáze 2 + pre-flip-check, migrace beze změny) | ✅ done (qa=skipped, build=full) | | 2026-08-01 14:43 UTC | venom | hub |0135373| feat(clients): CR-002 — klient bez e-mailu + konflikt adresy jako pracovní stav | ✅ done (qa=pass, build=full) | | 2026-08-01 14:45 UTC | venom | prod |0135373| feat(clients): CR-002 — klient bez e-mailu + konflikt adresy jako pracovní stav | ✅ done (qa=skipped, build=full) | | 2026-08-01 14:58 UTC | billit | hub |a413e16| docs(billit): import SPEC.md — CR-070 FR-4 záznam (odvozování platebních polí, subject_id, kořenový element) | ✅ done (qa=pass, build=full) | | 2026-08-01 15:08 UTC | billit | prod |a413e16| docs(billit): import SPEC.md — CR-070 FR-4 záznam (odvozování platebních polí, subject_id, kořenový element) | ✅ done (qa=skipped, build=skipped) | | 2026-08-01 19:25 UTC | billit | hub |baacf2b| docs(billit): REQ-064 §10 implementováno — stav + poznámka k findOne | ⚠️ fail (qa=skipped, build=full) | | 2026-08-01 19:28 UTC | billit | hub |baacf2b| docs(billit): REQ-064 §10 implementováno — stav + poznámka k findOne | ✅ done (qa=pass, build=skipped) | | 2026-08-01 19:31 UTC | billit | prod |baacf2b| docs(billit): REQ-064 §10 implementováno — stav + poznámka k findOne | ✅ done (qa=skipped, build=full) | | 2026-08-01 19:39 UTC | s60-auth | hub |f55736d| chore: DEPLOY.md — Current e74496e (CR-019 + admin UI, bez migrace) | ✅ done (qa=pass, build=full) | | 2026-08-01 19:41 UTC | s60-auth | prod |f55736d| chore: DEPLOY.md — Current e74496e (CR-019 + admin UI, bez migrace) | ✅ done (qa=skipped, build=full) | | 2026-08-01 19:55 UTC | badwolf | hub |8c26ba1| docs(deploy): Current = d54c542 — přibylo CR-021 (account + login-email). Migrace beze změny: 074/075/076 | ✅ done (qa=pass, build=full) | | 2026-08-01 19:57 UTC | badwolf | prod |8c26ba1| docs(deploy): Current = d54c542 — přibylo CR-021 (account + login-email). Migrace beze změny: 074/075/076 | ✅ done (qa=skipped, build=full) | | 2026-08-01 20:03 UTC | venom | hub |9573b61| feat(clients): REQ-035 — stav přihlašovacího účtu a nedodané přístupy | ✅ done (qa=pass, build=full) | | 2026-08-01 20:05 UTC | venom | prod |9573b61| feat(clients): REQ-035 — stav přihlašovacího účtu a nedodané přístupy | ✅ done (qa=skipped, build=full) | | 2026-08-01 20:10 UTC | badwolf | hub |5441d7a| docs(deploy): Current = eb44d72 — schémata access-mailů. Migrace beze změny: 074/075/076 | ✅ done (qa=pass, build=full) | | 2026-08-01 20:12 UTC | badwolf | prod |5441d7a| docs(deploy): Current = eb44d72 — schémata access-mailů. Migrace beze změny: 074/075/076 | ✅ done (qa=skipped, build=full) | | 2026-08-01 20:16 UTC | venom | hub |ae66059| fix(clients): nedodaný přístup bez zapsaného důvodu se schovával do historie + tlačítko Založit účet | ✅ done (qa=pass, build=full) | | 2026-08-01 20:18 UTC | venom | prod |ae66059| fix(clients): nedodaný přístup bez zapsaného důvodu se schovával do historie + tlačítko Založit účet | ✅ done (qa=skipped, build=full) | | 2026-08-02 04:09 UTC | billit | hub |8b3e330| fix(billit): RegistriesModule neaplikoval TenantMiddleware → nové endpointy 500 na prod | ✅ done (qa=pass, build=full) | | 2026-08-02 04:18 UTC | billit | prod |8b3e330| fix(billit): RegistriesModule neaplikoval TenantMiddleware → nové endpointy 500 na prod | ✅ done (qa=skipped, build=full) | | 2026-08-02 06:02 UTC | billit | hub |7c490bc| feat(billit): REQ-064 §2.2b — pull katalogu z BadWolfu (nahrazuje jejich zrušený push) | ✅ done (qa=pass, build=full) | | 2026-08-02 06:04 UTC | billit | prod |7c490bc| feat(billit): REQ-064 §2.2b — pull katalogu z BadWolfu (nahrazuje jejich zrušený push) | ✅ done (qa=skipped, build=full) | | 2026-08-02 06:17 UTC | badwolf | hub |2033c57| docs(deploy): Current = 3e69295 — CR-019 publikační rozsah (migrace 077). Předchozí balík archivován jako nasazený (5441d7a) | ✅ done (qa=pass, build=full) | | 2026-08-02 06:25 UTC | badwolf | prod |2033c57| docs(deploy): Current = 3e69295 — CR-019 publikační rozsah (migrace 077). Předchozí balík archivován jako nasazený (5441d7a) | ✅ done (qa=skipped, build=full) | | 2026-08-02 06:44 UTC | s60-auth | hub |f55736d| chore: DEPLOY.md — Current e74496e (CR-019 + admin UI, bez migrace) | ✅ done (qa=pass, build=full) | | 2026-08-02 07:10 UTC | s60-auth | prod |f55736d| chore: DEPLOY.md — Current e74496e (CR-019 + admin UI, bez migrace) | ✅ done (qa=skipped, build=full) | | 2026-08-02 07:25 UTC | badwolf | hub |fd69740| docs(deploy): Current = f48a040 — venom REQ-036 (409 conflict_other_identity, sessionsInvalidated, EmailMismatchDto). BEZ migrace. CR-019 archivován jako nasazený | ✅ done (qa=pass, build=full) | | 2026-08-02 07:31 UTC | badwolf | prod |fd69740| docs(deploy): Current = f48a040 — venom REQ-036 (409 conflict_other_identity, sessionsInvalidated, EmailMismatchDto). BEZ migrace. CR-019 archivován jako nasazený | ✅ done (qa=skipped, build=full) | | 2026-08-02 07:36 UTC | venom | hub |b09c585| feat(clients): REQ-036 — přehození přihlašovací adresy klienta | ✅ done (qa=pass, build=full) | | 2026-08-02 07:41 UTC | venom | prod |b09c585| feat(clients): REQ-036 — přehození přihlašovací adresy klienta | ✅ done (qa=skipped, build=full) | | 2026-08-02 07:50 UTC | billit | hub |83123a7| test(billit): pojistka na TenantMiddleware — z "budu si dávat pozor" udělán test | ⚠️ fail (qa=skipped, build=full) | | 2026-08-02 08:00 UTC | billit | hub |83123a7| test(billit): pojistka na TenantMiddleware — z "budu si dávat pozor" udělán test | ✅ done (qa=pass, build=full) | | 2026-08-02 08:08 UTC | billit | prod |83123a7| test(billit): pojistka na TenantMiddleware — z "budu si dávat pozor" udělán test | ✅ done (qa=skipped, build=full) | | 2026-08-02 08:22 UTC | s60-pulse | hub |9012e6c| fix(pulse): REQ-049 — bind /mnt/pulse-reviews do compose, jinak se video recenze tiše ztrácejí | ✅ done (qa=pass, build=full) | | 2026-08-02 08:32 UTC | s60-pulse | hub |9012e6c| fix(pulse): REQ-049 — bind /mnt/pulse-reviews do compose, jinak se video recenze tiše ztrácejí | ✅ done (qa=pass, build=full) | | 2026-08-02 08:39 UTC | s60-pulse | prod |9012e6c| fix(pulse): REQ-049 — bind /mnt/pulse-reviews do compose, jinak se video recenze tiše ztrácejí | ✅ done (qa=skipped, build=full) | | 2026-08-03 05:01 UTC | s60-pulse | hub |2d5543c| fix(pulse): kredity, totožnost v pokladně a co koupě uzavírá | ✅ done (qa=pass, build=full) | | 2026-08-03 05:07 UTC | s60-pulse | prod |2d5543c| fix(pulse): kredity, totožnost v pokladně a co koupě uzavírá | ✅ done (qa=skipped, build=full) | | 2026-08-03 07:19 UTC | s60-pulse | hub |2d5543c| fix(pulse): kredity, totožnost v pokladně a co koupě uzavírá | ✅ done (qa=pass, build=full) | | 2026-08-03 07:55 UTC | s60-pulse | prod |2d5543c| fix(pulse): kredity, totožnost v pokladně a co koupě uzavírá | ✅ done (qa=skipped, build=full) | | 2026-08-03 13:40 UTC | s60-pulse | hub |5141fc0| fix(pulse): CR-222 — lomítko navíc v prefixu nesmí zneviditelnit klientovo video | ✅ done (qa=pass, build=full) | | 2026-08-03 13:44 UTC | s60-pulse | prod |5141fc0| fix(pulse): CR-222 — lomítko navíc v prefixu nesmí zneviditelnit klientovo video | ✅ done (qa=skipped, build=full) | | 2026-08-04 04:34 UTC | billit | hub |a8c7d21| fix(billit): BUG-004 — doplněno 781 e-mailů kontaktů z Fakturoidu | ✅ done (qa=pass, build=full) | | 2026-08-12 06:35 UTC | s60-pulse | hub |9d32103| feat(pulse): CR-223 — nezaplacená objednávka se ozve a sama zavře | ✅ done (qa=pass, build=full) | | 2026-08-12 07:13 UTC | s60-pulse | prod |9d32103| feat(pulse): CR-223 — nezaplacená objednávka se ozve a sama zavře | ✅ done (qa=skipped, build=full) | | 2026-08-12 07:17 UTC | n8n | hub |unknown| manual | ✅ done (qa=skip, build=full) | | 2026-08-12 07:22 UTC | n8n | prod |unknown| manual | ✅ done (qa=skipped, build=full) | | 2026-08-25 04:34 UTC | n8n | hub |unknown| manual | ✅ done (qa=skip, build=full) | | 2026-08-25 04:43 UTC | n8n | prod |unknown| manual | ✅ done (qa=skipped, build=full) | | 2026-08-26 03:52 UTC | s60-pulse | hub |0d86499| fix(pulse): ukazatel průběhu generování přestává lhát (sectionsCompleted) | ✅ done (qa=pass, build=full) | | 2026-08-26 04:01 UTC | s60-pulse | prod |0d86499| fix(pulse): ukazatel průběhu generování přestává lhát (sectionsCompleted) | ✅ done (qa=skipped, build=full) |