Changelog

Historie změn pro testery. Tato stránka bude odstraněna před produkčním spuštěním.

21. března 2026
  • Fix: Zkrácený nadpis ticketu zůstával oříznutý i po rozbalení (mobil)
  • • `frontend/src/app/support/page.tsx` — podmíněné `truncate` jen pro zavřený stav, rozbalený zobrazí celý nadpis (`whitespace-normal break-words`)
  • Fix: Email notifikace z admin panelu nefungovaly
  • • `lead_approved` email sellerovi při schválení poptávky
  • • `lead_rejected` email sellerovi při zamítnutí poptávky
  • • `sale_confirmed` email makléři při potvrzení prodeje
  • • `rating_request` email sellerovi s žádostí o hodnocení
  • • `frontend/src/app/api/send-notification/route.ts` — nová server-side proxy (auth + admin role check + service_role forwarding)
  • • `frontend/src/app/admin/leads/[id]/page.tsx` — přesměrování na `/api/send-notification`
  • • `frontend/src/app/admin/matches/[id]/page.tsx` — přesměrování na `/api/send-notification`
  • Fix: Přetékání předmětu ticketu na /support (mobil)
  • • `frontend/src/app/support/page.tsx` — přidáno `overflow-hidden` na flex wrapper v `CardHeader`
19. března 2026
  • Chore: GDPR compliance — Sentry sendDefaultPii + Privacy Policy Session Replay
  • • `frontend/sentry.client.config.ts` — přidáno explicitní `sendDefaultPii: false` (potvrzuje default, GDPR best practice)
  • • `frontend/src/app/privacy/page.tsx` — sekce 3.14 doplněna o informaci o Sentry Session Replay (automatické maskování textu a vstupů)
  • Fix: Aktualizace právních dokumentů v registračních modálech na v2.0
  • • Broker: `TERMS_VERSION` 1.0 → 2.0, `EXPLICIT_POINTS` sladěny s čl. 4.3/5/9/14 Rámcové smlouvy v2.0
  • • Broker: Modál smlouvy — odstraněn banner "pracovní verze", nahrazen stručným shrnutím + odkaz na `/terms/broker`
  • • Broker: Modál GDPR — aktualizován na v2.0 shrnutí + odkaz na `/privacy`
  • • Seller: Modál podmínek — aktualizován na v2.0 shrnutí + odkaz na `/terms`
  • • Seller: Modál GDPR — aktualizován na v2.0 shrnutí + odkaz na `/privacy`
  • • `PRAVNIK-BRIEF.md` — aktualizovány reference na verzi 2.0
  • Chore: Odstranění mrtvého kódu
  • • `frontend/src/components/lead-location-map.tsx` — odstraněn nepoužívaný prop `locationArea`
  • • `frontend/src/app/broker/leads/[id]/page.tsx` — odstraněno předávání `locationArea`
  • • `frontend/src/components/service-checkboxes.tsx` — odstraněn mrtvý prop `compact`, zjednodušen className (obě větve ternary byly identické)
  • • `frontend/src/app/globals.css` — smazáno 9 nepoužívaných CSS utility tříd (`border-brand-gradient`, `shadow-brand-glow`, `border-l-brand`, `border-l-brand-dark`, `shadow-brand-sm/md/lg/xl`, `hover-lift`, `active-press`)
  • • `frontend/src/app/profile/page.tsx` — odstraněn deprecated `full_name` zápis
  • • `frontend/src/app/auth/register/seller/page.tsx` — odstraněn deprecated `full_name` zápis
  • • `frontend/src/app/auth/register/broker/page.tsx` — odstraněn deprecated `full_name` zápis
18. března 2026
  • Fix: Horizontální overflow na stránce /support (mobilní verze)
  • • `frontend/src/app/support/page.tsx` — header: responsive stacking (`flex-col` → `sm:flex-row`), ticket karta: badges wrap pod titulek na mobilu
12. března 2026
  • Feat: České skloňování jmen (vokativ) ve všech emailech
  • • `supabase/functions/send-notification-email/index.ts` — v17: přidána `toVocative()` funkce, nové pole `to_first_name`, handler převádí greeting na vokativ
  • • `frontend/src/app/admin/leads/[id]/page.tsx` — 2× přidáno `to_first_name` (lead_approved, lead_rejected)
  • • `frontend/src/app/admin/matches/[id]/page.tsx` — 2× přidáno `to_first_name` (rating_request, sale_confirmed)
  • • `supabase/functions/auto-approve-leads/index.ts` — přidáno `to_first_name` (lead_approved)
  • • `frontend/src/app/api/report-sale/route.ts` — přidáno `to_first_name` (sale_reported)
  • • `frontend/src/app/api/support-ticket/route.ts` — import `toVocative`, oslovení ve vokativu
  • • `frontend/src/app/api/support-ticket/reply/route.ts` — import `toVocative`, oslovení ve vokativu
  • Fix: Validace čísla jednotky (unit_number) — pouze číslice
  • • `frontend/src/components/unit-number-input.tsx` — filtr ne-číslic na onChange, `inputMode="numeric"`, aktualizované hinty
  • • `frontend/src/app/api/cadastral-lookup/route.ts` — API-level strip ne-číslic před parseInt (safety net)
  • • `frontend/src/app/admin/leads/[id]/page.tsx` — stejná validace v admin editaci, opraven placeholder
  • Fix: PriceInput na všech místech zadávání ceny
  • • `frontend/src/app/broker/matches/[id]/page.tsx` — PriceInput pro reportPrice
  • • `frontend/src/app/admin/matches/[id]/page.tsx` — PriceInput pro salePrice
10. března 2026
  • Feature: Edge Function `delete-account` — soft delete uživatelského účtu
  • • Nová Edge Function `delete-account/index.ts` — soft delete (anonymizace profilu + ban ~100 let)
  • • Dva režimy: self-service (uživatel z profilu s ověřením hesla) a admin (z admin panelu bez hesla)
  • • Broker flow: blokace při aktivních matchích (409 ACTIVE_MATCHES), reject pending bidů, smazání service profiles
  • • Seller flow: cancel aktivních leadů + watching matchů, reject pending bidů na těchto leadech
  • • Audit snapshot do `account_deletion_audit` před anonymizací (email, jméno, IČO, statistiky matchů)
  • • Auth anonymizace: email → `deleted_{id}@deleted.spravnymakler.cz`, ban 876000h, metadata vyčištěna
  • • Admin delete v `admin/users/[id]` přepsán z hard-delete na soft-delete přes Edge Function
9. března 2026
  • Fix: Validace profilu blokuje uložení notifikací
  • • Přidán řízený `activeTab` state pro `<Tabs>` komponentu
  • • Validace IČO, office address a network membership podmíněny `activeTab === "company" || "profile"`
  • • Tab Notifikace nyní ukládá bez blokování nesouvisejícími validacemi
5. března 2026
  • Fix: CRON joby failují — GUC parametr odstraněn ze Supabase
  • • CRON joby přeregistrovány — čtou klíč z `vault.decrypted_secrets` místo `current_setting()`
  • • Vault secret aktualizován na nový `sb_secret_` formát
  • • 2 zaseknuté leady (Chrást, Plzeň) auto-approved po opravě
  • • `supabase/migrations/20260305080000_fix_cron_vault_auth.sql` — nová migrace
  • • `supabase/migrations/20260124150000_setup_watchdog_cron.sql` — komentář o obsolete GUC
  • • `CLAUDE.md` — aktualizovaná sekce CRON auth
27. února 2026
  • Fix: Notifikace — deep-link s auto-expand
  • • `new_rating` → `/admin/ratings?rating_id=...` (admin vidí konkrétní hodnocení)
  • • `support_ticket` → `/admin/support?ticket_id=...` (admin vidí konkrétní ticket)
  • • `support_reply` → `/support?ticket_id=...` (seller vidí odpověď)
  • • `frontend/src/app/api/submit-rating/route.ts` — INSERT vrací ID, deep-link href
  • • `frontend/src/app/api/support-ticket/route.ts` — deep-link href s ticket_id
  • • `frontend/src/app/api/support-ticket/reply/route.ts` — deep-link href s ticket_id
  • • `frontend/src/app/admin/ratings/page.tsx` — useSearchParams + auto-expand + scrollIntoView
  • • `frontend/src/app/admin/support/page.tsx` — useSearchParams + auto-expand + scrollIntoView
  • • `frontend/src/app/support/page.tsx` — useSearchParams + auto-expand + scrollIntoView
  • Fix: Notifikace — revert "Zobrazit" tlačítka + fix rejection směrování
  • • `/notifications` stránka: revert na klik=navigace (klik na notifikaci = markAsRead + přechod na detail), odstraněno redundantní tlačítko "Zobrazit"
  • • Rejection notifikace ("vrácena k přepracování") nyní směřuje na `/seller/leads/[id]` (detail s bannerem + důvodem) místo `/seller/leads/[id]/edit` (edit stránka bez důvodu)
  • • `frontend/src/app/notifications/page.tsx` — revert klik=navigace, odebrán "Zobrazit" blok
  • • `frontend/src/app/admin/leads/[id]/page.tsx` — rejection href na detail místo edit
  • UI: Notifikace — plný text + mobile responsivita
  • • `/notifications` stránka: odstraněn `line-clamp-2` → celý body text (důvod zamítnutí apod.) je viditelný
  • • Popover zvoneček: responsive šířka (`w-[calc(100vw-2rem)] sm:w-80`) — na mobilu zabere viewport
  • • Header: badge zkrácen na číslo, "Přečíst vše" na mobilu jen ikona
  • • `frontend/src/components/notification-bell.tsx` — responsive popover šířka
  • • `frontend/src/app/notifications/page.tsx` — plný body text, responsive header
  • Fix: Chybějící emaily pro sellera (lead approval + support ticket reply)
  • • Přidány CORS headers do `send-notification-email` Edge Function (OPTIONS handler + `Access-Control-Allow-Origin/Headers` na všech response)
  • • Přidán `RESEND_API_KEY` do Coolify env vars + `.env.local`
  • • Vyměněn Resend API klíč ve všech prostředích (Supabase secrets, Coolify, lokální)
  • • Přidán response status logging do support-ticket route (`.then()` + `.catch()` místo jen `.catch()`)
  • • `supabase/functions/send-notification-email/index.ts` — CORS headers + OPTIONS handler (deploy v29)
  • • `frontend/src/app/api/support-ticket/reply/route.ts` — Resend response logging
  • • `frontend/src/app/api/support-ticket/route.ts` — Resend response logging
  • • `frontend/.env.example` — přidán `RESEND_API_KEY` placeholder
  • Fix: False positive v detekci duplicitních leadů (F19)
  • • Kontrola duplicit porovnávala pouze `parcel_number` + `unit_number`, ale ignorovala `property_type`
  • • Byt a garáž na stejné parcele jsou různé nemovitosti, ale systém je blokoval jako duplicitu
  • • Přidán `.eq("property_type", formData.propertyType)` do duplikátní kontroly
  • Fix: CRON auth — auto-approve-leads, checkin-send, watchdog-check 401 Unauthorized
  • • `auto-approve-leads` nasazena s `verify_jwt: true` (Supabase proxy odmítne CRON request před spuštěním kódu)
  • • CRON joby 4 (checkin-send) a 5 (auto-approve-leads) používaly neexistující GUC `app.settings.service_role_key` → NULL → Authorization header se neposlal
  • • `watchdog-check` neměl žádný auth check ani Authorization header v CRONu — veřejně přístupný
  • • Re-deploy `auto-approve-leads` s `verify_jwt: false` + explicitní auth check (service_role Bearer token)
  • • Re-deploy `watchdog-check` s auth checkem (předtím bez jakékoli ochrany)
  • • Oprava CRON jobů 2, 4, 5: `app.settings.service_role_key` → `supabase.service_role_key`
  • • `supabase/functions/auto-approve-leads/index.ts` — auth check přidán
  • • `supabase/functions/watchdog-check/index.ts` — auth check přidán
  • • SQL: `cron.alter_job(2)`, `cron.alter_job(4)`, `cron.alter_job(5)` (Supabase MCP)
26. února 2026
  • Fix: Admin notifikace při resubmitu leadu + Confirmation dialog
  • • Admin nedostával notifikaci když seller resubmitnul zamítnutý lead (trigger byl AFTER INSERT only)
  • • Nový UPDATE trigger `on_lead_resubmit_notify_admin` (rejected → pending_review)
  • • Funkce `notify_admin_pending_review()` rozlišuje INSERT/UPDATE přes `TG_OP` (jiný title + `is_resubmit` metadata)
  • • Confirmation dialog před resubmitem zamítnutého leadu (`LeadResubmitConfirmDialog`)
  • • Shrnutí klíčových údajů (typ, adresa, plocha, dispozice, stav, PENB, omezení, fotky)
  • • Čestné prohlášení o neexkluzivitě (povinný checkbox)
  • • Tlačítko "Zkontrolovat a odeslat" místo "Uložit změny" pro rejected leady
  • • Běžná editace pending_review leadu funguje přímo bez dialogu (bez regrese)
  • • SQL migrace: `notify_admin_on_lead_resubmit` (Supabase MCP)
  • • `components/lead-resubmit-confirm-dialog.tsx` — **NOVÝ**
  • • `seller/leads/[id]/edit/page.tsx` — dialog integrace, split handleSubmit/performUpdate
  • Brand-Consistent Email Templates (v16)
  • • Gradient top border (4px, 3 barvy: `#220860→#6039f6→#AF96FC`)
  • • Logo header (nové S-shape brand logo, 150×45px, Supabase Storage CDN)
  • • Tmavě fialový footer (`#220860` bg, `#AF96FC` nadpisy, právní údaje OneManDev s.r.o.)
  • • 3-barevný CTA gradient + solid `#6039f6` fallback pro Outlook
  • • Font stack rozšířen: Geist + system fallbacks (místo jen Arial)
  • • Zelená (`#22c55e`) → fialová (`#6039f6`) pro success stavy
  • • Ambrová (`#f59e0b`) → lavender (`#AF96FC`) pro attention stavy
  • • Oranžová (`#f97316`) → tmavě fialová (`#220860`) pro action stavy
  • • Šedý plaintext footer → dark purple branded footer
  • • 2-barevný CTA gradient → 3-barevný (konzistentní s webem)
  • • `send-notification-email/index.ts` — v16: BRAND konstanty, 4 helper funkce, redesign 11 šablon
  • • `lib/email-wrapper.ts` — **NOVÝ**: sdílený brand header/footer pro Next.js routes
  • • `api/support-ticket/route.ts` — redesign 2 inline emailů
  • • `api/support-ticket/reply/route.ts` — redesign 1 inline emailu
  • Audit & Fix: Konzistence notifikačního systému (6 oprav)
  • • Chybějící email šablony `sale_confirmed`, `sale_reported`, `rating_request` v Edge Function — emaily tiše selhávaly s 400 (→ v15, deployed)
  • • `submit-rating` posílal notifikaci sellerovi místo adminům (`p_user_id: user.id` bug) — opraveno na loop přes adminy, typ změněn na `new_rating`
  • • Duplikátní match notifikace — `create_match()` + trigger `notify_match_created()` = 2 in-app pro každého — odebrán `PERFORM create_notification()` z `create_match()` (SQL migrace)
  • • `watchdog-check` v5 — přímý Resend nahrazen Edge Function `plomba_detected`, hardcoded `ADMIN_EMAIL` → dynamický dotaz na adminy, přidána in-app notifikace
  • • `support-ticket` — přidána in-app notifikace pro adminy (`support_ticket` typ)
  • • Tiché `.catch(() => {})` v admin leads → nahrazeny `console.error()` logováním
  • • `send-notification-email/index.ts` — 3 nové šablony (v15)
  • • `watchdog-check/index.ts` — Edge Function + in-app + dynamičtí admini (v5)
  • • `api/submit-rating/route.ts` — fix admin notifikace
  • • `api/support-ticket/route.ts` — in-app pro adminy
  • • `admin/leads/[id]/page.tsx` — fix tiché .catch
  • • `lib/constants.ts` — nové notif. typy `new_rating`, `support_ticket`
  • • SQL migrace `create_match()` — odebrány duplikátní notifikace
  • Fix: Chybějící notifikace sellerovi při schválení/zamítnutí leadu
  • • Email při zamítnutí volal neexistující route `/api/send-notification` → opraveno na Edge Function `send-notification-email`
  • • In-app notifikace při zamítnutí používala neexistující parametr `p_data` → opraveno na `p_title`/`p_body`/`p_href`/`p_metadata`
  • • Seller email se nenačítal (je v `auth.users`, ne v `profiles`) → doplněn RPC `get_user_email_by_id`
  • • Dual-write notifikace sellerovi při schválení leadu (admin i auto-approve)
  • • Email šablona `lead_approved` v Edge Function v14
  • • Auto-approve CRON (v2) odesílá seller notifikace
  • • Nový typ `lead_review` v notifikačních preferencích + UI řádek "Schválení poptávky" v profilu sellera
  • • `admin/leads/[id]/page.tsx` — fetch email + prefs, fix reject, přidán approve notif.
  • • `admin/leads/[id]/lead-detail-types.ts` — `notification_preferences` v seller typu
  • • `send-notification-email/index.ts` — šablona `lead_approved` (v14)
  • • `auto-approve-leads/index.ts` — seller dual-write notifikace (v2)
  • • `lib/supabase/types.ts` — `lead_review` v `NotificationPreferences`
  • • `profile/page.tsx` — UI řádek pro `lead_review` (seller sekce)
