Changelog

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

9. května 2026
  • Cleanup: odstranění staging password feature
  • • `frontend/src/app/auth/staging/page.tsx` — login formulář
  • • `frontend/src/app/api/staging-auth/route.ts` — API endpoint nastavující cookie
  • • `stagingAuth` rate limit z `lib/rate-limit.ts`
  • • `CLAUDE.md`, `LEGAL-PRIVACY.md`, `TESTING-MATRIX.md/.csv`, `.claude/docs/ROUTES-AND-STRUCTURE.md`, `.claude/docs/COMPLETED-FEATURES.md` — odstraněny zmínky o staging gate
  • • `LEGAL-PRIVACY.md` — odstraněna deklarace staging cookie ze sekce 9.1 (právní dokument nesmí deklarovat cookie, kterou neukládáme)
19. dubna 2026
  • Security: quick wins z auditu (M2, H4, M4)
  • • **M2 — sendNotification rate limit 20→5/min** (`lib/rate-limit.ts:114`): Admin akce limit zpřísněn (anti-spam). Legitimní use case (admin posílá emaily uživatelům) běží daleko pod limitem.
  • • **H4 — `supabase/config.toml`**: Nový soubor trackuje `verify_jwt` flag pro všech 8 Edge Functions v repo (jediný source of truth, prevence driftu mezi platform UI a kódem). Inventura přes Supabase MCP potvrdila, že stav v UI odpovídá: `send-notification-email/watchdog-check/expire-leads/checkin-send/auto-approve-leads` mají `false` (s vlastním Bearer checkem), `delete-account/send-verification-email/send-verification-sms` mají `true`.
  • • **M4 — anti-bruteforce na `delete-account`**: Self-service mode volal `signInWithPassword()` bez per-IP ochrany → bruteforce risk. DB-backed rate limit (perzistentní napříč Edge Function instances).
  • • **M1 (Mapy.cz error sanitizace) — uzavřeno jako false positive**: Po revizi `address-suggest` a `reverse-geocode` — oba routes vrací generic `apiError(...)` při `!response.ok`. Mapy.cz API key je v URL query, ne v response body, takže `{...data, source}` spread není vektor leaku.
  • Security: oprava 4 nálezů z bezpečnostního auditu (C1, C2, H1, H2)
  • • **C1 — `send-notification-email` Bearer auth check (CRITICAL)**: Edge Function měla `verify_jwt: false` BEZ vlastního auth checku → publicly callable. Kdokoliv s URL mohl posílat emaily z naší domény (`notifikace@spravnymakler.cz`) — riziko spamu/phishingu. Fix:
  • • **C2 — `useAuthGuard` MFA fail-closed (CRITICAL)**: Pokud `getAuthenticatorAssuranceLevel()` nebo `listFactors()` selhalo (síťová chyba, Supabase timeout), kód spadl do `setIsAuthorized(true)` → admin dostal plný přístup BEZ 2FA verifikace. Fix:
  • • **H1 — `/api/send-notification` sanitizace error (HIGH)**: Proxy vracela `errorText` z Edge Function přímo klientovi (`apiError(\`...${errorText}\`, ...)`) → potenciální leak interních detailů Resend/SDK chyb. Fix: generic `"Email se nepodařilo odeslat."` + 502 status, detail jen do `console.error`.
  • • **H2 — `send-notification-email` sanitizace error (HIGH)**: Edge Function vracela `error.message` (Resend) a `String(error)` (catch) v JSON response. Fix: generic `"Email send failed"` (502) a `"Internal server error"` (500), detail jen do `console.error`.
  • Refactor: property-params-section split + memoizace
  • • Původní monolitický `property-params-section.tsx` (543 ř.) rozdělen do `property-params-section/`:
  • • `activeAmenities`, `activeHouseChars`, `unmanagedEntries`, `currentEncumbrances` nyní přes `useMemo` — dříve se přepočítávaly na KAŽDÝ render (včetně každého znaku při psaní do inputu)
  • • `has()` predikát stabilizován přes `useCallback` → umožňuje memoizaci derivovaných seznamů
  • • `setVal` stabilizován přes `useCallback` (setter pattern, nemění se)
  • • Žádná změna UI ani business logiky — čistě interní refactor pro lepší udržovatelnost a render perf
  • Perf: paralelní načítání na stránce hodnocení makléře
  • • `seller/rate/[matchId]` — načtení `matches` detailu a `broker_ratings` existujícího hodnocení nyní přes `Promise.all` místo sekvenčně (oba dotazy klíčují pouze na `matchId` z URL a nezávisí na sobě)
  • • Úspora ~50 ms latence na každém otevření stránky
  • Fix: setTimeout cleanup v auth/profile hooks
  • • `useChangePassword.ts` a `useProfileForm.ts` držely `setTimeout` bez cleanup → pokud uživatel navigoval pryč nebo zavřel dialog během 2-3s okna, React vypisoval "state update on unmounted component" warn + potenciální memory leak
  • • Standardní pattern: `useRef<ReturnType<typeof setTimeout>>` + cleanup v `useEffect` (stejný pattern jako `useNotifications.ts`)
  • Lokalizace Supabase auth chyb do češtiny
  • • Nový helper `lib/utils/auth-errors.ts` — funkce `translateAuthError(err)` mapuje anglické chybové zprávy od Supabase Auth (leaked password, slabé heslo, invalid credentials, rate limit, duplikátní email) na uživatelsky přívětivé české texty
  • • Použito v 4 místech: `useChangePassword.ts` (změna hesla v profilu), `reset-password/page.tsx` (zapomenuté heslo), `use-seller-register.ts` + `use-broker-register.ts` (registrace — detail pro password větev)
  • • Hlavní dopad: při leaked password (HaveIBeenPwned) vidí uživatel "Toto heslo bylo nalezeno v úniku dat nebo je příliš jednoduché. Zvolte prosím jiné." místo anglické "Password is known to be weak and easy to guess..."
  • • Login error zůstává univerzální ("Neplatný email nebo heslo") — security best practice (není žádoucí odhalit, zda email v systému existuje)
  • DB optimalizace: Supabase advisors (M1-M5)
  • • **M1 `security_quick_wins_m1`** — `SET search_path` na 2 funkcích (`update_support_ticket_updated_at`, `notify_admin_pending_review` SECURITY DEFINER), DROP dead-code `insert_service` policy na 3 tabulkách (`notifications`, `checkin_tokens`, `email_action_tokens`)
  • • **M2 `missing_fk_indexes_m2`** — 7 indexů pro unindexed FK: `broker_ratings.moderated_by/seller_id`, `checkin_tokens.user_id`, `leads.reviewed_by`, `profiles.approved_by/suspended_by`, `support_tickets.admin_replied_by`
  • • **M3 `rls_init_plan_fix_m3`** — přepis `audit_logs.admin_read_all` policy: `auth.uid()` → `(SELECT auth.uid())` pro init plan optimalizaci (eval 1× per query místo per řádek)
  • • **M4 `consolidate_rls_policies_m4`** — konsolidace duplicitních permissive policies na 5 tabulkách (16 WARN findings): `broker_ratings` SELECT (3→1), `checkin_tokens`/`email_action_tokens`/`support_tickets` SELECT (2→1), `matches` UPDATE (2→1). Chování je funkčně identické, jen rychlejší.
  • • **M5 `storage_bucket_listing_m5`** — DROP dead-code SELECT policies `Anyone can view photos` (property-photos) a `public_read_brand_assets` — ověřeno, že v projektu není ani jedno volání `.list()` nebo `.createSignedUrl()`. Public URL access funguje přes `bucket.public=true` flag, ne policy.
