All four alert code paths that previously loaded the entire SavedSearch
table into memory are replaced with bounded batch iteration backed by
the idx_savedsearch_alert_enabled partial index (merged in GOO-118).
Batch size is 500 rows; order-by is createdAt ASC, which matches the
index definition so the planner uses it for both the WHERE clause and
the cursor predicate.
Changed files:
- saved-search-alert.handler.ts: keyset loop on createdAt with
alertEnabled=true, ALERT_BATCH_SIZE=500
- saved-search-alert-cron.service.ts: same pagination loop, removes
the early-return on empty set (loop exits naturally on first empty page)
- residential-events.listener.ts: ResidentialPriceDropListener and
ResidentialNewListingInProjectListener both paginated; select now
includes createdAt to advance the cursor; shared ALERT_BATCH_SIZE
Tests:
- saved-search-alert.handler.spec.ts: adds createdAt to mock rows, adds
3-page pagination test and orderBy/take assertion
- residential-events.listener.spec.ts: adds createdAt to mock rows, adds
501-row pagination test verifying cursor advance on second call (9
existing tests all pass)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Create apps/web/lib/phone.ts with VN_PHONE_REGEX, normalizePhone,
formatPhone, and zaloHref helpers
- Deduplicate phone regex: auth.ts and inquiry.ts now import VN_PHONE_REGEX
from @/lib/phone instead of defining their own local patterns
- Replace raw .replace(/^0/, '84') in inquiry-detail-dialog.tsx and
lead-detail-dialog.tsx with zaloHref(); use formatPhone() for display
Resolves GOO-209
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Rewrite prisma/seed.ts to populate all 27 models with realistic
Vietnamese real estate data (8 users with login, 10 properties,
10 listings, orders, payments, reviews, notifications, etc.)
- Replace all emoji icons with Lucide React SVG icons across frontend
for consistent rendering, sizing, and accessibility
- Redesign dashboard nav: grouped sidebar with section headers,
primary/secondary split on desktop, icon-only secondary items
- Replace language switcher flag emoji with Globe icon
- Replace SVG theme toggle with Lucide Moon/Sun icons
- Fix API startup: graceful fallback for Sentry profiling, Google OAuth,
and Zalo OAuth when credentials are not configured
- Relax rate limiting in development mode (10k req/min)
- Fix listings API to include media[] array in search response
- Add optional chaining for property.media across frontend components
- Update OAuth strategy tests to match graceful fallback behavior
Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>