25. února 2026
  • UI: Vizuální odlišení přečtených vs nepřečtených notifikací
  • • `notification-bell.tsx` — tečka v popoveru: barevná (nepřečtená) → šedá (přečtená)
  • • `notifications/page.tsx` — tečka na stránce notifikací: stejná logika
  • Feature: Admin Lead Detail — property-type-aware zobrazení + editace
  • • `PropertyDetailsSection` — editace přímých DB sloupců podle property_type (disposition/ownership pro byt, house_category pro dům, land_category pro pozemek atd.)
  • • `PropertyParamsSection` — editace params JSONB: rozměry, PENB, stáří/rekonstrukce, omezení (radio + checkboxy), příslušenství (9 ks byt, 8 ks dům, 7 ks komerční), vlastnosti domu (6 ks)
  • • `lead-detail-types.ts` — sdílený `LeadDetail` interface + `PROPERTY_FIELD_CONFIG` centrální mapa
  • • Odstraněn JSON dump "Další parametry" (nahrazen strukturovaným zobrazením)
  • • Přidány lookup mapy v `constants.ts`: `AMENITY_LABELS`, `HOUSE_CHARACTERISTIC_LABELS`, `HOUSE_SIZE_LABELS`
  • • Fix: amber/orange barvy v admin lead detail (`getStatusBadge`, reject button/dialog) nahrazeny brand paletou
  • UI: Design konzistence — pending_review/rejected barvy sladěny s brand paletou
  • • `LEAD_STATUS_CONFIG` a `SELLER_LEAD_STATUS_CONFIG` — pending_review: `bg-[#f5f0ff] text-[#6039f6]`, rejected: `bg-[#ede5ff] text-[#220860]`
  • • `NOTIFICATION_CONFIG` — ikony `lead_pending_review` (#6039f6) a `lead_rejected` (#220860) místo amber/orange
  • • Seller lead detail — pending/rejected bannery v on-brand barvách
  • • Admin leads — badge barvy + pending alert banner v lavender tónech
  • • Odstraněny všechny amber/orange třídy z kontextu lead statusů
  • Fix: Lead INSERT selhal kvůli trigger type mismatch
  • • DB migrace: opravena funkce `notify_admin_pending_review()` — správné volání `create_notification()` s 6 argumenty (title, body, href, metadata)
  • • Nový helper `getErrorMessage()` (`lib/utils/error.ts`) — bezpečně extrahuje `.message` z `Error`, `PostgrestError` i stringů
  • • Nahrazeno ve 12 souborech (17 výskytů `err instanceof Error ? err.message : ...`)
  • • Přidán `Sentry.captureException()` pro lead submit
24. února 2026
  • Feature: Admin Review — schvalování poptávek (F22)
  • • `pending_review` — čeká na schválení adminem (seller může editovat)
  • • `rejected` — vráceno k přepracování s důvodem (seller edituje a resubmitne)
  • • DB migrace: CHECK constraint, sloupce `review_deadline`, `reviewed_by`, `reviewed_at`, `rejection_reason`
  • • UPDATE trigger `on_lead_approved_notify_brokers` — automatická notifikace brokerů při schválení
  • • INSERT trigger `on_lead_pending_review_notify_admin` — email + in-app adminu
  • • Edge Function `auto-approve-leads` v1 (CRON každou hodinu) — auto-schválení po 24h
  • • Edge Function `send-notification-email` v21 — 2 nové typy: `lead_pending_review`, `lead_rejected`
  • • Seller: lead se vytváří jako `pending_review` s `expires_at: null`, redirect na detail
  • • Seller detail: informační bannery (pending/rejected) s důvodem a tlačítkem na editaci
  • • Seller edit: guard pro pending_review/rejected, resubmit logika (rejected → pending_review)
  • • Seller leads: nový tab "Ke schválení" (pending + rejected leady)
  • • Admin leads: amber alert banner s počtem ke schválení, filtr pending_review/rejected
  • • Admin detail: zelené tlačítko "Schválit" + oranžové "Vrátit k přepracování" (AlertDialog s důvodem)
  • • Status badge: ikony Clock (pending) a RotateCcw (rejected)
  • • Audit log: akce `approve_lead`, `reject_lead`, `resubmit_lead`
  • • Constants: LEAD_STATUS_CONFIG, SELLER_LEAD_STATUS_CONFIG, NOTIFICATION_CONFIG rozšířeny
  • • TypeScript typy regenerovány z Supabase
  • • `expires_at = NULL` při vytvoření, nastaví se na NOW+30d při schválení
  • • `reviewed_by = NULL` = auto-approved (CRON), UUID = admin akce
  • • Brokeři nevidí pending/rejected leady (RLS + view `leads_for_brokers` WHERE status='active')
23. února 2026
  • UI: Gradient border přetéká přes zaoblené rohy karet
  • • Gradient top border (`absolute top-0 h-1`) přetékal přes zaoblené rohy Card na stránkách support, contact, admin/support
  • • Oprava: `overflow-hidden` na kartách bez dropdownů, `rounded-t-2xl` workaround na kartách s Select dropdowny
  • Fix: Report-sale a checkin-respond-web API vrací 401 "Nepřihlášen"
  • • API routes `/api/report-sale` a `/api/checkin-respond-web` používaly cookie-based auth (`@/lib/supabase/server`), ale session je v localStorage → vždy 401
  • • Oprava: Bearer JWT pattern (stejně jako `submit-rating`) — frontend posílá `Authorization: Bearer <token>`, API ho ověřuje přes `@supabase/supabase-js`
  • • Dotčené soubory: `api/report-sale/route.ts`, `broker/matches/[id]/page.tsx`, `api/checkin-respond-web/route.ts`, `components/checkin-banner.tsx`
  • Feature: Rok kolaudace a rekonstrukce v parametrech leadu
  • • **Rok kolaudace** (`year_built`) — rok první kolaudace/dokončení stavby (1800–aktuální rok)
  • • **Rok poslední rekonstrukce** (`year_reconstructed`) — volitelné
  • • **Rozsah rekonstrukce** (`reconstruction_scope`) — celková/částečná, zobrazí se jen pokud je vyplněn rok rekonstrukce
  • • Data uložena v `leads.params` JSONB (žádná DB migrace)
  • • Zobrazení: wizard krok 3 + shrnutí, seller/broker/admin detail, seller edit
  • • Nezobrazuje se pro pozemky a ostatní typy
  • UI: Vyčištění Card hover efektu
  • • Odebrán globální hover efekt z Card komponenty (`hover:shadow-xl hover:border-[#AF96FC]/50 hover:-translate-y-0.5`) — aplikoval se na všechny karty včetně formulářů a tabulek
  • • Odstraněn workaround `hover:shadow-none hover:-translate-y-0` z `empty-state.tsx`
  • • Klikatelné karty (lead cards, admin stat cards) mají vlastní hover efekty
  • Legal: Cross-reference audit právních dokumentů — 28 oprav
  • • **A1**: Lhůta odvolání sjednocena na 14 dní (VOP mělo 15, RS 14)
  • • **A2**: Definice Prodávajícího ve VOP rozšířena na FO/PO (RS už mělo oboje)
  • • **A3**: Fikce doručení sjednocena na 3. pracovní den + dual-channel (VOP mělo "okamžitě")
  • • **B1**: Google OAuth přidán do Privacy Policy (tabulka zpracovatelů + účel + přenos)
  • • **B2**: Mapy.cz/Seznam.cz přidán do Privacy Policy
  • • Mediační krok před soudem (čl. 19.2), Force Majeure (čl. 16.4)
  • • Lhůta kontaktování po Matchi 5 prac. dní (čl. 7.1.a), SLA odvolání 30 dní (čl. 12.2.c)
  • • Cross-property provize zúžena (čl. 6.5), přechodové pravidlo pro bidy (čl. 17.3)
  • • Cenový semafor — "vysoká/běžná/nízká cena" místo technických kódů (čl. 2.8, 10.1)
  • • Právo makléře na odpověď na hodnocení (čl. 11.4), progresivní sankce 150 % (čl. 14.5)
  • • Příklady pro okamžitou suspenzi (čl. 12.3), postoupení práv Provozovatele (čl. 19.8)
  • • Sjednocení lhůty, definic, fikce doručení (A1-A3), aktivní Match upřesněn (A4)
  • • Právo makléře na odpověď na hodnocení (čl. 9.7)
  • • 3 noví zpracovatelé (Google, Mapy.cz, support tickets) v sekcích 3.15-3.17 + tabulce 4.1
  • • Balancing testy u 6 oprávněných zájmů (3.3, 3.7, 3.9, 3.10, 3.13, 3.14)
  • • DPIA zmínka u Watchdog (3.7), souhrnná tabulka doby uchování (8.5)
  • • Notifikační preference pro sellery (2.1)
  • Legal: Komplexní revize právních dokumentů v2.0 (~40 změn)
  • • Nové definice: 2.13 Realizovaný obchod (vč. nepřímých převodů přes s.r.o.), 2.14 Skutečná prodejní cena (vč. vedlejších plnění), 2.15 Propojená osoba (5 kategorií)
  • • Registrace: souhlas→akceptace (GDPR konzistence), Propojené osoby v multi-account detekci
  • • Provize: 5.3 formy odměny (sníží/promine/jiná forma), 5.9 sporná prodejní cena, 5.10 námitka fakturace
  • • Vznik nároku: 6.5 provize z dalších nemovitostí (24 měsíců), 6.6 notifikace plomby + 7denní lhůta, 6.7 nepřímý převod = obchod, 6.8 lhůta 30 dní na fakturu
  • • Anti-bypass: 8.1.g zákaz identifikace adresy z anonymizovaných údajů, 8.2 temporal regime pro g), 8.5 trojnásobek→pětinásobek s odůvodněním, 8.6 Propojená osoba dle 2.15
  • • Monitoring: 9.2 automatické +12 měsíců při aktivní spolupráci, 9.4 7denní lhůta + neodpovězení = porušení
  • • Sankce: 2 nové řádky (neodpovězení check-in 10k, nadhodnocení 25k), obcházení 3x→5x
  • • Změny smlouvy: 17.4 ochrana aktivních matchů
  • • Závěrečná: 19.5 doručovací fikce 3. pracovní den + dual-channel, 19.8 promlčecí lhůta 10 let
  • • Nové definice: Úspěšný prodej, Aktivní Match, Rezervní nabídka, Opakované porušení
  • • Prodávající: odpovědnost za škodu, plná moc, 7denní check-in, re-posting, pre-existing relationships
  • • Makléři: zákaz využití pro kupující, self-dealing prohibition
  • • Match: 14denní fallback pro neúplné sloty, 7denní výběr, match cancellation při neodpovědi 14 dní
  • • Hodnocení: i po cancelled spolupráci, právo makléře na odpověď
  • • Odpovědnost: oddělené capy (broker provize-based, seller 50k CZK)
  • • Ukončení: 14 dní (ne 15), monitoring přežívá smazání
  • • Doručení: 3. pracovní den + dual-channel
  • • Data: IP adresa + user-agent, support tickety, retenční politika fotografií
  • • Účely: 3 nové (support tickets, Mapy.cz geokódování, Google OAuth)
  • • Balancing testy pro 4 oprávněné zájmy
  • • Zpracovatelé: oprava Supabase sídla (USA, data EU Frankfurt), přidáni Seznam.cz/Mapy.cz a Google
  • • Přeshraniční přenosy: Supabase a Google přidáni (SCCs + DPF)
  • • Práva: čl. 22 GDPR (automatizované rozhodování)
  • • Smazání účtu: rozšířená retenční politika + deleted_profiles popis
  • • Cookies: localStorage zmínka
  • • `LEGAL-TERMS-BROKER.md`, `LEGAL-TERMS.md`, `LEGAL-PRIVACY.md`
  • • `frontend/src/app/terms/broker/page.tsx`
  • • `PRAVNIK-BRIEF.md`, `ROADMAP.md`