16. dubna 2026
  • Bugfix: Terms re-acceptance loop
  • • **Opraveno**: Po odsouhlasení aktualizovaných podmínek (broker) se stránka zobrazila znovu místo přesměrování na dashboard — chyběl `refetchProfile()` po DB updatu, `useAuthGuard` viděl stale `terms_version` a redirectoval zpět
  • Reset verzí podmínek na 0.5
  • • **Verze podmínek**: Změna z `2.0` na `0.5` (produkční bude `1.0`) v `terms-config.ts`
  • • **DB reset**: Všichni uživatelé nastaveni na `terms_version = '0.4'` → vyžadována re-akceptace při příštím přihlášení
  • • **Seller blocking redirect**: `useAuthGuard` nyní redirectuje i sellery na `/auth/accept-terms` při outdated podmínkách (dříve jen non-blocking banner, který nebyl nikde renderovaný)
11. dubna 2026
  • Legal compliance: GDPR a právní dokumenty
  • • **Seller consent tracking**: Přidán povinný checkbox souhlasu s podmínkami při registraci sellera + ukládání `terms_accepted_at` a `terms_version` do DB
  • • **Google OAuth accept-terms**: Nová stránka `/auth/accept-terms` — OAuth selleři musí odsouhlasit podmínky po prvním přihlášení
  • • **Terms re-acceptance flow**: `useAuthGuard` kontroluje verzi podmínek — broker = blocking redirect, seller = non-blocking banner (`terms-reaccept-banner.tsx`)
  • • **Sdílená verze podmínek**: `lib/terms-config.ts` — single source of truth pro verze (seller + broker)
  • • **Site-wide footer**: Nová sdílená komponenta `footer.tsx` s právními odkazy (Podmínky, Ochrana soukromí, Kontakt) — přidán do root layout, odstraněn duplicitní inline footer z landing page
  • • **Email footer legal links**: Přidány odkazy na Podmínky a Ochranu soukromí do patičky všech emailů (`brand.ts`)
  • • **Contact form privacy notice**: Informace o zpracování osobních údajů a 3-leté retenci před submit tlačítkem
  • • **EXIF metadata stripping**: Fotky < 300KB nyní procházejí canvas redraw (strip GPS/EXIF dat) místo přeskakování komprese
  • • **Data export (GDPR čl. 20)**: Nová karta "Export dat" v profilu s mailto odkazem pro žádost o přenositelnost údajů
  • Pre-launch audit: P1 opravy
  • • Přidáno `error.tsx` — uživatelsky přívětivá error boundary s Sentry + "Zkusit znovu" tlačítkem
  • • Přidáno `not-found.tsx` — brand 404 stránka s odkazem na hlavní stránku
  • • Opraveno: `handleDeleteLead` v admin lead detail — přidán chybějící error check na mazání nabídek
  • • Nahrazeno 4x `<img>` za Next.js `<Image>` komponentu (MFA loga, admin property photos)
  • • Vyčištěno 8 ESLint warnings (nepoužívané importy/proměnné z refaktoringu) — 0 warnings
  • Pre-launch audit: P3 vylepšení
  • • Přidáno `aria-label` na 4 icon-only tlačítka (photo-lightbox: zavřít, předchozí, další; notifications: zpět)
  • • Přidáno page-level metadata na 8 veřejných stránek (kontakt, login, registrace seller/broker, registrace, podmínky, podmínky broker, ochrana údajů)
  • Pre-launch audit: P2 opravy
  • • Opraveno N+1 admin email notifikace v `confirm-contract` a `report-sale` — sekvenční loop nahrazen `Promise.all()` batch fetchem
  • • Přidáno Sentry error tracking na fire-and-forget notifikace ve 4 API routes (`confirm-contract`, `report-sale`, `submit-rating`, `support-ticket`)
