Phase 1 step 3 — make NotificationsPublisher available via DI and
introduce the NOTIFICATIONS_ASYNC_ENABLED flag that will gate the
listener cutover.
- NotificationsAsyncConfig: tiny injectable that reads
NOTIFICATIONS_ASYNC_ENABLED (truthy: 1/true/yes/on, default disabled).
Callers don't touch process.env directly; per-category rollout can be
added later without churn in listeners.
- NotificationsModule providers/exports now include NotificationsPublisher
and NotificationsAsyncConfig so listeners/handlers can inject them.
- Tests (14 specs on the flag + 4 on the publisher = 18 total green):
* default disabled when unset
* truthy parsing (1, true, TRUE, yes, on, padded)
* falsy parsing (false, 0, no, off, empty, unknown)
* describe() reports human-readable state
No call sites updated yet — next commit migrates the first listener
(PaymentCompletedListener pilot) onto the publisher with the flag check.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Refactors /agents/[id] from card-avatar layout to a data-dense
trading-floor style profile per TEC-3037 §5 mockup.
- Profile header: avatar, KYC badge, quality score, years exp, service areas
- KPI strip (5 cards): total listings, active, deals, avg price, rating
- Performance line chart (12m): published vs sold, derived from real listings
- Listings table (DataTable): sortable by price/area/views/inquiries, dense rows
- Reviews panel: EmptyState when none, ReviewRow cards otherwise
- Sticky right sidebar: contact card + quality donut + bio
- fetchAgentListings() server fn (agents-server.ts) via GET /listings?agentId
- SearchListingsParams.agentId added (listings-api.ts)
- page.tsx fetches listings in parallel with agent + reviews
- Test suite updated for new props (listings/listingsTotal) + new text copy
- Web unit tests: 82/82 files pass, 697/697 tests pass
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The "Nhắn tin" (Message) button on the agent profile ContactCard had no
onClick handler. Now opens the InquiryModal using the agent's first
active listing, or falls back to SMS for agents with no listings.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Implements a public-facing agent profile page with:
- Backend: new GET /agents/:agentId/profile public API endpoint with
agent info, active listings, quality score, and review stats
- Frontend: server-rendered profile page with generateMetadata for SEO,
JSON-LD structured data (RealEstateAgent schema), breadcrumbs
- Agent profile displays bio, service areas, quality score gauge,
active listing cards, reviews with star ratings, and contact CTA
- Mobile responsive layout with sticky contact sidebar on desktop
- Vietnamese UI text throughout, consistent with existing patterns
Co-Authored-By: Paperclip <noreply@paperclip.ing>