19. února 2026
  • Fix: Shrnutí nového leadu — chybějící adresa a fotografie
  • • Adresa se nyní zobrazuje kompletní (ulice, město, PSČ), oblast zvlášť pokud se liší
  • • Přidány náhledy nahraných fotek (64×64px thumbnaily) s celkovým počtem
  • • Automaticky získaná data (parcela, LV, k.ú.) se záměrně nezobrazují — seller je nepotřebuje
  • • `app/seller/new-lead/step-5-summary.tsx` — plná adresa, foto náhledy
  • Fix: Prodloužení leadu — výpočet expirace + UX omezení
  • • `app/seller/leads/[id]/page.tsx` — oprava výpočtu, disabled logika, toast
  • • `app/api/extend-lead/route.ts` — konzistentní oprava výpočtu
  • Fix: Prodloužení leadu — auth mismatch (401 "Nepřihlášen")
  • • `app/seller/leads/[id]/page.tsx` — client-side extend s validací, RLS, audit log, analytics
  • Feat: Responsive Navbar — hamburger menu + user dropdown
  • • `components/ui/sheet.tsx` — shadcn Sheet (slide-out panel)
  • • `components/ui/dropdown-menu.tsx` — shadcn DropdownMenu
  • • `components/user-menu.tsx` — desktop dropdown (Profil, Podpora, Odhlásit)
  • • `components/mobile-nav.tsx` — mobilní hamburger Sheet
  • • `components/navbar.tsx` — responsivní layout s `md:` breakpointem, Bell vždy viditelný, CTA Registrovat vždy viditelná
  • • Desktop (md+) přihlášený: Logo | Dashboard | Podpora | Bell | [Jméno ▼]
  • • Mobil přihlášený: Logo | Bell | [☰] → Sheet
  • • Desktop nepřihlášený: Logo | Kontakt | Přihlásit | Registrovat
  • • Mobil nepřihlášený: Logo | Registrovat | [☰] → Sheet
  • Feat: Support Ticket System
  • • `app/api/support-ticket/route.ts` — vytvoření ticketu (anon + auth), rate limit 3/5min, emaily, audit log
  • • `app/api/support-ticket/reply/route.ts` — admin odpověď s emailem + in-app notifikací
  • • `app/contact/page.tsx` — veřejný kontaktní formulář s pre-fill pro přihlášené
  • • `app/support/page.tsx` — historie vlastních ticketů (auth required)
  • • `app/admin/support/page.tsx` — admin správa: filtry, sorting, CSV export, inline reply
  • • `lib/rate-limit.ts` — nový limit `supportTicket: 3/5min`
  • • `admin/layout.tsx` — "Podpora" v navigaci
  • • `admin/audit/page.tsx` — nové ACTION_LABELS + ENTITY_LABEL pro support tickety
  • • `components/navbar.tsx` — odkaz "Kontakt" pro nepřihlášené, "Podpora" pro přihlášené
  • • `app/page.tsx` — "Kontaktní formulář" ve footer sekci Kontakt
  • • Tabulka `support_tickets` s RLS, indexy, auto-update trigger
  • Fix: Konzistentní validace adresy ve wizardu
  • • `components/address-autocomplete.tsx` — nový `onManualChange` callback (reset odvozených dat při manuální editaci textu)
  • • `seller/new-lead/step-2-location.tsx` — pole Město/PSČ jsou readOnly (plní se z autocomplete), tlačítko "Pokračovat" vyžaduje souřadnice (lat/lng), varování při nezvolené adrese
  • Fix: Konzistentní validace plochy (size_m2) mezi wizard a editací
  • • `lib/utils/validation.ts` — `validateNumericInput()` (clamp v onChange), `isInRange()` (submit safety net)
  • • `lib/constants.ts` — `SIZE_LIMITS` konstanty + `getSizeLimits()` helper
  • • `seller/new-lead/step-3-parameters.tsx` — onChange validace na sizeM2/landAreaM2, dynamický max, disabled button kontrola
  • • `seller/new-lead/page.tsx` — submit safety net před insertem
  • • `seller/leads/[id]/edit/page.tsx` — onChange validace na všech sizeM2 inputech + landAreaM2, submit safety net
  • Feat: Google OAuth pro sellery (F17)
  • • `components/google-sign-in-button.tsx` — GoogleSignInButton komponenta (oficiální Google "G" ikona, loading/error state)
  • • `app/auth/callback/route.ts` — smart redirect (admin→/admin, neověřený→/auth/verify, ověřený→/dashboard)
  • • `app/auth/verify/page.tsx` — formulář pro zadání telefonu (Google OAuth seller nemá phone), dynamický popis dle stavu email verifikace
  • • `app/auth/login/page.tsx` — divider "nebo" + GoogleSignInButton pod formulářem
  • • `app/auth/register/seller/page.tsx` — GoogleSignInButton navrchu + divider "nebo vyplňte formulář"
  • • `handle_new_user()` — detekce Google providera (`raw_app_meta_data->>'provider'`), automaticky `role=seller`, `email_verified_at=NOW()`, parsování `full_name` na `first_name`/`last_name`
  • • Google provider zapnut (Client ID + Secret)
  • • Redirect URLs nastaveny (wildcard `/**`)
  • • Automatic Linking (výchozí chování Supabase)
  • • OAuth 2.0 Client (Web application) — 3 JS origins, 1 redirect URI
  • • App publikována (In production)
18. února 2026
  • Feat: OG image pro sociální sítě (F15 dokončeno)
  • Fix: Landing page — mobilní responsivita obrázků
  • • **Hero** — přidán druhý `<Image>` s `lg:hidden` pod text (desktop zachován absolutní pozicí)
  • • **WhySellersSection** — `order-last lg:order-first` místo `hidden lg:block`
  • • **HowItWorksSection** — odstraněn `hidden lg:block`, responzivní výšky
  • SEO: F5 dokončení — robots.txt, sitemap.xml, JSON-LD, Image optimalizace
  • • `public/robots.txt` — pravidla pro crawlery (Disallow: /admin, /api, /dashboard, /auth, /seller, /broker, /notifications, /checkin)
  • • `app/sitemap.ts` — statický sitemap (/, /privacy, /terms, /terms/broker, /changelog)
  • • Organization schema (OneManDev s.r.o., adresa, logo, email)
  • • WebSite schema (název, URL, jazyk)
  • • FAQPage schema (6 otázek z FAQ sekce)
  • • Nahrazeny raw `<img>` za Next.js `<Image>` ve 4 souborech (page.tsx, why-sellers-section, how-it-works-section, compare-section)
  • • Hero building: `priority={true}` pro LCP optimalizaci
  • • Automatický WebP + srcset pro všechny obrázky
  • • hero-building.png: "Moderní bytový dům s balkóny — prodej nemovitosti"
  • • compare-landscape.png: "Realitní makléři konzultují prodej nemovitosti"
  • • how-it-works.png: "Podání rukou při dohodě o prodeji nemovitosti"
  • • compare-house.png: "Rodinný dům — srovnání nabídek makléřů"
  • Security: Hardening — CRON auth, Next.js CVE, race conditions, IP spoofing, headers
  • • 3 CRON Edge Functions (`watchdog-check` v10, `expire-leads` v4, `checkin-send` v4) — přidán service_role_key auth check, deploy do produkce
  • • Next.js 16.0.7 → 16.1.6 — oprava known CVEs (DoS, source exposure)
  • • `checkin-respond` — atomic UPDATE (race condition) + `Referrer-Policy: no-referrer` (token leak)
  • • `verify-email` — rate limit 10/min + atomic UPDATE (race condition)
  • • `getClientIp()` helper — anti-spoofing IP extraction (x-real-ip preference, poslední IP z x-forwarded-for)
  • • 11 API routes aktualizováno na `getClientIp()`
  • • Security headers v `next.config.ts` — HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy
  • • Smazán legacy `backend/` adresář (nepoužívaný Python prototyp)
  • • `next.config.ts` — security headers + turbopack.root
  • • `lib/rate-limit.ts` — `getClientIp()`, `verifyEmail` preset
  • • `auth/verify-email/route.ts` — atomic update + rate limit
  • • `api/checkin-respond/route.ts` — atomic update + safeRedirect
  • • 10 dalších API routes — `getClientIp()` migration
  • • 6 test souborů — mock updates pro `getClientIp`
  • Content: Landing page SEO + faktická správnost
  • • `app/layout.tsx` — meta title, description, OG/Twitter tagy (SEO keywords "prodej nemovitosti")
  • • `app/page.tsx` — H1 s SEO keywords, hero popis, trust badges, copyright 2025→2026
  • • `components/landing/why-sellers-section.tsx` — H2, podtitulek, "zdarma" místo "platíte při úspěchu"
  • • `components/landing/how-it-works-section.tsx` — H2 se SEO keywords, kroky bez "500m" a "z okolí"
  • • `components/landing/compare-section.tsx` — H2, features (jen % provize, semafor popis)
  • • `components/landing/for-brokers-section.tsx` — provize specifikována (20 %)
  • • `components/landing/testimonial-section.tsx` — fiktivní testimonial nahrazen value proposition kartami
  • • `components/landing/faq-section.tsx` — semafor opraven, min. provize 5 000 Kč, poloha nemovitosti
  • • `components/hero-buttons.tsx` — CTA text, link na /auth/register/seller
  • • Cenový semafor: zelený/žlutý/červený → štítky Vysoká/Nízká cena
  • • "% vs. fixní" provize → jen procentuální
  • • "Platíte až při úspěchu" → prodávající neplatí vůbec
  • • "Makléři z okolí/regionu" → odstraněno (makléř se může přihlásit odkudkoli)
  • • "Až 5 nabídek" → "5 nabídek" (odemknou se při 5)
  • • Fiktivní testimonial "Jan N." → 3 karty (5 nabídek, 0 Kč, ověření makléři)
  • • Copyright 2025 → 2026
  • • Minimální provize 5 000 Kč bez DPH doplněna do FAQ
16. února 2026
  • Fix: Match inline select — validace state machine
  • • `app/admin/matches/page.tsx` — přidána `VALID_TRANSITIONS` mapa, validace v `handleStatusChange`, filtr v `<SelectContent>`
  • • Nová konstanta `VALID_TRANSITIONS` definuje povolené přechody pro každý stav
  • • `handleStatusChange` validuje přechod před UPDATE — nevalidní odmítne s toast chybou
  • • `<SelectContent>` zobrazuje jen aktuální stav + validní cíle (finální stavy jsou readonly)
  • Testing Matrix — Kompletní testovací matice
  • • `TESTING-MATRIX.md` — kompletní testovací matice v markdown (16 sekcí, 471 test casů)
  • • `TESTING-MATRIX.csv` — CSV export pro Excel/Google Sheets (UTF-8 BOM, středníky)
  • F1: Právní dokumenty v2.0
  • • `app/terms/page.tsx` — Podmínky služby v2.0 (16 sekcí, definice, pravidla, match, monitoring, hodnocení, suspenze, spory)
  • • `app/terms/broker/page.tsx` — Rámcová smlouva pro makléře v2.0 (19 sekcí, provize 20%, anti-bypass, sankce, watchdog, check-in)
  • • `app/privacy/page.tsx` — Zásady ochrany osobních údajů v2.0 (13 sekcí, 14 účelů zpracování, GDPR práva, zpracovatelé, třetí země)
  • • `LEGAL-TERMS.md` — zdrojový markdown Podmínek služby
  • • `LEGAL-TERMS-BROKER.md` — zdrojový markdown Rámcové smlouvy
  • • `LEGAL-PRIVACY.md` — zdrojový markdown Zásad ochrany osobních údajů
  • • `PRAVNIK-BRIEF.md` — aktualizovaný podklad pro právníka (9 sekcí, 33 otázek)
  • • Odstraněn warning banner „Toto je pracovní verze smlouvy" z broker terms
  • • Cross-linky mezi dokumenty (VOP → Rámcová smlouva → Privacy)
  • • Tabulka sankcí (obcházení 100k Kč / 3x provize, nepravdivý check-in 50k Kč)
  • • Tabulka zpracovatelů (Supabase IE, Hetzner DE, Resend US, Vonage NL, Sentry US)
  • • SCCs/DPF pro přenosy do USA (Resend, Sentry)
  • • ČOI + ODR odkaz pro spotřebitele, ÚOOÚ kontakt
  • F18: Admin 2FA (TOTP)
  • • `hooks/useMfa.ts` — centralizovaný MFA hook (enroll, verify, unenroll, AAL check)
  • • `app/auth/mfa-verify/page.tsx` — verifikační stránka po loginu (6-ciferný OTP, auto-submit)
  • • `app/auth/mfa-setup/page.tsx` — 3-krokový setup wizard (instrukce → QR kód → ověření)
  • • `components/mfa-setup-section.tsx` — 2FA správa v profilu (setup/unenroll dialogy)
  • • `hooks/useAuthGuard.ts` — nová `requireMfa` option, async KONTROLA 3.5 (AAL level + listFactors)
  • • `app/admin/layout.tsx` — zapnuto `requireMfa: true`
  • • `app/auth/login/page.tsx` — admin redirect na `/admin` (useAuthGuard zachytí MFA)
  • • `app/profile/page.tsx` — MfaSetupSection v tabu Účet (pouze admin)
  • • `app/admin/audit/page.tsx` — 4 nové audit labels (mfa_enroll/unenroll/verify_success/verify_failed)
  • • `hooks/index.ts` — export useMfa
  • Refaktoring: Dead code cleanup
  • • `leads.extra_slots_unlocked` — nikdy implementovaný mechanismus 5+2 slotů
  • • `leads.floor_plan_url` — nikdy implementovaný upload půdorysu
  • • `bids.proof_description` — nikdy implementovaný popis důkazu
  • • `matches.invoice_generated` — odložená Fakturoid integrace
  • • `seller_leads_summary` VIEW — nikde nedotazovaný
  • • `hooks/useFetchData.ts` — nikdy importovaný hook
  • • `app/api/notifications/route.ts` — nepoužívaná API route (frontend dotazuje Supabase přímo)
  • • `components/ui/form.tsx` — nepoužívaný shadcn Form wrapper
  • • `proxy.ts` — staging proxy bez middleware
  • • 9 mrtvých exportů z constants.ts (ENERGY_RATING_LABELS, ENCUMBRANCE_VALUES, NETWORK_LABELS aj.)
  • • 5 mrtvých type aliasů z types.ts (Match, CheckinToken, BrokerRating aj.)
  • • `validateParams()` z api.ts, `notifications` rate limit
  • • 6 console.log v useAuthGuard.ts nahrazeno komentáři
  • • Autogenerované TypeScript typy synchronizovány se Supabase
