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í