9. dubna 2026
  • Refactor: auth/register/seller — rozpad na hook + sekce (konzistence s broker)
  • • `page.tsx` zmenšen z 461 na 56 řádků (orchestrátor)
  • • `use-seller-register.ts` (123 ř.) — hook: formData, validace, handleSubmit, redirect
  • • `section-form.tsx` (83 ř.) — formulář: Google OAuth, inputs, submit
  • • `section-terms-modals.tsx` (96 ř.) — Terms + Privacy modální dialogy
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: admin/bids list page — rozpad na hook + sekce
  • • `page.tsx` zmenšen z 366 na 57 řádků
  • • `use-bids.ts` (103 ř.) + `section-table.tsx` (115 ř.) + `types.ts` (38 ř.)
  • Refactor: admin/users list page — rozpad na hook + sekce
  • • `page.tsx` zmenšen z 366 na 69 řádků
  • • `use-users.ts` (105 ř.) + `section-table.tsx` (113 ř.) + `types.ts` (34 ř.)
  • Refactor: admin/leads list page — rozpad na hook + sekce
  • • `page.tsx` zmenšen z 383 na 90 řádků (orchestrátor)
  • • `use-leads.ts` (105 ř.) + `section-table.tsx` (116 ř.) + `types.ts` (29 ř.)
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: admin/ratings page — rozpad na hook + sekce
  • • `page.tsx` zmenšen z 450 na 89 řádků (orchestrátor + Suspense wrapper)
  • • `use-ratings.ts` (136 ř.) — hook: fetch, filter, expand, handleModerate, deep-link
  • • `section-table.tsx` (148 ř.) — tabulka s expandable rows (star ratings, detail) + moderace
  • • `types.ts` (50 ř.) — RatingRow, lookupLabel, CSV_COLUMNS
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: admin/support page — rozpad na hook + sekce + konstanty
  • • `page.tsx` zmenšen z 575 na 90 řádků (orchestrátor + Suspense wrapper)
  • • `use-support.ts` (183 ř.) — hook: fetch, filtry, expand, handleReply, deep-link
  • • `support-constants.ts` (20 ř.) — STATUS_CONFIG, CATEGORY_CONFIG, STATUS_OPTIONS
  • • `section-filters.tsx` (69 ř.) — search + status/category selects
  • • `section-table.tsx` (177 ř.) — tabulka s expandable rows + reply form + pagination
  • • `types.ts` (31 ř.) — SupportTicket, CSV_COLUMNS
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: admin/networks page — rozpad na hook + sekce + dialog
  • • `page.tsx` zmenšen z 582 na 65 řádků (orchestrátor)
  • • `use-networks.ts` (244 ř.) — hook: fetch, CRUD, approval workflow, slug gen
  • • `section-pending.tsx` (152 ř.) — pending approvals tabulka + approve dialog
  • • `section-networks-table.tsx` (72 ř.) — hlavní tabulka sítí
  • • `add-network-dialog.tsx` (81 ř.) — dialog pro přidání sítě
  • • `types.ts` (4 ř.) — ProfileWithCustomNetwork
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: admin/matches list page — rozpad na hook + sekce + konstanty
  • • `page.tsx` zmenšen z 703 na 100 řádků (orchestrátor)
  • • `use-matches.ts` (203 ř.) — hook: fetch, filtrování, sorting, handleStatusChange (state machine)
  • • `matches-constants.ts` (29 ř.) — MATCH_STATUS_CONFIG, VALID_TRANSITIONS
  • • `section-status-tabs.tsx` (52 ř.) — status filter taby s počty a ikonami
  • • `section-table.tsx` (231 ř.) — tabulka s 11 sloupci, inline status select, pagination
  • • `types.ts` (60 ř.) — Match, MatchStatus, CSV_COLUMNS
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: admin/audit page — rozpad na hook + sekce + konstanty
  • • `page.tsx` zmenšen z 737 na 63 řádků (orchestrátor)
  • • `use-audit-log.ts` (246 ř.) — hook: fetch, filtrování, sorting, pagination, entity cache
  • • `audit-constants.ts` (147 ř.) — ACTION_LABELS, ENTITY_LABELS, ROLE_BADGE_CONFIG, METADATA_KEY_LABELS, formattery
  • • `section-filters.tsx` (99 ř.) — filter bar: search, dropdowns, date range
  • • `section-table.tsx` (221 ř.) — tabulka: header, expandovatelné řádky, detail, pagination, CSV export
  • • `types.ts` (35 ř.) — AuditLog, EntityField, EntityCacheEntry, CSV_COLUMNS
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: auth/verify page — rozpad na hook + sekce
  • • `page.tsx` zmenšen z 552 na 126 řádků (orchestrátor)
  • • `use-verify.ts` (366 ř.) — hook: 13 stavů, 5 efektů, 8 handlerů (email, SMS, phone, redirect)
  • • `section-email.tsx` (47 ř.) — email verifikace karta
  • • `section-phone.tsx` (130 ř.) — phone verifikace: OTP flow + phone input (Google OAuth)
  • • `types.ts` (35 ř.) — EmailSectionProps, PhoneSectionProps
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: bid-comparison-table — rozpad na adresář s moduly
  • • `bid-comparison-table.tsx` (652 ř.) → adresář `bid-comparison-table/` se 6 soubory
  • • `index.tsx` (318 ř.) — hlavní JSX komponenta (tabulka, header, body, footer)
  • • `use-bid-comparison.ts` (167 ř.) — hook: state, handlers, memos (rozdíly, filtrování, eliminace)
  • • `collapsible-category.tsx` (84 ř.) — sbalitelná sekce kategorií služeb
  • • `service-row.tsx` (32 ř.) — řádek služby s check/cross ikonou
  • • `text-cell-popover.tsx` (53 ř.) — text s popoverem pro dlouhý obsah
  • • `types.ts` (15 ř.) — BidComparisonTableProps, CategoryKey, ServiceItem
  • • Import path zachován (`@/components/bid-comparison-table`)
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: checkin-send Edge Function — rozpad na moduly
  • • `index.ts` zmenšen z 461 na 68 řádků (auth + orchestrátor)
  • • `helpers.ts` (86 ř.) — sdílené: NotifPrefs typ, getNotifPref, sendEmailViaBrand, createActionToken, parseMatchRelations
  • • `contract-prompt.ts` (106 ř.) — Fáze A: "Podepsali jste smlouvu?" (7 dní po matchi)
  • • `contract-reminder.ts` (106 ř.) — Fáze B: Připomínka + admin alert (21 dní)
  • • `sale-check.ts` (150 ř.) — Fáze C+D: Sale check (42 dní) + opakovaný (3 měsíce)
  • • Žádná změna chování — čistě DX refaktorizace
  • Refactor: send-notification-email Edge Function — rozpad na moduly
  • • `index.ts` zmenšen z 807 na 99 řádků (HTTP handler only)
  • • 3 infrastrukturní moduly: `types.ts` (EmailType, EmailPayload, TemplateMap), `vocative.ts` (vokativ), `brand.ts` (SITE_URL, BRAND, header/footer/infobox/button)
  • • 7 template souborů v `templates/`: `lead.ts`, `match.ts`, `sale.ts`, `broker.ts`, `checkin.ts`, `contract.ts`, `watchdog.ts`
  • • Barrel `templates/index.ts` — merge všech 23 šablon do jednoho Record
  • • Přidán chybějící `action_token` do `EmailPayload` typu (type-only fix)
  • • Žádná změna chování ani email outputu — čistě DX refaktorizace
  • Refactor: New lead wizard step 3 — rozpad na params sub-komponenty
  • • `seller/new-lead/step-3-parameters.tsx` zmenšen z 901 na ~85 řádků (orchestrátor)
  • • 6 sub-komponent: `params-apartment`, `params-house`, `params-commercial`, `params-common`, `params-amenities`, `params-encumbrances`
  • • `CheckboxItem` helper v params-amenities, `EncumbranceGroup` helper v params-encumbrances (eliminace repetitivního JSX)
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: Broker lead detail — rozpad na sekce a hook
  • • `broker/leads/[id]/page.tsx` zmenšen z 892 na ~50 řádků (orchestrátor)
  • • 2 section komponenty: `section-lead-info` (property details + photos + map), `section-bid-panel` (formulář/status + confirm dialog)
  • • Centrální hook `use-broker-lead-detail.ts` (10 state, 1 efekt, 6 handlerů)
  • • Sdílené typy v `types.ts` (BrokerLead, ExistingBid, BidFormData, section Props)
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: Broker match detail — rozpad na sekce a hook
  • • `broker/matches/[id]/page.tsx` zmenšen z 970 na ~60 řádků (orchestrátor)
  • • 5 section komponent: `section-header`, `section-seller-contact`, `section-cooperation`, `section-property-details`, `section-bid`
  • • Centrální hook `use-broker-match-detail.ts` (10 state, 1 efekt, 4 handlery)
  • • Sdílené typy v `types.ts` (MatchDetail, section Props)
  • • `ContractConfirmButton` extrahován jako reusable sub-komponenta (eliminace duplikace AlertDialog)
  • • `PropertyRow` helper v section-property-details (eliminace opakovaného JSX)
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: Broker register page — rozpad na sekce a hook
  • • `auth/register/broker/page.tsx` zmenšen z 1064 na ~113 řádků (orchestrátor)
  • • 5 section komponent: `section-personal-info`, `section-company-info`, `section-network`, `section-credentials`, `section-terms`
  • • Centrální hook `use-broker-register.ts` (15 state, 3 efekty, 10 handlerů)
  • • Sdílené typy v `types.ts` (BrokerFormData, IcoVerificationState, section Props)
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
8. dubna 2026
  • Refactor: Admin user detail — rozpad na sekce a hook
  • • `admin/users/[id]/page.tsx` zmenšen z 1137 na ~130 řádků (orchestrátor)
  • • 4 section komponenty: `section-header`, `section-user-info` (2 exporty), `section-broker-prefs`, `section-data-tables`
  • • Centrální hook `use-admin-user-detail.tsx` (13 state, fetch, 8 handlerů)
  • • Sdílené typy v `types.ts` (UserDetail, section Props)
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: Admin lead detail — rozpad na sekce a hook
  • • `admin/leads/[id]/page.tsx` zmenšen z 1187 na ~130 řádků (orchestrátor)
  • • 3 section komponenty: `lead-header-section`, `property-info-section`, `bids-table-section`
  • • Centrální hook `use-admin-lead-detail.tsx` (10 state, fetch, 15 handlerů)
  • • Section Props přidány do existujícího `lead-detail-types.ts`
  • • Existující `property-details-section` a `property-params-section` beze změn
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: Seller lead detail — rozpad na sekce a hook
  • • `seller/leads/[id]/page.tsx` zmenšen z 1254 na ~110 řádků (orchestrátor)
  • • 6 section komponent: `section-banners`, `section-match-info`, `section-collaboration`, `section-bids`, `section-lead-detail`, `section-actions`
  • • Centrální hook `use-lead-detail.ts` (18 state, fetch, 5 handlerů, derived values)
  • • Sdílené typy v `types.ts` (SellerLead, section Props)
  • • Deduplikovaný ContractConfirmButton (dříve 2x duplikovaný AlertDialog)
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: Seller lead edit — rozpad na field komponenty a hook
  • • `seller/leads/[id]/edit/page.tsx` zmenšen z 1256 na ~110 řádků (orchestrátor)
  • • 5 field komponent: `fields-apartment`, `fields-house`, `fields-commercial`, `fields-land-other`, `fields-shared`
  • • Centrální hook `use-edit-lead.ts` (state, fetch, performUpdate, handleSubmit)
  • • Sdílené typy v `types.ts` (SellerLead, EditFormData, INITIAL_EDIT_FORM, EditSectionProps)
  • • 3x duplikovaný inline PENB select nahrazen existující `<EnergyRatingSelect>` komponentou
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: Admin match detail — rozpad na komponenty a hook
  • • `admin/matches/[id]/page.tsx` zmenšen z 1493 na ~140 řádků (orchestrátor)
  • • 8 section komponent: `section-timeline`, `section-property`, `section-parties`, `section-broker-offer`, `section-sale`, `section-invoice`, `section-checkin`, `section-actions`
  • • Centrální hook `use-match-detail.ts` (state, fetch, 8 handlerů, email funkce)
  • • Sdílené typy v `types.ts`, business konstanty v `constants.ts`
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
  • Refactor: Profil stránka — rozpad na komponenty a hooky
  • • `profile/page.tsx` zmenšen z 2124 na 206 řádků (orchestrátor)
  • • 5 tab komponent: `tab-profile`, `tab-company`, `tab-notifications`, `tab-templates`, `tab-account`
  • • 5 custom hooků: `useProfileForm`, `useIcoVerification`, `useServiceProfiles`, `useChangePassword`, `useDeleteAccount`
  • • `useIcoVerification` deduplikuje dříve duplicitní kód (vlastní IČO + parent IČO)
  • • Utility `notification-prefs.ts` (getPref/setPref/deriveNotifyNewLeads)
  • • `CZECH_REGIONS` přesunuto do sdílených `lib/constants.ts`
  • • Nový `profile/types.ts` se sdílenými typy a props interfaces
  • • Žádná změna designu ani funkčnosti — čistě DX refaktorizace