13. února 2026
  • Refaktoring: New-lead wizard split
  • • `types.ts` — FormData, StepProps, INITIAL_FORM_DATA
  • • `step-1-property-type.tsx` — výběr typu nemovitosti
  • • `step-2-location.tsx` — adresa / mapa + katastr
  • • `step-3-parameters.tsx` — parametry per typ nemovitosti
  • • `step-4-photos.tsx` — upload fotek interiér/exteriér
  • • `step-5-summary.tsx` — shrnutí + čestné prohlášení
  • Feat: F16 — Export CSV z admin tabulek
  • • `lib/csv-export.ts` — utilita: BOM pro Excel, středník jako oddělovač, escapování
  • • `components/csv-export-button.tsx` — reusable tlačítko s Download ikonou
  • • `__tests__/utils/csv-export.test.ts` — 16 testů (escapování, BOM, formátování, edge cases)
  • Feat: F13 — Hodnocení makléřů
  • • `/seller/rate/[matchId]` — formulář s 4 sekcemi (povinné hvězdy + doporučení, volitelné kategorie, kontextové otázky z nabídky, komentář max 500 znaků)
  • • `/admin/ratings` — tabulka s moderací (schválit/zamítnout), filtry dle statusu, rozbalitelné detaily
  • • `star-rating.tsx` — interaktivní star picker (1-5 hvězd, brand barvy)
  • • CTA banner v seller lead detailu "Ohodnoťte svého makléře"
  • • DB tabulka `broker_ratings` s RLS (seller insert/select, admin select/update, broker select approved)
  • • API `/api/submit-rating` s rate limitingem, validací, audit logem
  • • Edge Function `send-notification-email` v20 — nový typ `rating_request`
  • • Trigger v `handleConfirmSale()` — email + in-app notifikace sellerovi
  • Feat: F19 — Detekce duplicitních leadů
  • • Stejná parcela + stejná (nebo obě prázdná) jednotka → blokace s odkazem na existující poptávku
  • • Stejná parcela + různá jednotka → projde (jiná nemovitost)
  • • Bez parcelního čísla → kontrola se přeskakuje
  • • Kontrola v `handleSubmit()` přímým Supabase dotazem (RLS, žádný nový API endpoint)
  • • UI blok s informací a tlačítkem na existující poptávku
  • • DB partial index `idx_leads_duplicate_check` pro rychlé vyhledávání
  • Feat: F11 — Pokročilé filtry leadů pro makléře
  • • Typ nemovitosti — badge toggle buttons (Vše + 5 typů, klik na vybraný zruší)
  • • Subkategorie — kontextový Select (byt→dispozice, dům→kategorie, pozemek→kategorie...)
  • • Stav nemovitosti — Select (novostavba, po rekonstrukci, před rekonstrukcí...)
  • • Plocha m² — dva Input pole (od/do) s debounce 300ms
  • • Řazení — Select (nejnovější, brzy vyprší, málo slotů, největší plocha)
  • • Export `getLeadSubcategory` z `lead-card.tsx` (bylo privátní)
  • • Fix `parseLeadParams` — přidáno parsování `rooms`
  • • Tab počty se počítají z `advancedFilteredLeads` (ne z `locationFilteredLeads`)
  • • "Zrušit filtry" resetuje všechny filtry včetně nových
  • • Counter "X z Y" reflektuje aktuální filtrovaný+seřazený stav
12. února 2026
  • Fix: In-app notifikace se nezobrazovaly
  • • `hooks/useNotifications.ts` — fetch() nahrazen primymi Supabase dotazy, hook prijima `supabase` klienta jako parametr
  • • `components/notification-bell.tsx` — pridan import `useAuth`, predava `supabase` do hooku
  • • `app/notifications/page.tsx` — vsechny fetch() nahrazeny primymi Supabase dotazy pres `useAuthGuard().supabase`
  • Feat: F9 — Audit Log
  • • Nova tabulka `audit_logs` (UUID PK, user_id, user_role, action, entity_type, entity_id, changes JSONB, metadata JSONB)
  • • RLS: admin-only cteni, authenticated INSERT (user_id = auth.uid() nebo NULL)
  • • 4 indexy: created_at DESC, action, (entity_type, entity_id), user_id
  • • `lib/audit.ts` — `logAuditAction()` fire-and-forget (nikdy neblokuje UX)
  • • Admin: suspend_user, unsuspend_user, change_role, delete_user, confirm_sale, issue_invoice, record_payment, cancel_match, revert_to_watching, approve_sale_report, reject_sale_report, change_match_status
  • • Broker: report_sale, submit_bid, checkin_respond
  • • Seller: create_lead, create_match, extend_lead
  • • `/admin/audit` — filtry (akce, entita, uzivatel, datum od-do), razeni, paginace
  • • Rozbalitelne radky s detailem zmen a metadat
  • • Badge barvy podle role (admin fialova, broker modra, seller seda, system seda)
  • • Navigacni odkaz v admin sidebar (ScrollText ikona)
  • Feat: F15 (částečně) + F5 (OG tagy) — Umami Analytics + Open Graph
  • • **Cookieless tracking** — GDPR bez consent banneru, žádné cookies
  • • **Podmíněné načtení** — `<Script>` se renderuje pouze pokud jsou nastaveny `NEXT_PUBLIC_UMAMI_URL` + `NEXT_PUBLIC_UMAMI_WEBSITE_ID`
  • • **5 custom events** (konverzní body):
  • • **`trackEvent()` utilita** (`lib/utils/analytics.ts`) — production-only, v dev loguje do konzole, fire-and-forget
  • • **UTM parametry** — Umami trackuje automaticky (utm_source, utm_medium, utm_campaign)
  • • `metadataBase`, `openGraph`, `twitter` metadata v layout.tsx
  • • Title: "Správný Makléř – Nechte makléře soutěžit o vaši nemovitost"
  • • Description: "Zadejte nemovitost zdarma a získejte až 5 nabídek od ověřených makléřů."
  • • OG image placeholder: `og-image.png` (1200×630, zatím nutno vytvořit manuálně)
  • UX: Sloučení notifikačních karet v profilu makléře
  • • **Collapsible panel** — řádek "Nové poptávky v oblasti" je klikatelný, rozbalí výběr krajů přímo pod sebou
  • • **RadioGroup** — přepínač "Všechny kraje" / "Vybrané kraje" s grid checkboxů 14 krajů
  • • **Dynamický popisek** — pod-text řádku zobrazuje aktuální stav ("Všechny kraje" nebo "Vybrané kraje (N)")
  • • **Disabled stav** — panel krajů se deaktivuje pokud jsou oba kanály (email + in-app) vypnuté
  • • **Beze změny backendu** — `preferred_regions` se ukládá stejně jako dosud
11. února 2026
  • Feat: Granulární notifikační preference (JSONB matice)
  • • **6 typů notifikací**: Nové poptávky, Match, Potvrzení prodeje, Check-in, Nabídky připraveny, Expirace poptávky
  • • **2 kanály**: Email + In-app — každý typ lze nezávisle zapnout/vypnout
  • • **Opt-out model** — výchozí stav je "vše zapnuto", uživatel vypíná co nechce
  • • **Zamčené in-app** — operační notifikace (match, check-in) mají in-app vždy zapnutý
  • • **Backend respektuje preference**: 3 SQL trigger funkce, Edge Functions `expire-leads` v3 + `checkin-send` v3, admin match detail
  • • **Zpětná kompatibilita** — staré sloupce se stále zapisují paralelně
  • • **Admin panel** — zobrazení JSONB preferencí v detailu uživatele
  • Fix: Staging password loop po přihlášení
  • • **Nahrazení HTTP Basic Auth za cookie-based ochranu** — `proxy.ts` nyní kontroluje HttpOnly cookie `staging_access` (SHA-256 hash hesla)
  • • **Nová stránka `/auth/staging`** — formulář na zadání staging hesla s brand designem
  • • **Nový API endpoint `/api/staging-auth`** — ověří heslo, nastaví cookie (30 dní, HttpOnly, SameSite=Lax)
  • • Cookie se posílá automaticky na všechny requesty (fetch, SSR, navigace) → žádná smyčka
  • Feat: F12 — In-app notifikace (zvoneček + dual-write)
  • • **DB**: Tabulka `notifications` s RLS (select_own, update_own, insert_authenticated)
  • • **SQL funkce `create_notification()`** (SECURITY DEFINER) — volatelná z Edge Functions i API routes
  • • **Hook `useNotifications`** — polling 60s, mark as read, mark all as read
  • • **Komponenta `NotificationBell`** — zvoneček v navbaru s badge nepřečtených, popover dropdown s posledními 10 notifikacemi
  • • **API `/api/notifications`** — GET (paginated, filtr unread_only) + PATCH (mark read: single ID nebo all)
  • • **Stránka `/notifications`** — kompletní seznam, seskupení po dnech (Dnes/Včera/Starší), filtr nepřečtené
  • • **Dual-write retrofit**: `send-notification-email` v16 — po odeslání emailu i `create_notification()` RPC
  • • **Dual-write**: report-sale (admin notifikace), watchdog-check (admin alert), expire-leads (seller upozornění)
  • • **Integrace do navbaru** — NotificationBell mezi Dashboard linkem a jménem uživatele
  • Feat: F10 — Match check-in systém (3-měsíční dotazník obou stran)
  • • **DB**: Tabulka `checkin_tokens` (tokenizované 1-click odpovědi) + sloupce v matches (last_checkin_at, next_checkin_at, checkin_round, checkin_status)
  • • **Edge Function `checkin-send`** v1 (CRON denně 9:00 UTC) — query matches kde `next_checkin_at <= NOW()`, email + in-app notifikace obou stran
  • • **Email šablony**: `checkin_broker`, `checkin_seller`, `checkin_reminder` — 3 CTA tlačítka (Probíhá / Prodej dokončen / Problém)
  • • **API `/api/checkin-respond`** — token-based 1-click odpověď z emailu (bez přihlášení, GET s redirect)
  • • **API `/api/checkin-respond-web`** — auth-based odpověď z webové aplikace (POST s JWT)
  • • **Vyhodnocovací logika**: obě "ongoing" → ok; obě "completed" → nahlásit prodej; nesoulad → red_flag + admin notifikace
  • • **Upomínka**: 14 dní bez odpovědi → reminder email; 2+ neodpovědí → red flag
  • • **Komponenta `CheckinBanner`** — brand card s gradient border, 3 tlačítka, success stav
  • • **Integrace**: broker match detail (`/broker/matches/[id]`) + seller lead detail (`/seller/leads/[id]`)
  • • **Stránka `/checkin/success`** — potvrzení po odpovědi z emailu + "strašák" monitoring katastru
  • • **Admin UI**: check-in sloupec v tabulce matchů (ok/pending/red_flag badge), red flag filtr, check-in historie v match detailu (tabulka odpovědí)
  • Feat: F4 — Sentry integrace (error tracking)
  • • **Client**: Zachytává JS errory v prohlížeči, Session Replay (100% sessions s errorem)
  • • **Server**: API routes, Server Components, server actions
  • • **Edge**: Middleware errory
  • • `global-error.tsx` — React error boundary pro App Router
  • • `instrumentation.ts` — registrace Sentry pro Node.js a Edge runtime
  • • `next.config.ts` — `withSentryConfig` wrapper, auto-instrumentace
  • • Build přepnut na webpack (`next build --webpack`) — Turbopack má bug s `node:inspector` v názvu chunku na Windows
  • • Sentry posílá data pouze v produkci (`enabled: process.env.NODE_ENV === "production"`)
  • Fix: F3 — Account Deletion Cleanup (kritický bug fix)
  • • **KRITICKÝ BUG FIX**: `auth.admin.deleteUser()` spouštělo CASCADE chain (auth.users → profiles → leads/bids/matches), čímž mazalo veškerá data včetně matchů a faktur
  • • Nahrazeno za **ban + anonymizaci**: `updateUserById()` s ban_duration ~100 let + anonymizace emailu
  • • **Broker**: Nelze smazat s aktivními matchi (watching/sold/invoiced) — vrací ACTIVE_MATCHES error s počtem a detaily
  • • **Seller**: Automatické zrušení aktivních leadů (→ cancelled) + odmítnutí pending bidů (→ rejected)
  • • **Rozšířená anonymizace**: nově i first_name, last_name, bank_account, office_*, network_*, verifikační pole, terms_*
  • • Smazání broker_service_profiles při mazání brokera
  • • DB migrace: rozšíření `account_deletion_audit` o first_name, last_name, bank_account, leads_cancelled, bids_rejected
  • • Role-specific popis v delete dialogu (broker vs seller)
  • • Upozornění pro brokery o blokaci při aktivním spárování
  • • Parsování ACTIVE_MATCHES chyby z Edge Function s detailní zprávou
  • Feat: F6 — Potvrzovací dialog před odesláním nabídky
  • • Validace formuláře (suspended check, služby) → otevření dialogu místo přímého odeslání
  • • Rekapitulace: odhadovaná cena, provize (%), služby (badge tagy), další služby, zpráva (zkrácená na 100 znaků)
  • • Tlačítka "Zpět k úpravám" a "Odeslat nabídku"
  • • Doplňuje F2 (race condition ochrana) — poslední šance zkontrolovat údaje před INSERT
  • Feat: F2 — Race condition ochrana nabídek (BEFORE INSERT trigger)
  • • **`check_bid_limits()`** — kontrola `max_bids` limitu a stavu leadu před vložením nabídky
  • • **`FOR UPDATE` lock** na řádku leadu → atomická kontrola (serializuje souběžné INSERTy)
  • • Kontrola stavu leadu (musí být `active`) — custom ERRCODE `P0001`
  • • Počítání pouze ne-rejected bidů proti limitu — custom ERRCODE `P0002`
  • • `SECURITY DEFINER` + `SET search_path = public`
  • • Rozlišení chybových hlášek: neaktivní lead, plný lead, duplicitní nabídka
  • • Re-fetch lead dat po chybě (aktualizace UI při změně stavu)
  • • Kontrola slotů: pokud `bid_count >= max_bids` → "Všechna místa obsazena" místo formuláře
