Add a horizontal FilterBar component with popover-based dropdowns for
Price, Beds, Size, and a "More Filters" panel with advanced options
(price/m2, furnishing, district, date, POI travel filters). Action
buttons (Show Listings / Scrape New) are aligned to the right.
Add FilterChips component that renders active (non-default) filter
values as removable pills below the filter bar.
- Wrap App in BrowserRouter in main.tsx
- Create useFilterParams hook that syncs filter state with URL search params
and derives viewMode from the URL pathname
- Replace window.location.pathname callback check with React Router Routes
- Split App into AppContent (main UI) and App (route definitions)
- Primary/accent changed from achromatic black to teal (oklch 0.55 0.14 175)
- Background/foreground given subtle cool slate tint
- Added --deal-good (emerald) and --deal-above (amber) custom properties
- Ring color updated to teal for focus states
- Dark mode updated to match teal theme
Approach C: Map-First with Modern Chrome
- Horizontal filter bar replacing sidebar
- React Router for URL state / deep linking
- Redesigned property cards with better visual hierarchy
- Refined color palette and typography
- Tabbed listing detail sheet
Replace .drone.yml with .woodpecker/ pipeline configs (frontend.yml, api.yml).
Convert Drone env vars to Woodpecker equivalents (CI_PIPELINE_NUMBER, CI_COMMIT_SHA),
use woodpeckerci/plugin-git for clone with retry, woodpeckerci/plugin-slack for
notifications, and plugins/docker for image builds. Update all docs and skills.
Instrument every API endpoint with Server-Timing headers so sub-operation
durations are visible in browser DevTools Network tab. Also adds Grafana
dashboard panels for per-endpoint latency comparison (p50/p95 timeseries
and p95 ranking bar gauge).
- Increase Redis cache TTL from 30 minutes to 24 hours
- Add stale-while-revalidate: serve stale cache (>4h) immediately while
repopulating in background with SETNX lock to prevent concurrent rebuilds
- Add in-memory frontend LRU cache (5 entries) so repeat filter visits
are instant without network requests
- Invalidate frontend cache on listing refresh and task completion
- Add unit tests for get_cache_age, is_cache_stale, acquire_repopulation_lock
Add spec.paused: null to the strategic merge patch to clear any
paused state that might be blocking rollouts. Also add detailed
deployment status debug output (conditions, replica counts,
paused state) and list ReplicaSets to diagnose why new pods
aren't being created despite spec changes.
The JSON Patch was updating the deployment spec image but K8s wasn't
creating new pods — the rollout was stuck from previous failed builds.
Switch to strategic-merge-patch that also sets restartedAt annotation,
equivalent to 'kubectl rollout restart', which forces K8s to create
a new ReplicaSet regardless of stalled rollout state.
- Add prefers-reduced-motion support (global CSS + SwipeCard spring config)
- Add dismissible map click hint overlay with localStorage persistence
- Replace generic image alt text with descriptive property info across 4 components
- Rename filter buttons to clarify intent (Show Matching Listings / Scrape New from Rightmove)
- Fix mobile FAB overlap with bottom sheet via dynamic snap-aware positioning
- Add swipe review onboarding overlay with gesture explanations and button labels
- Delete unused components: AppSidebar, ActiveQuery, SavedView
Show deployment spec image to confirm patch worked, dump all pod
details (image, ready, phase, restarts, reason) on attempts 1/10/30
and on failure. This will reveal whether pods are crashlooping, stuck
in Pending, or if the deployment patch didn't take effect.
Init OTel metrics at module level in celery_app.py so prefork child
processes inherit the MeterProvider and PrometheusMetricReader from
the parent. Previously, worker_process_init created a separate
MeterProvider in each child, disconnected from the HTTP server in
the main process — so all scrape/celery/OCR metrics were silently
lost.
Update Grafana dashboard with API Performance and Frontend Performance
sections, synced from the live cluster dashboard.
Kubernetes may normalize image references to include docker.io/ prefix
(e.g., docker.io/viktorbarzin/realestatecrawler:356), causing exact
string match to fail. Use endswith() instead. Also add debug output
on first attempt to show actual pod images and readiness state.
Collect browser-side worker round-trips, computation times, main-thread
operations, and feature counts, batch them client-side, and expose as
Prometheus histograms via a new POST /api/perf endpoint.
The jq filter required pods to be younger than 60 seconds AND ready,
but pods often take longer than 60s to become ready (alembic migrations,
image pull, etc.), causing the check to never match. The image tag check
is sufficient to confirm the new version is running. This aligns the API
verify-deploy with the frontend verify-deploy which has no age filter.