7. dubna 2026
  • Feature: Email-driven match lifecycle (1-click tokeny + sale check)
  • • Nový systém řídí celý lifecycle matche přes email — seller nemusí na web
  • • 1-click potvrzení z emailu přes token (tabulka `email_action_tokens`, endpoint `/api/email-action`)
  • • Potvrzovací stránka `/email-action` s ochranou proti náhodnému kliknutí (Card + "Ano, potvrzuji")
  • • Fáze A: Contract prompt 7 dní po matchi (1-click token CTA místo odkazu na web)
  • • Fáze B: Contract reminder 21 dní po matchi + admin notifikace pokud nikdo nepotvrdil
  • • Fáze C: Sale check 42 dní (6 týdnů) po `contracted` — "Došlo k prodeji?"
  • • Fáze D: Opakovaný sale check každé 3 měsíce
  • • Nové email šablony: `contract_reminder`, `sale_check`
  • • Nový notifikační typ `cooperation` (smlouva + prodej) v profilu — nahrazuje `checkin`
  • • Starý check-in systém (Probíhá/Dokončeno/Problém) odstraněn — CheckinBanner ze seller/broker detailů
  • • `checkin-send` kompletně přepsán na v8 (match lifecycle)
  • • `send-notification-email` v21 (2 nové šablony + token CTA)
  • Feature: Nový stav matche `contracted` (Spolupráce zahájena)
  • • Nový stav mezi `watching` a `sale_reported` — indikuje podepsanou zprostředkovatelskou smlouvu
  • • Automatický přechod: broker potvrdí podpis smlouvy → stav `watching` → `contracted`
  • • Seller sám nestačí — čeká se na makléře (makléř by šel proti sobě, kdyby lhal)
  • • `contracted` NENÍ prerekvizita prodeje — broker může nahlásit prodej přímo z `watching`
  • • Admin matches list: nový tab "Spolupráce zahájena" s počítadlem
  • • Admin match detail: nový krok v timeline mezi "Spárováno" a "Nahlášeno"
  • • Watchdog (katastr) a check-in běží i ve stavu `contracted`
  • • DB migrace: rozšířen CHECK constraint na `matches.status`
  • • Upravené API routes: `confirm-contract`, `report-sale`, `confirm-sale-seller`
  • • Deploy Edge Functions: `checkin-send` v10, `watchdog-check` v16
  • Fix: Konzistentní mezery mezi kartami na seller/broker match detailu
  • • Sjednoceny margin-bottom na `mb-6` u všech Card sekcí na seller lead detailu (bylo mb-4/mb-6/mb-8)
  • • Sjednoceny margin-bottom na `mb-6` u všech Card sekcí na broker match detailu (bylo mb-8)