9. února 2026
  • Remove: Testing banner odebrán z layoutu
  • Feat: Floating navbar + windowed landing page layout
  • • Zaoblené rohy (`rounded-2xl`), brand purple shadow, border
  • • Responsivní margins (`mx-4 sm:mx-6 lg:mx-8`), max šířka `max-w-7xl`
  • • Sticky s odsazením od vrchu (`top-3 mt-3`)
  • • Backdrop blur efekt zachován
  • • Všechny sekce mají shodné margins a max-width jako navbar
  • • Barevné sekce (Hero, HowItWorks, ForBrokers, Testimonial, CTA, Footer) se zaoblenými rohy
  • • Footer s větším vnitřním paddingem pro lepší čitelnost
  • Fix: Chybějící soubory v git repo (Coolify build fail)
  • Fix: Dropdown adresního našeptávání oříznutý v profilu
  • Feat: Role přesunuta z pruhu do navbaru
  • • Jméno uživatele + role s barevnou tečkou
  • • Na mobile jen křestní jméno
  • • Klik vede na profil
  • • Smazána komponenta `role-indicator.tsx`
  • Feat: České skloňování křestních jmen (5. pád / vokativ)
  • • Heuristická pravidla pro 5. pád českých křestních jmen (bez externích závislostí)
  • • Pokrytá pravidla: -a→-o (Jana→Jano), -ek→-ku (Marek→Marku), -ch→+u (Vojtěch→Vojtěchu), sykavky +i (Tomáš→Tomáši), -k→-ku (Patrik→Patriku), tvrdé souhlásky +e (Michal→Michale)
  • • Nepravidelné tvary: Petr→Petře, Pavel→Pavle, Karel→Karle, Zdeněk→Zdeňku
  • • Neměnné koncovky: -ie (Marie), -í (Jiří), -o (Hugo), -e (René)
  • • Cizí a neznámá jména zůstávají beze změny (fallback)
  • • Zachování velikosti písmen (PETR→PETŘE, petr→petře)
  • • 46 nových testů (mužská, ženská, cizí jména, edge cases)
  • • Celkem: **164 testů v 14 suites**
  • Feat: Brand design refresh — kompletní migrace barev na brand paletu
  • • **28+ stránek** — admin, auth, broker, seller, profil, dashboard, landing
  • • **4 komponenty** — button, card, bid-comparison-table, lead-card
  • • **1 config** — constants.ts (status badges, PENB barvy)
  • • **Button**: nový `lavender` variant (`bg-[#AF96FC]`) pro auth a sekundární akce
  • • **Card**: `rounded-2xl`, `shadow-md shadow-[#6039f6]/5`, lepší hover efekty
  • • **Auth layout wrapper** (`auth-layout.tsx`) — reusable gradient pozadí pro 6 auth stránek
  • • **Seller wizard stepper** — gradient kroužky, checkmark ikony, scale animace, smooth progress bar
  • • **Layout** — `min-h-[calc(100vh-4rem)]` fix pro správné pozicování footeru
  • • Active/Success: `bg-[#e0d5f5] text-[#220860]` (místo green)
  • • Error messages: `bg-[#f5f0ff] border-[#220860]/10 text-[#220860]` (místo red)
  • • Warning/Info: `bg-[#f5f0ff] border-[#e0d5f5]` (místo amber/yellow)
  • • PENB A-B: `#6039f6`, C: `#AF96FC`, D-G: `#220860` s klesající opacitou
6. února 2026
  • Feat: Provizní a fakturační systém
  • • `invoice_number` — číslo faktury (reference na externí systém)
  • • `invoice_issued_at` — datum vystavení faktury
  • • `invoice_due_date` — datum splatnosti
  • • `invoice_paid_at` — datum zaplacení
  • • `actual_commission_percent` — skutečná provize makléře (pokud se liší)
  • • `sale_confirmed_at` — datum potvrzení prodeje adminem
  • • `admin_notes` — poznámky admina
  • • `broker_response_deadline` — deadline pro reakci makléře
  • • **Časová osa** — 5 kroků: spárováno → prodáno → potvrzeno → fakturováno → zaplaceno
  • • **Info sekce** — nemovitost, kontakty stran (vč. emailů), nabídka makléře
  • • **Prodej** — detekce plomby, potvrzení prodeje, editace prodejní ceny
  • • **Fakturace** — live výpočet provize (20 % z nabídkové, min. 5 000 Kč + DPH 21 %)
  • • **Akční tlačítka** — kontextová dle stavu (Potvrdit prodej, Vystavit fakturu, Zaznamenat platbu, Zrušit)
  • • **Poznámky** — interní poznámky admina
  • • Řádky klikací → odkaz na detail stránku
  • • Nový sloupec "Faktura" (číslo + ikona stavu platby/splatnosti)
  • • **`sale_confirmed`** — výzva makléři po potvrzení prodeje adminem (dynamický předmět, deadline 14 dní, nabídková cena)
  • • **`payment_reminder`** — upomínka o neuhrazené faktuře (číslo, částka, dny po splatnosti, varování o suspenzi po 30 dnech)
  • • Přesný provizní vzorec s příkladem výpočtu
  • • Pravidla pro smlouvu (7 bodů)
  • • Povinnosti makléře + sankce (nenahlášení, nepravdivé údaje, neuhrazení)
  • • Informační klauzule o monitoringu katastru (veřejný registr, souhlas nepotřeba)
  • • Business proces (7 kroků s lhůtami)
27. ledna 2026
  • Fix: Error handling - toast notifikace na zbývajících 9 místech
  • • `fetchProfile` — Supabase error po vyčerpání retries → "Nepodařilo se načíst profil. Zkuste obnovit stránku."
  • • `fetchProfile` — neočekávaná výjimka → "Nepodařilo se načíst profil. Zkuste obnovit stránku."
  • • `signOut` — chyba při odhlášení → "Chyba při odhlašování."
  • • `fetchData` — načtení sítí selhalo → "Nepodařilo se načíst sítě."
  • • `toggleNetworkActive` — přepnutí stavu → "Nepodařilo se změnit stav sítě."
  • • `deleteNetwork` — smazání sítě → "Nepodařilo se smazat síť."
  • • `rejectCustomNetwork` — zamítnutí → "Nepodařilo se zamítnout síť."
  • • `fetchUsers` — načtení uživatelů → "Nepodařilo se načíst uživatele."
  • • `fetchMatches` — načtení spárování → "Nepodařilo se načíst spárování."
  • • `getSession` error — uživatel je přesměrován na login
  • • Init error / timeout — fallback na `unauthenticated` funguje
26. ledna 2026
  • Feat: Kontrola duplicitního telefonu při registraci
  • • **Partial UNIQUE index** na `profiles.phone` (WHERE phone IS NOT NULL)
  • • Vyčištěny existující duplicity (8+2 účtů se sdíleným telefonem)
  • • **POST `/api/check-availability`** - kontrola dostupnosti telefonu
  • • **Seller + Broker** - phone check před `supabase.auth.signUp()`
  • • Pokud telefon obsazen → chybová hláška "Tento telefon je již registrován"
  • • Pokud API selže → pokračuje (DB UNIQUE constraint je safety net)
  • • **8 nových testů** v `__tests__/api/check-availability.test.ts`
  • Feat: Pozastavení účtu (Admin Suspension)
  • • Nové sloupce v `profiles`: `status` ('active'/'suspended'), `suspension_reason`, `suspended_at`, `suspended_by`
  • • CHECK constraint na status
  • • Partial index `idx_profiles_status` (WHERE status != 'active')
  • • **`is_user_active(user_id)`** - SECURITY DEFINER helper funkce
  • • RLS INSERT policies na `bids` a `leads` rozšířeny o `AND is_user_active(auth.uid())`
  • • `get_users_with_email()` rozšířena o `status` a `suspended_at`
  • • **User detail** (`/admin/users/[id]`):
  • • **Users list** (`/admin/users`):
  • • **useAuthGuard** - nový flag `isSuspended` (admin role vyjmuta)
  • • **Dashboard** - varovný banner (červený gradient) pokud pozastaven
  • • **Broker bid submit** - blokace odeslání nabídky + disabled tlačítko
  • • **Seller new lead** - blokace vytvoření poptávky + disabled tlačítko
  • • **`/auth/suspended`** (nová stránka) - info o pozastavení, důvod, kontakt, odhlášení
  • • Rozšířeny typy `Profile` (Row/Insert/Update) o suspension pole
  • • Nová funkce `is_user_active` ve Functions typech
  • Admin: Sorting + Pagination na všech admin tabulkách
  • • **`hooks/useAdminTable.ts`** - generický hook pro sorting + pagination stav
  • • **`hooks/useDebounce.ts`** - debounce pro search inputy (300ms default)
  • • **`components/sortable-table-head.tsx`** - klikatelný TableHead se sort ikonami
  • • **`components/table-pagination.tsx`** - paginační ovládání pod tabulkou
  • • **Users** - sortovatelné: Jméno, Role, Firma, Registrace + debounced search
  • • **Leads** - sortovatelné: Typ, Město, Prodávající, Stav, Nabídky, Vytvořeno
  • • **Bids** - sortovatelné: Odhad ceny, Provize, Stav, Datum; odstraněn ADMIN_PAGE_LIMIT
  • • **Matches** - sortovatelné: Datum, Odhad ceny, Provize, Stav prodeje; odstraněn ADMIN_PAGE_LIMIT
  • • `DEFAULT_ADMIN_PAGE_SIZE = 20` (nová)
  • • `ADMIN_PAGE_LIMIT` ponechán pro zpětnou kompatibilitu
  • 🧹 ESLint: Oprava všech 80 problémů (6 errors + 74 warnings)
  • • `bid-comparison-table.tsx` — `set-state-in-effect` → lazy useState initializer (nahrazuje useEffect)
  • • `photo-lightbox.tsx` — `set-state-in-effect` → "adjusting state during render" pattern
  • • `price-input.tsx` — `set-state-in-effect` → displayValue odvozeno přímo z prop (bez useState/useEffect)
  • • `useAuthGuard.ts` — `set-state-in-effect` (2×) → eslint-disable (redirect flag potřebuje useState pro rendering)
  • • ~45× `import/order` — automaticky opraveno (`eslint --fix`)
  • • 9× nepoužívané proměnné/importy odstraněny
  • • 7× `no-img-element` → eslint-disable (lightbox/upload blob URL)
  • • 1× `alt-text` → přejmenování Lucide `Image` → `ImageIcon`
  • • 2× `exhaustive-deps` → eslint-disable
  • • 1× `import/no-duplicates` → eslint-disable-line (leaflet namespace import)
  • • 2× nepoužívané props odstraněny z `CollapsibleCategorySection`
  • • 1× TypeScript fix admin/bids (Supabase relace jako pole → transformace broker i lead)
  • ⚡ Code Quality Overhaul - Komplexní audit a hardening (17 úkolů ve 4 fázích)
  • 🔒 ZÁSADNÍ: Security Hardening
  • • **Problém**: `/api/test-watchdog` bez jakékoliv autentizace - kdokoli mohl volat ČÚZK API
  • • **Řešení**: JWT token + admin role kontrola přes Supabase server client
  • • Soubor: `frontend/src/app/api/test-watchdog/route.ts`
  • • **Problém**: `watchdog-check` Edge Function posílala `service_role_key` jako Bearer token přes HTTP
  • • **Řešení**: Přímé volání Resend API místo HTTP volání `send-notification-email`
  • • Soubor: `supabase/functions/watchdog-check/index.ts`
  • • Přidáno do `.gitignore`: `tmpclaude-*`, `nul`, `frontend/nul`, `frontend/tmpclaude-*`
  • • Smazáno 29 dočasných souborů z repozitáře
  • • **Nový soubor**: `frontend/src/lib/rate-limit.ts` - in-memory sliding window
  • • Aplikováno na 5 API routes:
  • • Automatický cleanup paměti každých 5 minut
  • 🔒 ZÁSADNÍ: CI/CD Pipeline (z 0/10 na funkční)
  • • **Nový soubor**: `.github/workflows/ci.yml`
  • • Pipeline: `npm ci → eslint → tsc --noEmit → vitest → next build`
  • • Spouští se na push a PR do master
  • • Husky s monorepo setupem (`.git` v root, `package.json` ve `frontend/`)
  • • lint-staged: `eslint --fix` na staged `.ts/.tsx` soubory
  • • Soubor: `frontend/.husky/pre-commit`
  • 🔒 ZÁSADNÍ: Testing (z 0/10 na funkční)
  • • **Nový soubor**: `frontend/vitest.config.ts`
  • • **3 test suites**:
  • • **Extrakce**: IČO validace do sdíleného modulu `lib/utils/ico-validation.ts`
  • Error Handling
  • • `map-picker.tsx` - 2× `.catch(() => ({}))` → `toast.error()`
  • • `seller/new-lead/page.tsx` - LV lookup → `toast.error()`
  • • `profile/page.tsx` - loading networks/templates → `toast.error()`
  • • `admin/matches/page.tsx` - `alert()` → `toast.error()`
  • • Odstraněn debug `console.log` z `test-watchdog/route.ts`
  • Refactoring
  • • **Nový soubor**: `frontend/src/hooks/useFetchData.ts`
  • • Nahrazuje opakující se `useState + useEffect` pattern
  • • Exportován z `hooks/index.ts`
  • • `ANONYMIZE_RADIUS_M = 500` (geo.ts)
  • • `PARCEL_ZOOM_THRESHOLD = 17` (map-picker.tsx)
  • • `COMPRESSION_THRESHOLD = 300 * 1024` (photo-upload.tsx)
  • • `ADMIN_PAGE_LIMIT = 100` (admin stránky)
  • • Soubor: `frontend/src/lib/constants.ts`
  • • `zod` 4.1→4.3, `@supabase/supabase-js` 2.86→2.91, `@types/node` v20→v25
  • • 5 nových indexů pro optimalizaci RLS a častých queries:
  • Polish
  • • `map-picker.tsx` - `role="region" aria-label="Mapa pro výběr lokace nemovitosti"`
  • • `lead-location-map.tsx` - `role="region" aria-label="Mapa s přibližnou polohou nemovitosti"`
  • • **Nový soubor**: `frontend/.prettierrc`
  • • Přidáno: `eslint-config-prettier`, `eslint-plugin-import`
  • • Import sorting pravidla (groups, no duplicates)
  • • Prettier: `semi: true`, `singleQuote: false`, `printWidth: 100`
  • • Nahrazen manuální auth kód za `useAuthGuard({ allowedRoles: ["admin"] })`
  • • Soubor: `frontend/src/app/admin/layout.tsx`
  • • Nahrazen `return params as LeadParams` za field-by-field validaci
  • • Numerické, stringové a boolean pole validovány individuálně
  • • Soubor: `frontend/src/lib/supabase/types.ts`
24. ledna 2026
  • Feat: Admin users - zobrazení emailu
  • • **`get_users_with_email()`** - vrací seznam uživatelů s emailem (join profiles + auth.users)
  • • **`get_user_email_by_id(user_id)`** - vrací email konkrétního uživatele podle ID
  • • Obě funkce kontrolují admin roli volajícího
  • • `/admin/users` - email zobrazen v sloupci Kontakt, vyhledávání rozšířeno o email
  • • `/admin/users/[id]` - email zobrazen v sekci Kontaktní údaje
  • • `supabase/migrations/..._admin_users_email_functions.sql`
  • • `frontend/src/app/admin/users/page.tsx`
  • • `frontend/src/app/admin/users/[id]/page.tsx`
  • Feat: Watchdog - Kompletní implementace automatické detekce plomby
  • • **watchdog-check v4** - kontroluje matche se statusem `watching`
  • • **send-notification-email v12** - nový typ `plomba_detected`
  • • Příjemce: `admin@spravnymakler.cz`
  • • Obsah: typ řízení, lokace, prodávající, makléř, odkaz na LV v ČÚZK
  • • Automatická změna statusu matche na "Prodáno"
  • • `/admin/settings` - Watchdog status změněn na "Aktivní"
  • • `/admin/matches` - upozornění ⚠️ "Chybí k.ú. / parcela" u matchů bez katastrálních dat
  • • `watchdog-weekly-check`: `0 8 * * 1` (pondělí 8:00 UTC)
  • • `supabase/functions/watchdog-check/index.ts`
  • • `supabase/functions/send-notification-email/index.ts`
  • • `supabase/migrations/20260124150000_setup_watchdog_cron.sql`
  • • `frontend/src/app/admin/settings/page.tsx`
  • • `frontend/src/app/admin/matches/page.tsx`
  • Security: Fix function_search_path_mutable
  • • `update_networks_updated_at` - přidán `SET search_path = public`
  • • `update_broker_service_profiles_updated_at` - přidán `SET search_path = public`
  • • `ensure_single_default_service_profile` - přidán `SET search_path = public`
  • • `supabase/migrations/20260124110000_fix_function_search_path.sql`
  • Security: Fix SECURITY DEFINER views
  • • **leads_for_brokers** - změna `security_invoker=false` → `security_invoker=true`
  • • **admin_leads_summary** - změna `security_invoker=false` → `security_invoker=true`
  • • View `admin_leads_summary` přidán do migrací (dříve jen v DB)
  • • `supabase/migrations/20260124100000_fix_security_invoker_views.sql`
23. ledna 2026
  • Design Enhancement - Micro-interactions a vizuální hloubka
  • • **Brand shadows** - nové utility třídy `shadow-brand-sm/md/lg/xl` s fialovým nádechem
  • • **Hover lift** - `.hover-lift` třída pro jemné vyzdvižení při hoveru
  • • **Active press** - `.active-press` třída pro stisknutí při kliknutí
  • • **Animace** - nové keyframes: `subtle-pulse`, `shimmer`, `float`, `bounce-subtle`
  • • Přidán `active:scale-[0.98]` pro všechny varianty (press feedback)
  • • Přidány shadow transitions: `hover:shadow-md` → `active:shadow-sm`
  • • Gradient varianta s `hover:shadow-lg` a fialovým glow efektem
  • • Změna `hover:shadow-md` → `hover:shadow-lg` pro výraznější stín
  • • Přidán `hover:-translate-y-0.5` pro jemný lift efekt
  • • Prodloužena transition na `duration-300`
  • • Brand-colored focus ring: `focus-visible:border-[#6039f6]`
  • • Glow efekt: `focus-visible:shadow-[0_0_0_4px_rgba(96,57,246,0.1)]`
  • • Sticky pozice: `sticky top-0 z-50`
  • • Glass efekt: `backdrop-blur-sm bg-background/95`
  • • Přidán `shadow-sm` pro vizuální separaci
  • • Logo hover: `group-hover:scale-105`
  • • Lucide ikony pro každý status typ (Clock, Eye, CheckCircle, XCircle, TrendingUp/Down...)
  • • Změna na `rounded-full` pro pill shape
  • • Spinning animace pro "collecting" stav
  • • Nový prop `hideIcon` pro zobrazení pouze textu
  • • Nový prop `icon` s možnostmi: inbox, search, question, alert
  • • Animovaný icon container s gradient pozadím (`animate-float`)
  • • Změna na `border-2 border-dashed` styl
  • • Gradient CTA tlačítko
  • • Přidán `hover:-translate-y-1 hover:shadow-lg` pro výraznější lift
  • • Ready state: `ring-2 ring-green-200 shadow-green-100`
  • • Urgency indicator: `animate-subtle-pulse` při ≤2 zbývajících slotech
  • • Přidán `shadow-sm` base shadow
  • • Interaktivní badges: `[a&]:hover:shadow-md [a&]:hover:scale-105`
21. ledna 2026
  • Brand Design 2025 - Kompletní vizuální redesign
  • • **S-shaped ikona** s textem "Správný Makléř"
  • • Gradient na ikonu: lavender → purple → dark
  • • Bílá verze pro tmavé pozadí (`logo-white.svg`)
  • • Favicon a PWA ikony aktualizovány
  • • **Royal Plum**: `#220860` (primární tmavá)
  • • **Brand Purple**: `#6039F6` (gradient střed)
  • • **Lavender Glow**: `#AF96FC` (accent světlá)
  • • **Text**: `#1f1463` (tmavě modrá)
  • • Gradient pozadí: `from-[#220860] via-[#6039f6] to-[#AF96FC]`
  • • Bílé logo, bílý text, bílá tlačítka
  • • Modernizovaný vizuální styl
  • Design: Gradient top borders na všech Card komponentách
  • • Přidány gradient top borders na všechny Card komponenty v aplikaci
  • • 74 karet aktualizováno ve 29 souborech
  • • Brand gradient: `from-[#220860] via-[#6039f6] to-[#AF96FC]`
  • • **Success** (zelená): email-verified, úspěšné akce
  • • **Error** (červená): chybové stavy
  • • **Pending** (oranžová): čekající položky (admin networks)
  • • Admin: dashboard, users, leads, bids, matches, networks, settings + detaily
  • • Seller: dashboard, new-lead wizard (5 kroků), lead detail, lead edit
  • • Broker: dashboard, lead detail, bids, match detail
  • • Auth: login, register, verify, forgot-password, reset-password, email-verified
  • • Public: terms, terms/broker, privacy, changelog
  • Legal: Údaje provozovatele aktualizovány
  • • **IČO**: 24109193
  • • **Sídlo**: Plzeňská 3352/156, Smíchov, 150 00 Praha 5
  • • **E-mail**: info@spravnymakler.cz
  • • Footer na všech stránkách
  • • Terms of Service (`/terms`)
  • • Privacy Policy (`/privacy`)
  • • GDPR dialogy v registraci
  • Feat: Watchdog příprava - nová databázová pole
  • • `cadastral_code` - kód katastrálního území (pro ČÚZK API)
  • • `house_number` - číslo popisné/evidenční (pro lookup jednotek)
  • • Příprava pro automatické sledování změn na LV (plomba)
  • • Umožní přesnější lookup jednotek v ČÚZK REST API KN
  • • Watchdog CRON job: kontrola prodeje každé pondělí 8:00 UTC
25. prosince 2025
  • Fix: Deploy opravy a Edge Functions
  • • **admin/matches/page.tsx** - Supabase 1:1 relace (`lead`, `bid`) vracely pole místo objektu
  • • Přidána kontrola `Array.isArray()` s fallbackem na první prvek
  • • Oprava přístupu k `icon` property pro "all" status filter
  • • **Příčina**: Default hodnota `matches.status` byla `'active'`, ale check constraint povoloval pouze `watching/sold/invoiced/paid/cancelled`
  • • **Řešení**: DB migrace - změna default hodnoty na `'watching'`
  • • `send-notification-email` v11
  • • `send-verification-email` v6
  • Admin: Stránka Spárování - kompletní redesign
  • • **Sledováno** (modrá) - čeká se na prodej
  • • **Prodáno** (zelená) - detekována plomba na LV
  • • **Fakturováno** (oranžová) - faktura odeslána
  • • **Zaplaceno** (fialová) - platba přijata
  • • **Zrušeno** (šedá) - zrušený případ
  • • **Naše provize** - kalkulace: `Odhad ceny × Provize makléře × 20%`
  • • **Odkaz na LV** - klikací odkaz na ČÚZK nahlížení do katastru
  • • Editovatelný select pro změnu stavu (admin only)
  • • Filtry podle stavu prodeje (taby s počty)
  • • Klikací odkazy: Nemovitost → lead detail, Prodávající → profil, Makléř → profil
  • • Přechod z nested queries na snapshot sloupce (performance)
  • • Nová RLS policy pro UPDATE matches (admins only)
  • • DB migrace: `status` CHECK constraint + workflow stavy
  • UX: Profil - sidebar tabs layout
  • • **Broker (5 tabů)**: Profil, Firma, Notifikace, Šablony, Účet
  • • **Seller (3 taby)**: Profil, Notifikace, Účet
  • • **Profil** - osobní údaje (jméno, email, telefon)
  • • **Firma** (broker) - firemní údaje, příslušnost k síti, adresa kanceláře (sloučeno)
  • • **Notifikace** - preferované oblasti (broker) + emailové notifikace
  • • **Šablony** (broker) - šablony služeb pro rychlejší vyplňování nabídek
  • • **Účet** - zabezpečení (změna hesla) + nebezpečná zóna (smazání účtu)
  • • Vertikální sidebar navigace vlevo, obsah vpravo
  • • Na mobilu ikony bez textu (responzivní)
  • • Adresa kanceláře přesunuta z vlastního tabu do tabu "Firma"
  • • Radix Tabs s `orientation="vertical"`
  • Feat: Změna hesla v profilu
  • • Nová sekce "Zabezpečení" v tabu Účet
  • • Dialog pro změnu hesla s validací aktuálního hesla
  • • Kontrola délky nového hesla (min. 6 znaků)
  • Feat: Re-verifikace telefonu při změně
  • • Oranžové varování při změně telefonního čísla
  • • Reset `phone_verified_at` na null při uložení
  • • Platí pro seller i broker (telefon se předává při matchi)
  • Feat: Jedna cena místo rozsahu
  • • **Formulář nabídky**: Jedno pole "Odhadovaná prodejní cena" místo dvou (Od/Do)
  • • **Databáze**: `price_min` = `price_max` (zpětná kompatibilita)
  • • **Zobrazení**: `formatPriceRange()` zobrazí jednu cenu když min === max
  • • **Existující data**: Aktualizována na horní hodnotu rozsahu
  • • Jednodušší rozhodování pro prodávajícího
  • • Větší tlak na makléře být přesný
  • • Inspirace: Online odhady (Hypox) také uvádějí jednu cenu
  • Feat: Cenový semafor - vylepšení
  • • **Medián** z 5 nabídek (ne průměr - není ovlivněn extrémy)
  • • **Trigger až při 5. nabídce** - do té doby klient nevidí porovnání
  • • **Klasifikace**:
  • • **Vysoká cena**: "Tato cena je výrazně vyšší než ostatní nabídky. Makléř možná přestřelil, aby vypadal atraktivně."
  • • **Nízká cena**: "Tato cena je výrazně nižší než ostatní nabídky. Makléř možná podstřelil nebo nemá zkušenosti s touto lokalitou."
  • • `calculate_price_label()` - výpočet s mediánem
  • • `recalculate_lead_price_labels()` - přepočet všech nabídek leadu
  • • `trigger_calculate_price_labels_at_max_bids()` - trigger při dosažení 5 nabídek
  • UX: Mobile-friendly srovnávací tabulka
  • • **Tlačítko "Skrýt"** v řádku "Akce" u každého makléře
  • • Skryje makléře z porovnání (neovlivňuje databázi)
  • • **Toast notifikace** s počítadlem "X makléřů skryto" a tlačítkem "Vrátit"
  • • Možnost vrátit všechny skryté makléře jedním klikem
  • • UX: Méně děsivé než "Vyřadit" - uživatel ví že akce je vratná
  • • **Agregované řádky** pro každou kategorii (Příprava a Vizuál, Marketing, Právní, Poprodejní)
  • • **Počítadlo X/Y** s progress barem (zelená výplň)
  • • **Kliknutím rozbalení** všech služeb v kategorii
  • • **Responzivní chování**:
  • • **Tlačítko "Sbalit vše"** pro rychlé sbalení všech kategorií
  • • **Nový řádek "Vybrat makléře"** na konci tabulky
  • • **Sticky pozice** - viditelný při scrollu
  • • **Zelené pozadí** pro vizuální odlišení od ostatních řádků
  • • Tlačítka "Vybrat" přesunuta sem (pryč z hlavičky)
  • • Nová závislost: `usehooks-ts` (useMediaQuery hook)
  • • Integrace: `sonner` toast komponenta (shadcn/ui)
  • • Responsive breakpoint: 768px (md)
  • UX: Dvou-krokové potvrzení výběru makléře
  • • **První klik** → tlačítko se změní na červené "Opravdu?"
  • • **Druhý klik do 3 sekund** → provede se match
  • • **Timeout 3s** → automatický reset zpět na "Vybrat"