6. dubna 2026
  • UX: Broker match detail — kompletní info o nemovitosti + sbalitelné sekce
  • • Detail nemovitosti nyní zobrazuje všechny parametry (dispozice, stav, PENB, omezení, příslušenství, house features, rok kolaudace/rekonstrukce) — stejné info jako při dávání nabídky
  • • Exteriérové fotografie odhaleny po matchi (nově přidáno k interiérovým)
  • • Fotografie používají PhotoGallery komponentu s lightboxem (místo základního img gridu)
  • • Sekce nabídky zobrazuje kompletní detail: služby podle kategorií s checkmarky (readonly ServiceCheckboxes), další služby, zprávu, datum odeslání
  • • Opravena duplicitní přesná adresa (exact_address a street/zip/city zobrazovaly totéž)
  • • Obě sekce (nemovitost + nabídka) jsou sbalovací — nemovitost defaultně rozbalená, nabídka defaultně sbalená
  • • Collapsible trigger s ChevronDown animací a textem Zobrazit/Skrýt (konzistentní se seller detailem)
  • • Hero banner: přidán typ nemovitosti + lokace + plocha (např. "Byt - Plzeň - Bolevec 85 m²")
  • • Karta nemovitosti: popis změněn na "Podrobné informace o nemovitosti"
  • • Přijaté nabídky na `/broker/bids`: karta zobrazuje přesnou adresu místo anonymní lokality (po matchi)
  • • Hero banner match detailu: typ + přesná adresa (bez m², ty jsou v podrobnostech)
  • • Karta nemovitosti: zjednodušený nadpis "Podrobné informace o nemovitosti" (typ + adresa je v hero)
  • • Sjednoceno zarovnání collapsible CardHeaders — CardAction slot místo flex-row override + text-left fix na trigger buttons (seller i broker, 4 místa)
  • • AlertDialog potvrzení pro "Potvrdit podpis smlouvy" — ochrana proti náhodnému dotyku (seller i broker, 4 místa)
  • UX: Seller lead detail — zarovnání a sbalitelné nabídky
  • • Zarovnání tlačítka "Ano, prodej proběhl" na úroveň inputu prodejní ceny (fix `flex items-start`)
  • • Nabídky makléřů u matched leadu jsou nyní defaultně sbalené, rozbalí se kliknutím na Card trigger s textem "Zobrazit nabídky"
  • • Detail poptávky u matched leadu také defaultně sbalený — trigger je přímo v CardHeader (jedna Card, ne dva oddělené boxy), u ostatních stavů vždy rozbalený
  • • Sloučení sekcí smlouvy a prodeje do jedné Card (seller i broker) — Separator mezi sekcemi
  • • Redesign Card "Stav spolupráce" — CardHeader s nadpisem, sekční nadpisy, info-box styl na stavových zprávách (seller i broker)
  • • Vertikální layout prodeje (input + tlačítko pod sebou, konzistentně se smlouvou)
  • • Sjednocení collapsible triggerů — nabídky i detail poptávky používají CardTitle + CardDescription (stejná velikost, výška)
  • Feature: Potvrzení smlouvy a prodeje — obě strany
  • • Seller i broker mohou nezávisle potvrdit podpis zprostředkovatelské smlouvy (nová UI sekce na detailu leadu/matche)
  • • Seller může potvrdit prodej nemovitosti (paralelně k broker report-sale, volitelná cena)
  • • 4 stavy smlouvy: nikdo nepotvrdil → jedna strana → obě strany → success
  • • Automatický email "Podepsali jste smlouvu?" 7 dní po matchi (CRON Fáze D v checkin-send v6)
  • • 4 nové email šablony: `contract_prompt`, `contract_signed_notification`, `contract_both_signed`, `seller_confirmed_sale`
  • • 2 nové API endpointy: `/api/confirm-contract`, `/api/confirm-sale-seller` (Bearer JWT auth, rate limit, audit log)
  • • Admin match detail: zobrazení stavu smlouvy a seller potvrzení prodeje
  • • DB migrace: 5 nových sloupců v `matches` (contract_signed_by_seller_at, contract_signed_by_broker_at, seller_confirmed_sale_at, seller_confirmed_sale_price, contract_prompt_sent_at)
  • Notifikace: Sjednocení check-in emailů do brand design systému
  • • Check-in emaily (broker, seller, reminder, red flag) nyní používají stejný brand design jako ostatních 13 typů emailů
  • • Přidány 4 nové šablony do `send-notification-email` v19: `checkin_broker`, `checkin_seller`, `checkin_reminder`, `checkin_red_flag`
  • • Nový helper `checkinButtons()` — 3 CTA tlačítka (Probíhá/Dokončeno/Problém) v brand paletě
  • • Refaktorován `checkin-send` v5 — emaily posílány přes `send-notification-email` (místo přímého Resend API)
  • • Opravena chybějící diakritika v in-app notifikacích check-in systému ("Pripominame" → "Připomínáme")
  • • Zdrojový kód `checkin-send` přidán do lokálního repo (`supabase/functions/checkin-send/index.ts`)
  • UX: Sjednocení stylu placeholderů napříč webem
  • • Přidána kurzíva (`italic`) pro všechny placeholdery — centrálně v Input, Textarea, Select a LocationFilter komponentách
  • • Prefix "např." u 25 placeholderů, které vypadaly jako reálná data (jméno, telefon, IČO, bank. účet, cena, provize)
  • • Dotčené stránky: registrace, profil, kontakt, broker nabídka/match, admin match/networks
  • • Auth emaily (login, registrace, forgot-password) ponechány bez "např." — standardní UX pattern
  • UX: Kontaktní údaje po matchi — email + telefon pro obě strany
  • • Prodávající nyní vidí telefon a email makléře v kontaktní kartě po spárování
  • • Makléř nyní vidí email prodávajícího vedle telefonu v kontaktní kartě
  • • Nová RPC funkce `get_match_contact_email(match_id)` — bezpečně vrací email protistrany (SECURITY DEFINER, ověření účasti v matchi)
  • • Sjednocený design kontaktních karet (seller i broker): bg-[#f5f0ff], label-above-value grid, klikací tel:/mailto: linky
  • Fix: Chybějící diakritika v in-app notifikacích
  • • Opravena chybějící česká diakritika v 10 textových řetězcích notifikací (SQL triggery + Edge Function)
  • • Postižené notifikace: bids_ready, new_lead, match (seller i broker), lead_approved (auto-approve)
  • • Nová migrace `20260406_fix_notification_diacritics.sql` — 3x `CREATE OR REPLACE FUNCTION`
  • • Edge Function `auto-approve-leads` v7 — opraveny 2 textové řetězce
  • • Retroaktivně opraveny existující záznamy v tabulce `notifications`
5. dubna 2026
  • Security: HTML injection fix + rate limiting
  • • Přidána `escapeHtml()` utilita — všechny uživatelské vstupy v support ticket emailech jsou nyní escapovány
  • • Přidán rate limit na `/api/staging-auth` (5/min, brute-force ochrana)
  • • Opravena špatná rate limit konstanta na `/api/send-notification` (reverseGeocode → sendNotification)
  • Fix: SQL trigger funkce — source control + deprecated GUC
  • • 4 notification trigger funkce (notify_brokers_new_lead, notify_new_bid, notify_match_created, notify_admin_pending_review) + 6 triggerů nyní trackováno v migracích
  • • `notify_new_bid` a `notify_match_created` opraveny: odstraněn deprecated `current_setting()`, vault-only pattern
  • Refactor: Kódová konzistence
  • • Extrahována duplicitní `evaluateCheckinResponses()` do sdíleného `lib/checkin-utils.ts` s proper SupabaseClient typem
  • • 16x `alert()` nahrazeno `toast.error()` ve 3 admin stránkách (users, leads, networks)
  • • 14x `toLocaleDateString("cs-CZ")` nahrazeno `formatDate()` utilitou v 9 souborech
  • UX: Placeholdery ve formuláři poptávky
  • • Číselné placeholdery ve Step 3 (Parametry) dostaly prefix "např." — plocha, patro, celkem pater, počet místností
  • • Předchozí placeholdery ("3", "5", "75") vypadaly jako vyplněná data
4. dubna 2026
  • Feature: Schvalování registrace makléřů
  • • Nové sloupce v `profiles`: `approved_at`, `approved_by`, `registration_rejection_reason`
  • • CHECK constraint rozšířen o `pending_approval` a `rejected`
  • • `handle_new_user()` — brokeři dostanou `status = 'pending_approval'`
  • • Trigger `notify_admin_pending_broker()` — in-app notifikace adminům
  • • SQL funkce `cleanup_rejected_brokers()` + CRON denně 3:00 UTC
  • • Nová stránka `/auth/pending-approval` — čekací/zamítnutá stránka s pollingem (30s)
  • • `useAuthGuard` — KONTROLA 4.5: redirect pending/rejected brokerů
  • • `/auth/verify` — fix double-redirect pro pending brokery
  • • `/auth/register/broker` — info text "Registrace podléhá schválení"
  • • `/admin/users/[id]` — tlačítka Schválit/Zamítnout, info karta, dual-write notifikace
  • • `/admin/users` — filtr "Ke schválení" + "Zamítnutí", status badge
  • • Audit log: `approve_broker`, `reject_broker` akce
  • • `send-notification-email` v18 — nové šablony `broker_approved`, `broker_rejected`
  • • `/api/send-notification` whitelist rozšířen
  • • `supabase/migrations/20260404120000_broker_pending_approval.sql`
  • • `supabase/functions/send-notification-email/index.ts`
  • • `frontend/src/hooks/useAuthGuard.ts`
  • • `frontend/src/app/auth/pending-approval/page.tsx` (NOVÝ)
  • • `frontend/src/app/auth/verify/page.tsx`
  • • `frontend/src/app/auth/register/broker/page.tsx`
  • • `frontend/src/app/admin/users/[id]/page.tsx`
  • • `frontend/src/app/admin/users/page.tsx`
  • • `frontend/src/app/admin/audit/page.tsx`
  • • `frontend/src/app/api/send-notification/route.ts`
  • • `frontend/src/lib/supabase/types.ts`
  • Fix: Audit log filtry — responsivní layout při středních šířkách
  • • `frontend/src/app/admin/audit/page.tsx` — `lg:grid-cols-5` → `xl:grid-cols-5`, search span na `md:col-span-2`
  • Fix: Audit log — detail pod řádkem + vyhledávání podle e-mailu
  • • Detail se nyní renderuje jako inline řádek přímo pod kliknutým záznamem
  • • Přidáno vyhledávání podle e-mailu (paralelní fetch přes `get_users_with_email` RPC)
  • • E-mail zobrazen pod jménem ve sloupci Uživatel
  • • CSV export rozšířen o sloupec E-mail
  • • `frontend/src/app/admin/audit/page.tsx` — Fragment pattern pro inline detail, email fetch + zobrazení + search
  • Enhance: Audit log — obohacená metadata pro právní důkazy
  • • `create_lead` — přidáno: ulice, PSČ, dispozice, kraj, okres, entity ID
  • • `create_match` — přidáno: město, typ, ulice, jméno makléře, ID makléře, cena nabídky, provize
  • • `extend_lead` — přidáno: město, typ nemovitosti
  • • `submit_bid` — přidáno: město a typ poptávky
  • • `submit_rating` — přidáno: jméno makléře
  • • `approve_lead` / `reject_lead` — přidáno: město, typ, jméno prodávajícího
  • • 7 match akcí (confirm_sale, issue_invoice, record_payment, cancel_match, revert_to_watching, approve/reject_sale_report) — přidáno: jméno makléře/prodávajícího, město, ceny, faktury
  • • `change_match_status` — přidáno: jméno makléře, město
  • • 3 user akce (change_role, suspend, unsuspend) — přidáno: jméno a email cílového uživatele
  • • `moderate_rating` — přidáno: jména makléře/prodávajícího, hodnocení
  • • České popisky metadata klíčů (property_type → "Typ nemovitosti", broker_name → "Makléř" atd.)
  • • Překlad hodnot (typ nemovitosti, ceny formátovány jako Kč)
  • • On-demand entity fetch při rozbalení řádku — kontext z DB pro staré záznamy (lead, match, bid, rating, support_ticket)
  • • Cache pro zamezení opakovaných dotazů
  • • `frontend/src/app/admin/audit/page.tsx` — METADATA_KEY_LABELS, entity cache + fetch, EntityContext sekce
  • • `frontend/src/app/seller/new-lead/page.tsx`, `seller/leads/[id]/page.tsx`, `seller/rate/[matchId]/page.tsx`
  • • `frontend/src/app/broker/leads/[id]/page.tsx`
  • • `frontend/src/app/api/extend-lead/route.ts`, `api/report-sale/route.ts`, `api/submit-rating/route.ts`
  • • `frontend/src/app/admin/leads/[id]/page.tsx`, `admin/matches/[id]/page.tsx`, `admin/matches/page.tsx`
  • • `frontend/src/app/admin/users/[id]/page.tsx`, `admin/ratings/page.tsx`
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í