24. prosince 2025
  • UX: Srovnávací tabulka nabídek makléřů (styl Alza.cz)
  • • **Sloupce = makléři** (#1-#5), řádky = služby seskupené do kategorií
  • • **Hlavička**: odhad ceny, provize, tlačítko "Vybrat"
  • • **28 služeb ve 4 kategoriích** s ✓/✗ ikonami
  • • **Toggle "Zobrazit pouze odlišné parametry"** - filtruje služby kde se makléři liší
  • • **Žluté zvýraznění** rozdílných řádků
  • • **Popover pro zprávy** - kliknutím na zkrácený text se zobrazí celá zpráva
  • • **Mobile-friendly**:
  • UX: Barevné stavy poptávek pro prodávající
  • • **Šedá** (waiting) - Čeká na nabídky (0 nabídek)
  • • **Žlutá** (collecting) - Sbírá nabídky (1-4 nabídek)
  • • **Zelená** (ready) - Připraveno k výběru (5/5 nabídek) + zelený ring
  • • **Modrá** (matched) - Spárováno
  • • `constants.ts` - nový `SELLER_LEAD_STATUS_CONFIG` a funkce `getSellerLeadDisplayStatus()`
  • • `status-badge.tsx` - podpora typu "seller-lead"
  • • `lead-card.tsx` - progress bar X/5, dynamický badge, `maxBids` prop
  • • `seller/leads/page.tsx` - filtrovací taby (Všechny, Sbírá nabídky, K výběru, Spárováno)
  • KRITICKÁ OPRAVA: Radix Checkbox Bug #2549 - infinite loop uvnitř form
  • • **Problém**: React Error #185 při klikání na checkbox služeb v broker lead detail page
  • • **Příčina**: Radix Checkbox uvnitř `<form>` dispatchuje syntetické click eventy přes interní `BubbleInput`
  • • **Proč fungovalo v profile page**: ServiceCheckboxes tam byl uvnitř `<Dialog>`, NE uvnitř `<form>`
  • • **Řešení**:
  • • **Reference**: https://github.com/radix-ui/primitives/issues/2549
  • KRITICKÁ OPRAVA: React Error #185 - Maximum update depth exceeded
  • • **Problém**: Při rychlém zaškrtávání služeb v nabídkovém formuláři došlo k pádu aplikace
  • • **Příčina**: Kombinace několika faktorů způsobovala kaskádové re-rendery:
  • • **Řešení** (3 commity):
  • UX: Accordion pro služby makléře
  • • **Nahrazen scrollbox** - služby nyní v rozbalovacích sekcích (Accordion)
  • • **4 kategorie jako AccordionItem** - Příprava a Vizuál, Marketing, Právní servis, Poprodejní servis
  • • **Checkbox v hlavičce** - kliknutím vybere/odebere celou kategorii
  • • **Počítadlo X/Y** u každé kategorie
  • • **Žádný horizontální scroll** - jeden sloupec, čistý design
  • • **Automatické otevření** - kategorie s vybranými službami se otevřou
  • • **Nová závislost**: `@radix-ui/react-accordion`
  • Služby makléře - checkboxy místo textu
  • • **BROKER_SERVICES** - 28 služeb ve 4 kategoriích:
  • • **ALL_BROKER_SERVICES** - flat array všech služeb
  • • **BROKER_SERVICE_LABELS** - mapa klíč → label
  • • **BrokerServiceKey** - TypeScript union type
  • • **ServiceCheckboxes** - grid s checkboxy seskupenými do kategorií
  • • **ServiceBadges** - kompaktní zobrazení jako barevné tagy
  • • **Migrace**: `add_broker_services_and_profiles`
  • • **Nové sloupce v `bids`**:
  • • **Nová tabulka `broker_service_profiles`**:
  • • **broker/leads/[id]** - nabídkový formulář
  • • **profile** - správa šablon služeb (pouze broker)
  • • **seller/leads/[id]** - zobrazení nabídek
  • • **admin/leads/[id]** - admin panel
  • • Aktualizovány typy v `lib/supabase/types.ts`
  • • Nový type alias `BrokerServiceProfile`
  • • Oprava: `as string[]` cast v service-checkboxes.tsx (type mismatch)
  • • Oprava: `const brokerId = profile.id` před async funkcí (null check)
23. prosince 2025
  • Code Review a Optimalizace
  • • **XML Injection ochrana** - `escapeXml()` funkce pro VIES SOAP API (`ico-lookup/route.ts`)
  • • **Validace parcelního čísla** - regex validace proti injection útokům (`cadastral-lookup/route.ts`)
  • • **signOut() race condition** - správné pořadí: nejdřív Supabase logout, pak clear state (`AuthContext.tsx`)
  • • **fetchProfile memory leak** - přidán `mountedRef` check + exponential backoff retry (`AuthContext.tsx`)
  • • **photo-upload setTimeout leak** - cleanup timer při unmount (`photo-upload.tsx`)
  • • **N+1 query fix** - Map lookup O(1) místo .filter() O(n) v loop (`dashboard/page.tsx`)
  • • **ARES timeout** - přidán 10s timeout pomocí `fetchWithTimeout()` (`ico-lookup/route.ts`)
  • • **Geo cache** - zvýšen z 1 hodiny na 7 dní pro RUIAN data (`cadastral-lookup/route.ts`)
  • • **Leaflet CSS utility** - nový soubor `lib/utils/leaflet.ts` s `initializeLeaflet()` a `ensureLeafletCSSLoaded()`
  • • **EnergyRatingSelect** - nová reusable komponenta pro PENB výběr (nahrazuje 3 duplicity)
  • • **UnitNumberInput** - nová reusable komponenta pro číslo jednotky (nahrazuje 3 duplicity)
  • Vrstva parcel v MapPicker - WMTS upgrade
  • • **Nové tlačítko "Parcely"** v pravém horním rohu mapy
  • • **ČÚZK WMTS vrstva** (nahrazuje WMS) - ostré rozlišení až do zoom 19
  • • **REST endpoint**: `services.cuzk.cz/wmts/local-km-wmts-google/rest/WMTS/default/KN/{z}/{y}/{x}`
  • • **Použití**: Pro snadnější identifikaci pozemku (garáže, pole, zahrady)
  • • **Omezení**: Zobrazí se pouze při zoom 17+ (WMTS limit)
  • • **UX**: Kliknutí zachová aktuální zoom (nepřibližuje pokud zoom ≥ 17)
  • • **Marker**: Vysoký z-index (1000) aby byl viditelný nad vrstvou parcel
  • • **Pouze pro prodávající**: Makléři stále vidí jen anonymní kruh
  • Admin detail poptávky - rozšíření a editace
  • • **Kompletní zobrazení všech polí** - LV, parcelní číslo, číslo jednotky, dispoziční řešení, vlastnictví, stav, typ budovy
  • • **Editace katastrálních údajů** - parcelní číslo, LV, číslo jednotky (inline edit s uložením)
  • • **Editace detailů nemovitosti** - dispozice, vlastnictví, stav, typ budovy
  • • **Editace popisu** - inline editace textu poptávky
  • • **Správa fotek**:
  • • **Oprava duplicitní adresy** - sloučeno "Přesná adresa" a "Adresa" do jedné sekce
  • UX vylepšení - Číslo jednotky
  • • **Přesunuto pole "Číslo jednotky"** z Kroku 2 (Poloha) do Kroku 3 (Parametry)
  • • **Lepší viditelnost** - pole bylo dříve schované na konci kroku Poloha
  • • **Shrnutí** - číslo jednotky se nyní zobrazuje v přehledu (Krok 5)
  • Oprava: LV jednotky se nyní správně získává
  • • **Problém**: Když uživatel zadal číslo jednotky v Kroku 3, LV jednotky se nikdy nezískalo z ČÚZK API
  • • **Příčina**: API se volalo pouze v Kroku 2 (pro parcelu), ne po zadání čísla jednotky
  • • **Řešení**:
  • • **Jak to funguje**:
  • • **Pro domy**: LV se získá automaticky v Kroku 2 při výběru adresy (není potřeba číslo jednotky)
  • KRITICKÁ OPRAVA: ČÚZK REST API KN autentizace
  • • **Problém**: LV číslo se nikdy nezískávalo - API vracelo 401 Unauthorized
  • • **Příčina**: Špatný název hlavičky `Api-Key` místo `ApiKey` (bez pomlčky)
  • • **Dopad**: Všechny typy nemovitostí (byty, domy, pozemky) neměly LV
  • • **Řešení**:
  • • **Nyní funguje**: LV pro parcely i jednotky se správně získává
  • Oprava TypeScript typů
  • • **Regenerace Supabase typů** - oprava chyby s `DatabaseWithoutInternals`
  • • **Nové type aliasy**: `Profile`, `Lead`, `LeadForBroker`, `Bid`, `Match`, `Network`
  • • **Composite typy**: `BidWithLead`, `BidWithBroker`
  • • **Enum typy**: `NotifyNewLeads`, `UserRole`
  • • **Helper funkce**: `parseLeadParams()` pro bezpečné parsování JSONB params
  • Oprava Changelog stránky pro produkci
  • • **Problém**: Changelog stránka nefungovala na Coolify (špatná cesta k souboru)
  • • **Řešení**:
  • • **Funguje** v lokálním vývoji i na produkci
  • Automatické získávání katastrálních dat z ČÚZK
  • • **Parcelní číslo** - automaticky získáváno při výběru lokace
  • • **List vlastnictví (LV)** - automaticky získáváno pro parcely i jednotky
  • • **Číslo jednotky** - nové volitelné pole pro byty, kanceláře, garáže
  • • **API `/api/cadastral-lookup`** rozšířeno:
  • • **Databázové změny**:
  • • **Environment variable**: `CUZK_API_KEY` pro REST API KN
  • • **MapPicker komponenta** - rozšířena o nová pole z ČÚZK
  • • **Formulář new-lead** - zobrazuje katastrální údaje v zeleném boxu
  • Adresa kanceláře a příslušnost k síti
  • • **Adresa kanceláře (působiště)** - nové povinné pole pro makléře
  • • **Příslušnost k realitní síti** - nová funkcionalita
  • • **Nová tabulka `networks`**
  • • **Admin panel `/admin/networks`**
  • • **Databázové změny**
  • • **Frontend změny**
  • Fakturační údaje makléře
  • • **Sídlo firmy** - nové pole v registraci a profilu (readonly, načítá se z ARES)
  • • **Bankovní účet** - volitelné pole pro makléře (formát: 123456789/0100)
  • • **Databázová změna** - nové sloupce `company_address` a `bank_account` v tabulce `profiles`
  • • **Registrace makléře** - sídlo firmy se zobrazí automaticky po ověření IČO
  • • **Profil makléře** - sekce "Firemní údaje" rozšířena o sídlo a bankovní účet
  • • **API `/api/ico-lookup`** - již vracelo adresu z ARES, nyní se využívá i ve frontendu
  • Rozdělení jména na Jméno + Příjmení
  • • **Databázová změna** - nové sloupce `first_name` a `last_name` v tabulce `profiles`
  • • **Migrace dat** - automatické rozdělení `full_name` podle první mezery
  • • **SQL funkce `create_match()`** - upravena pro snapshoty (spojuje first_name || ' ' || last_name)
  • • **VIEW `admin_leads_summary`** - aktualizován pro spojené jméno
  • • **14 frontend souborů upraveno**:
  • • **Zpětná kompatibilita** - `full_name` zůstává jako deprecated, stále se ukládá pro fallback
  • • **TypeScript typy** - aktualizovány + helper funkce `formatFullName()`
  • Vylepšení ověření makléřů
  • • **IČO ověření v profilu** - makléř musí ověřit IČO i při změně v profilu (stejně jako při registraci)
  • • **VIES ověření plátcovství DPH** - integrace EU VAT Information Exchange System
  • • **Readonly firemní údaje** - název firmy a DIČ nelze ručně upravovat
  • UX vylepšení
  • • **Odstranění duplicitního odkazu** - karta "Profil makléře" odstraněna z dashboardu makléře
  • Technické změny
  • • **API `/api/ico-lookup`** - rozšířeno o VIES ověření
  • • **Profil stránka** - přidány stavy pro IČO ověření (`icoVerified`, `icoLoading`, `icoError`)
22. prosince 2025
  • Migrace hostingu: Vercel → Hetzner + Coolify (DOKONČENO)
  • • **Nový hosting**: Hetzner VPS (CPX32) + Coolify v Německu
  • • **Důvod migrace**:
  • • **Server specifikace**:
  • • **Coolify**: Self-hosted PaaS (open-source Vercel alternativa)
  • Vercel zrušen
  • • **Projekt smazán** z Vercel dashboardu
  • • **Supabase Auth** - aktualizovány redirect URLs na `spravnymakler.cz`
  • • **Referer headery** - aktualizovány v API routes pro Mapy.cz
  • • **GDPR dokumentace** - aktualizováno v privacy policy a registračních formulářích (Vercel → Hetzner)
  • • **Admin settings** - Vercel Dashboard nahrazen Coolify Dashboard
  • Aktualizované soubory
  • • `api/address-suggest/route.ts` - Referer → spravnymakler.cz
  • • `api/reverse-geocode/route.ts` - Referer → spravnymakler.cz
  • • `privacy/page.tsx` - Hetzner místo Vercel
  • • `admin/settings/page.tsx` - Coolify Dashboard
  • • `auth/register/seller/page.tsx` - Hetzner v GDPR info
  • • `auth/register/broker/page.tsx` - Hetzner v GDPR info
  • Next.js konfigurace pro self-hosted
  • • **Standalone output** - `output: "standalone"` v next.config.ts
  • • **Vypnutá image optimizace** - `images.unoptimized: true` (řeší 400 Bad Request)
  • Dokumentace
  • • **MIGRATION-PLAN.md** - kompletní návod pro případnou budoucí migraci
  • • Aktualizace CLAUDE.md, CHANGELOG.md, ROADMAP.md
19. prosince 2025
  • PENB - Energetická třída budovy
  • • **Nové pole při zadání poptávky** pro byt, dům a komerční nemovitosti
  • • Klasifikace A–G s barevným kódováním podle české legislativy
  • • Volitelné pole (prodávající nemusí vyplnit)
  • • **Zobrazení na detail stránkách** (seller, broker, admin) - barevný badge s třídou
  • • Nové konstanty: `ENERGY_RATINGS`, `ENERGY_RATING_CONFIG`, `ENERGY_RATING_LABELS`
  • Vlastnická omezení nemovitosti
  • • **Nové pole** pro zadání právních/finančních omezení nemovitosti
  • • Radio výběr: "Bez omezení" / "Ano, má omezení"
  • • **Kategorizované checkboxy** pro specifická omezení:
  • • Implementováno v new-lead, edit stránce a všech detail stránkách
  • • Zelený badge "Bez omezení" / Oranžový "Má omezení" + tagy specifikace
  • • Nové konstanty: `PROPERTY_ENCUMBRANCES`, `ENCUMBRANCE_LABELS`
  • • Nové typy: `has_encumbrances`, `encumbrances[]` v LeadParams
  • UX vylepšení - pořadí polí ve formuláři
  • • **Příslušenství před vlastnickými omezeními** - logičtější flow
  • • Nejdřív fyzické vlastnosti, pak právní stav, pak popis
18. prosince 2025
  • Pokročilé filtry pro makléře
  • • **Nová komponenta `LocationFilter`** - hierarchický multi-select pro lokality
  • • **Tabs filtr podle stavu nabídky** na `/broker/leads`
  • • **Nové shadcn komponenty**: Popover, Checkbox, Collapsible
  • Konsolidace kontextových souborů
  • • **Nový `CLAUDE.md`** - jeden konsolidovaný kontextový soubor pro AI
  • • **Cleanup** - staré duplicitní soubory odstraněny (zůstávají v git historii)
17. prosince 2025
  • Rozšíření dat pro makléře
  • • **View `leads_for_brokers`** - přidány chybějící sloupce:
  • • **Migrace**: `20251217215805_add_missing_columns_to_leads_for_brokers_view.sql`
  • Kompletně přepracovaný detail poptávky pro makléře
  • • **Broker detail UI** (`/broker/leads/[id]`) - makléři nyní vidí všechny relevantní údaje:
  • • **Lokace** - zobrazena jako samostatný blok s okresem a krajem
  • • **Příslušenství** - kompletní seznam (balkón, lodžie, terasa, zahrada, sklep, parkování, garáž, výtah, bezbariérový, bazén)
  • • **Vlastnosti domu** - nízkoenergetický, dřevostavba, přízemní/patrový, samostatný/řadový
  • TypeScript typy
  • • Aktualizované typy v `types.ts` pro `leads_for_brokers` view
  • • Rozšířený `BrokerLead` type v broker detail stránce
10. prosince 2025
  • Editace a zrušení poptávky (Seller)
  • • **Nová stránka `/seller/leads/[id]/edit`** - editace poptávky
  • • **Tlačítko "Zrušit poptávku"** na detailu
  • • **Nový status `cancelled`** v LEAD_STATUS_CONFIG
  • UX přeuspořádání detailu poptávky
  • • **Nové pořadí sekcí** (podle priority pro uživatele):
  • • **Rationale**: Seller primárně čeká na nabídky, detail už zná
  • KRITICKÁ OPRAVA: leads_for_brokers VIEW
  • • **Problém**: Makléři neviděli žádné poptávky (0 z 0)
  • • **Příčina**: VIEW měl `security_invoker=true` - RLS na leads/bids blokoval dotazy
  • • **Řešení**: Změna na `security_invoker=false` (SECURITY DEFINER)
  • • VIEW nyní bypassuje RLS, bezpečnost zajištěna WHERE clause
  • • Migrace: `fix_leads_for_brokers_security`
  • GDPR a právní dokumenty
  • • **Privacy Policy** (`/privacy`) - kompletní zásady ochrany osobních údajů
  • • **Podmínky služby** (`/terms`) - obecné podmínky pro všechny uživatele
  • Registrace - modální okna pro právní dokumenty
  • • **Seller registrace** - Podmínky a Privacy se otevírají v modálním okně
  • • **Broker registrace** - Privacy se otevírá v modálním okně
  • Čestné prohlášení o neexkluzivitě
  • • **Wizard krok 5** - nový checkbox před odesláním poptávky
  • • **Databáze** - nové sloupce v `leads`:
  • Detail poptávky pro prodávajícího
  • • **Kompletní přehled zadaných údajů** - seller nyní vidí všechny informace které zadal
  • Lightbox pro fotografie
  • • **Nová komponenta `PhotoGallery`** - moderní prohlížení fotek
  • • **Nová komponenta `PhotoLightbox`** - modal dialog pro zobrazení
  • • **Použito na stránkách**:
  • Oprava Leaflet mapy z-index
  • • **Problém**: Mapa se zobrazovala nad lightbox overlayem
  • • **Řešení**: Reset z-indexu pro `.leaflet-pane`, `.leaflet-control`, `.leaflet-control-zoom`
  • • Opraveno v `LeadLocationMap` i `MapPicker` komponentách
  • Broker lead detail - oprava načítání dat
  • • Změna z `leads` tabulky na `leads_for_brokers` view
  • • Správné RLS - broker vidí pouze povolená data
  • Reset hesla
  • • **Nová stránka `/auth/forgot-password`** - zadání emailu pro obnovení hesla
  • • **Nová stránka `/auth/reset-password`** - zadání nového hesla
  • • **Proxy aktualizován** - propouští reset-password a forgot-password bez Basic Auth
  • Next.js 16 migrace
  • • **Middleware → Proxy** - migrace na nový Next.js 16 systém
9. prosince 2025
  • Oprava nahrávání fotek (PhotoUpload) - KRITICKÁ
  • • **Bug #1**: Prohlížeč/mobil zamrzal při nahrávání fotek
  • • **Bug #2**: Fotky se nenahrávaly (soubory neprošly validací)
  • • **Bug #3**: Multiple GoTrueClient instances (stovky instancí)
  • • **Vylepšení**:
  • • **Nová závislost**: `heic2any`
  • UX vylepšení pro makléře
  • • **Odstranění "Lokalita pro makléře"** - pole odstraněno z formuláře i zobrazení
  • • Makléři nyní vidí pouze mapu s anonymním kruhem a okres/kraj
  • • Text u mapy změněn na "Nemovitost se nachází někde ve vyznačeném kruhu"
  • Oprava mapování okres/kraj z Mapy.cz API
  • • **Příčina problému**: V ČR jsou oba (okres i kraj) typu `regional.region`
  • • **Opravené soubory**:
  • • Nyní se data ukládají správně: `district` = okres, `region` = kraj
  • Filtry pro makléře
  • • **Dva filtry** na stránce `/broker/leads`:
  • • Karty poptávek zobrazují "okres, kraj" pod názvem typu nemovitosti
  • Formulář pro pozemky (krok 3)
  • • **Nové pole "Kategorie pozemku"** (povinné):
  • • **Přejmenování**: "Užitná plocha" → "Plocha pozemku" pro typ pozemek
  • • **Zvýšený limit**: max 10 mil m² pro pozemky (vs 100 000 m² pro byty/domy)
  • • **Odstraněny nesmyslné položky** pro pozemky:
  • Databáze
  • • **Nový sloupec**: `leads.land_category` (text)
  • Nové konstanty
  • • `LAND_CATEGORIES` v `lib/constants.ts`
8. prosince 2025
  • Fix: Address suggest API - Referer header
  • • **Problém**: Našeptávač adres vracel 403 "The client did not meet the restrictions"
  • • **Příčina**: Mapy.cz API klíč má omezení na Referer header, server-side requesty neposílaly Referer
  • • **Řešení**: Přidán `Referer: https://spravny-makler.vercel.app/` header do fetch requestu
  • • **Doména REST API**: `api.mapy.com` (ne api.mapy.cz - ta funguje jen pro tiles)
  • Mapy.cz - odstranění OpenStreetMap fallbacku
  • • **address-suggest API route** - odstraněn Nominatim (OSM) fallback
  • • **lead-location-map komponenta** - odstraněn OSM tiles fallback
  • • Projekt nyní používá **výhradně Mapy.cz API**
  • • **Nutné nastavit na Vercelu**:
  • • **API klíč v Mapy.cz portálu** musí mít povolené domény včetně produkční
  • Anonymní kruh pro makléře (Privacy Feature)
  • • **Nový sloupec leads**: `display_latitude`, `display_longitude` - náhodně posunuté souřadnice
  • • **Nová komponenta `LeadLocationMap`** - Leaflet mapa zobrazující 500m kruh
  • • **Nová utility `lib/utils/geo.ts`** - funkce `generateRandomPointInCircle()`
  • • **View `leads_for_brokers` aktualizována**:
  • • Makléř vidí kruh o poloměru 500m, nemovitost je náhodně umístěna uvnitř (ne ve středu)
  • • Offset se generuje jednou při vytvoření poptávky a nemění se
  • Oprava Mapy.cz integrace
  • • **Tiles URL**: `api.mapy.cz` pro mapové dlaždice
  • • **REST API URL**: `api.mapy.com` pro suggest/geocode endpointy
  • • **cityPart v lokaci**: zobrazuje se "Město - Část města" (např. "Plzeň - Plzeň 1")
  • • Přidána proměnná `NEXT_PUBLIC_MAPY_CZ_API_KEY` pro client-side přístup
  • KRITICKÁ OPRAVA #2: supabase-js deadlock bug
  • • **Root cause**: supabase-js má bug kde `await` jakéhokoliv Supabase API volání uvnitř `onAuthStateChange` callbacku způsobí deadlock
  • • **Symptom**: Po SMS ověření spinner točil navždy, Supabase query nikdy nedokončila (HTTP 200, ale Promise se neresolvla)
  • • **Řešení**: `setTimeout(() => fetchProfile(...), 0)` - odloží volání mimo callback
  • • **Reference**: https://github.com/orgs/supabase/discussions/19058
  • KRITICKÁ OPRAVA #1: Supabase SSR caching bug
  • • **Root cause**: `@supabase/ssr` `createBrowserClient` měl interní cache, která vracela stará data i po změnách v DB
  • • **Symptom**: Po ověření emailu/SMS spinner stále točil, UI se neaktualizovalo
  • • **Řešení**: Přechod z `@supabase/ssr` na standardní `@supabase/supabase-js`
  • Změna závislostí
  • • import { createBrowserClient } from '@supabase/ssr'
  • Refaktor auth architektury (dříve)
  • • **Singleton Supabase client** - jedna instance pro celou aplikaci (odstraněny race conditions)
  • • **Nový useAuth hook** - centrální zdroj pravdy pro auth stav
  • • **Smazán useUserRole hook** - nahrazen `useAuth().profile?.role`
  • • **Odstraněna závislost na Realtime** - místo pasivního čekání na změny používáme explicitní invalidaci
  • • **useAuthGuard zjednodušen** - používá useAuth() místo vlastního fetch
  • Opravené problémy
  • • Dashboard se nenačítal po registraci a verifikaci (stale cache)
  • • Více Supabase klientů s různým stavem session
  • • Komponenty nereagovaly na změny profilu po verifikaci
  • Aktualizované soubory
  • • `lib/supabase/client.ts` - změna z @supabase/ssr na @supabase/supabase-js
  • • `AuthContext.tsx` - kompletní přepis (singleton + refetchProfile)
  • • `useAuthGuard.ts` - zjednodušení (používá useAuth)
  • • `role-indicator.tsx` - používá useAuth místo useUserRole
  • • `hero-buttons.tsx` - používá useAuth místo useUserRole
  • • `verify/page.tsx` - visibilitychange místo polling, router.replace()
7. prosince 2025
  • Refaktor registračního procesu
  • • **Jednotná verifikační stránka** `/auth/verify` - email + telefon na jednom místě
  • • **Seller registrace opravena** - telefon povinný, "complete" krok s instrukcemi
  • • **Broker registrace vyčištěna** - odstraněno ~150 řádků mrtvého OTP kódu
  • • **Shared utility** `lib/utils/phone.ts` - normalizePhone funkce
  • • **useAuthGuard** nyní vyžaduje ověření telefonu pro všechny uživatele (seller i broker)
  • • Konzistentní flow: Registrace → Email potvrzení → Login → Verify telefon → Dashboard
  • Mazání účtu s právní ochranou
  • • **Soft delete s anonymizací** - účty se nemažou, data zůstávají pro právní účely
  • • Edge Function `delete-account` s ověřením hesla
  • • Dialog pro mazání účtu v profilu uživatele
  • • **Audit log** - kompletní záloha dat před anonymizací (`account_deletion_audit`)
  • • **Snapshot sloupce v matches** - jméno, telefon, IČO, firma makléře i prodávajícího
  • • Anonymizace: `full_name` = "Smazaný uživatel", osobní údaje = null
  • • Migrované RLS policies filtrují `deleted_at IS NULL`
  • Bezpečnostní opravy
  • • **SECURITY INVOKER** - view `leads_for_brokers` nyní respektuje volajícího
  • • **SET search_path=public** - funkce `create_match` chráněna proti injection
  • • Memory leak fix v broker registraci (interval cleanup)
  • Optimalizace výkonu
  • • **Database views** pro admin panel:
  • • **Pagination** - limit 100 záznamů na admin stránkách
  • • **useMemo** - memoizace filtrovaných seznamů (users, bids, matches)
  • • **Lazy loading** - `browser-image-compression` načítáno dynamicky
  • • **Next.js Image** - remotePatterns pro Supabase Storage
  • Opravy
  • • Fix: Vonage SMS credentials - aktualizace API klíčů
  • • Fix: Sender ID zkráceno na max 11 znaků (limit Vonage)
6. prosince 2025
  • Code Cleanup & Performance
  • • **RLS Performance Fix** - `auth.uid()` → `(select auth.uid())` v 15 policies
  • • **Nová komponenta `LoadingSpinner`** - nahrazuje 7 duplicitních spinnerů
  • • Odstraněn debug `console.log` v photo-upload.tsx
  • • Migrace: `fix_rls_policies_performance`
  • Admin panel
  • • Admin rozhraní s kompletní správou systému
  • • Dashboard se statistikami (uživatelé, poptávky, nabídky, matche)
  • • Seznam uživatelů s filtrováním podle role
  • • Detail uživatele se změnou role a možností smazání
  • • Seznam poptávek s plnými adresami
  • • Detail poptávky se změnou statusu a možností smazání
  • • Správa nabídek (změna statusu, mazání) přímo v detailu poptávky
  • • Stránka spárování s kontaktními údaji obou stran
  • • Nastavení systému s přehledem služeb
  • Email notifikace
  • • Resend integrace - doména ověřena (SPF, DKIM, MX)
  • • Edge Function `send-notification-email`
  • • Supabase Vault secrets (supabase_url, service_role_key)
  • • Edge Function secrets (RESEND_API_KEY, FROM_EMAIL, SITE_URL)
  • • Potvrzení emailu při registraci zapnuto
  • Registrace makléře - právní compliance
  • • **Explicitní souhlas s podmínkami** - viditelné klíčové body (20% provize, zákaz obcházení, mlčenlivost)
  • • **Modal s celým zněním smlouvy** - ScrollArea pro přehledné čtení
  • • **SMS ověření telefonu** - 6místný OTP kód přes Vonage
  • • Normalizace telefonního čísla (+420)
  • • Audit log souhlasu (verze, timestamp, body)
  • • DB sloupce: `terms_accepted_at`, `terms_version`, `terms_explicit_points`, `phone_verified_at`, `ico`
  • IČO ověření a kontrola živnosti
  • • **IČO je povinné** pro registraci makléře
  • • **ARES API integrace** - ověření firmy v registru ARES
  • • API route `/api/ico-lookup` - lookup + RŽP živnosti
  • • Validace kontrolní číslice IČO (modulo 11)
  • • **Auto-fill názvu firmy** po ověření IČO
  • • **Kontrola živnosti** "Realitní zprostředkování" z RŽP
  • • Chybějící živnost = varování (neblokuje registraci)
  • • DB sloupec: `has_realitni_zivnost` (boolean)
  • • Admin může manuálně upravit stav živnosti
  • Opravy
  • • Fix: `commission` → `commission_percent` v admin detailech
  • • RLS policies pro admin přístup (SELECT, UPDATE, DELETE)
  • • Fix: useUserRole hook - automatický update UI při přihlášení/odhlášení
  • • Fix: chybějící závislost @radix-ui/react-alert-dialog
5. prosince 2025
  • Nové funkce
  • • **Location Picker** - výběr polohy na mapě pro pozemky/garáže bez adresy
  • • **Katastrální údaje** - automatické získání k.ú. z ČÚZK RUIAN API
  • • API route `/api/cadastral-lookup` pro katastrální území
  • • API route `/api/reverse-geocode` pro Mapy.cz reverse geocoding
  • • Přepínač "Mám adresu" / "Vybrat na mapě" ve wizardu
  • Změny
  • • DB: street je nullable - pozemky/garáže mohou být bez adresy
  • • AddressAutocomplete vrací i souřadnice (lat/lon)
  • • Wizard step 2 přepracován s přepínačem metody zadání lokace
4. prosince 2025
  • Základní funkce
  • • Registrace prodávající / makléř
  • • Wizard pro zadání nemovitosti (5 kroků)
  • • Fotky interiér/exteriér s kompresí
  • • Address autocomplete (Mapy.cz)
  • • Seznam poptávek pro makléře
  • • Odeslání nabídky
  • • Match systém
  • • Dashboard pro oba typy uživatelů
  • • **Logo** v hlavičce a na homepage
  • • **useAuthGuard hook** - centralizovaná autentizace
  • • **useUserRole hook** - získání role uživatele
  • • **LeadCard komponenta** - reusable karta pro poptávky
  • • Changelog stránka pro testery
  • • Formátování cen s mezerami (1 000 000 Kč)
  • • Dynamická homepage podle role uživatele
  • • Password protection pro staging
  • • **Role indikátor** - barevný pruh (Prodávající/Makléř/Admin)
  • • **Stránka profilu** (`/profile`)
  • • **Filtry podle kraje/okresu** na `/broker/leads`
  • • **Preference makléře** - výběr krajů a frekvence notifikací
  • • Extrakce kraje a okresu z Mapy.cz API
  • Opravy
  • • RLS recursion při vytváření nabídky
  • • Hydration error na homepage
  • • Doplněny kraje/okresy u existujících poptávek
  • • Security issues a useEffect dependencies
  • • N+1 query optimalizace
Typy email notifikací