Commit Graph

42 Commits

Author SHA1 Message Date
Ho Ngoc Hai
79e173938b feat(avm): end-to-end AVM v2 schema + POST /analytics/valuation endpoint
Some checks failed
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m31s
Deploy / Build API Image (push) Failing after 25s
E2E Tests / Playwright E2E (push) Failing after 23s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 6s
Deploy / Build Web Image (push) Failing after 17s
Deploy / Build AI Services Image (push) Failing after 13s
Security Scanning / Trivy Scan — Web Image (push) Failing after 58s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 51s
Security Scanning / Trivy Scan — API Image (push) Failing after 1m55s
Security Scanning / Trivy Filesystem Scan (push) Failing after 45s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 3s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 8s
CI / E2E Tests (push) Has been skipped
Closes the last gap from the tec-2725 branch: the valuation form's v2
extended-features section and POST endpoint can now submit real
predictions through to the Python ensemble model.

Backend
- New DTO apps/api/src/modules/analytics/presentation/dto/predict-valuation.dto.ts
  with all v1 fields + 8 v2 fields (useV2 toggle, distanceToHospital/Park/
  Mall in km, floodZoneRisk enum NONE|LOW|MEDIUM|HIGH, hasElevator/
  Parking/Pool booleans).
- New CQRS handler apps/api/src/modules/analytics/application/queries/
  predict-valuation/ that routes to AVM_SERVICE.estimateValue() with the
  full request body.
- Extend AVMParams (domain) with the same v2 fields + inline v1 fields
  (district, city, bedrooms, bathrooms, floors, frontage, roadWidth,
  hasLegalPaper, projectId, imageUrl, description, deepAnalysis).
- HttpAVMService.estimateViaAi now branches on `useV2`: v2 calls the new
  aiClient.predictV2() → POST /avm/v2/predict on the Python service,
  mapping floodZoneRisk enum → 0..1 float and computing
  building_age_years from yearBuilt. v1 path gets all the inline
  descriptors wired through so non-propertyId calls no longer lose
  context.
- AiServiceClient gets AiPredictV2Request / AiPredictV2Response types
  mirroring libs/ai-services/app/models/avm_v2.py::AVMv2PredictRequest
  (which already accepts all 7 numeric/boolean v2 fields — no Python
  change needed).
- Register PredictValuationHandler in AnalyticsModule.
- New route POST /analytics/valuation on AnalyticsController:
  JwtAuthGuard + QuotaGuard + EndpointRateLimitGuard (10/min),
  @RequireQuota('analytics_queries'), full Swagger doc. Total endpoint
  count 179 → 180.

Frontend
- Extend ValuationRequest with useV2, 3 distance-km fields,
  floodZoneRisk, hasElevator/Parking/Pool + export FloodZoneRisk type
  and FLOOD_RISK_OPTIONS.
- valuationApi.predict() body mapping now includes v2 fields and renames
  'areaM2' → 'area' to match the backend DTO contract.
- valuationFormSchema gains matching optional Zod fields + exports
  FLOOD_RISK_OPTIONS for the form.
- valuation-form.tsx gets:
  * Image upload hardening: MIME+size validation (JPG/PNG ≤5MB) before
    preview, role="progressbar" + aria-labels on the progress bar,
    role="alert" + data-testid="image-upload-error" on errors. Matches
    the upload-progress part of the task/tec-2725 commit 4ee0129 that
    was previously parked as blocked.
  * New Sparkles-branded "Mô hình v2 (Ensemble)" toggle alongside the
    existing Bot-branded "Phân tích chuyên sâu" toggle.
  * Collapsible "Đặc trưng mở rộng (AVM v2)" section with distance
    inputs, flood-risk select, and three amenity checkboxes.
  * handleFormSubmit passes all v2 fields through to onSubmit.

Python service unchanged — AVMv2PredictRequest already has every field
we send (distance_to_hospital_km, flood_zone_risk as float,
has_elevator/parking/pool, etc.).

Typecheck clean for the valuation surface. Pre-existing errors in
metadata.spec.ts and transfer-wizard-client.tsx are unrelated and left
for a follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 06:49:57 +07:00
Ho Ngoc Hai
492bd0a043 feat(web): enable residential projects feature flag by default for MVP
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 8s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 44s
Deploy / Build AI Services Image (push) Failing after 9s
E2E Tests / Playwright E2E (push) Failing after 8s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 37s
Security Scanning / Trivy Scan — Web Image (push) Failing after 31s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 38s
Deploy / Deploy to Staging (push) Has been cancelled
Deploy / Deploy to Production (push) Has been cancelled
Deploy / Smoke Test Staging (push) Has been cancelled
Deploy / Rollback Staging (push) Has been cancelled
Deploy / Rollback Production (push) Has been cancelled
Deploy / Build API Image (push) Failing after 11s
Deploy / Build Web Image (push) Failing after 9s
Deploy / Smoke Test Production (push) Has been cancelled
Security Scanning / Security Gate (push) Has been cancelled
Security Scanning / Trivy Filesystem Scan (push) Has been cancelled
Flip NEXT_PUBLIC_FEATURE_RESIDENTIAL_PROJECTS default from false to
true so /du-an and /du-an/[slug] render without requiring an env var
or ?residential_projects=1 query override. Kill-switch preserved —
set the env var to "0"/"false" to disable.

The homepage now advertises Dự án as a core feature; having the page
404 by default contradicted that positioning.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 21:59:54 +07:00
Ho Ngoc Hai
38b9def99a feat: implement project development module, transfer management features, and industrial AVM model integration 2026-04-18 20:34:35 +07:00
Ho Ngoc Hai
580eb2a261 feat(web): residential_projects feature flag for /du-an routes (TEC-2757)
- Add useResidentialProjectsFlag hook with NEXT_PUBLIC_FEATURE_RESIDENTIAL_PROJECTS env + URL/localStorage override (mirrors AVM v2 pattern)
- Gate /du-an index (client) and /du-an/[slug] detail (server) routes via notFound() when flag disabled
- Add component tests for index page including disabled-flag notFound branch

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-18 15:13:06 +07:00
Ho Ngoc Hai
5d4ecdeb2f feat(web): AVM v2 upgraded valuation dashboard (TEC-2763)
R5.4 ships the upgraded AVM UI behind the `avm_v2` A/B flag. When the
flag is on, the dashboard exposes:

- Tab switch between single valuation and multi-property compare
- Waterfall drivers chart (ValueDriversChart) alongside the existing
  horizontal bar breakdown
- Mapbox comparables map with similarity-coloured markers and an
  optional highlighted subject pin
- Confidence interval + range bar and PDF export remain available
- Valuation history chart surface unchanged (still lazy-loaded)

Flag plumbing (useAvmV2Flag):
- NEXT_PUBLIC_FEATURE_AVM_V2=1 enables by default
- `?avm_v2=1|0` URL param forces + persists to localStorage
- safe localStorage handling (no throw when storage is blocked)

Tests: comparables-map, value-drivers-chart, use-avm-v2-flag specs
added. Pre-existing "Yếu tố chính" assertion in valuation-results.spec
updated to match the current copy ("Yếu tố ảnh hưởng giá") so the
valuation suite is green (7 files, 52 tests).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-18 15:05:46 +07:00
Ho Ngoc Hai
8e9d021465 feat: add unit tests for featured listings, neighborhood scores + price history chart
- Add unit tests for FeatureListingHandler (6 tests) and ActivateFeaturedListingHandler (6 tests)
- Add unit tests for NeighborhoodScoreServiceImpl (5 tests) and GetNeighborhoodScoreHandler (2 tests)
- Add PriceHistoryChart component with recharts LineChart for listing detail page
- Wire up price history API client and integrate chart into listing detail view

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-16 18:21:44 +07:00
Ho Ngoc Hai
8592fb436c feat(web): integrate neighborhood radar chart into listing detail page
Add NeighborhoodRadarChart to listing detail view, fetching scores
from the analytics API based on the listing's district and city.
Displays a 6-axis radar chart (education, healthcare, transport,
shopping, environment, safety) with overall score and color-coded
badges.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-16 17:05:26 +07:00
Ho Ngoc Hai
24a2fd1369 fix(web,prisma): fix TypeScript errors in transfer wizard and schema
- Fix Zod v4 enum API: replace deprecated `required_error` with `error`
- Create missing TransferWizardClient component (4-step wizard: category, items, AI estimate, submit)
- Add CANCELLED status to TransferListingStatus enum for soft-delete support

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-16 17:02:20 +07:00
Ho Ngoc Hai
5810f0be56 feat(web): add industrial compare page, listing search, and Mapbox park map
- Add interactive Mapbox map to /khu-cong-nghiep landing page with park markers and popups
- Build compare page at /khu-cong-nghiep/so-sanh with recharts RadarChart and detailed comparison table
- Build listing search page at /khu-cong-nghiep/cho-thue with filters for property type, lease type, area, and price
- Add IndustrialListing types, API client functions, and React Query hooks

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-16 12:40:35 +07:00
Ho Ngoc Hai
7ce651fce5 feat(web): add khu-cong-nghiep, chuyen-nhuong, and reports pages
Add three new frontend page sections:
- Industrial parks (khu-cong-nghiep): listing, detail, filter bar
- Transfer listings (chuyen-nhuong): search, category tabs, detail
- AI reports dashboard: list, create, viewer with TOC

Includes components, API clients, hooks, server helpers, i18n keys,
navigation links in public and dashboard layouts, and lint fixes.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-16 09:07:45 +07:00
Ho Ngoc Hai
e21e096e54 feat(web): complete du-an project pages, neighborhood components, and public notification bell
- Add grid/map view toggle on /du-an listing page with Mapbox project markers
- Enhance du-an detail with master plan viewer, neighborhood radar chart, POI map, and price history chart
- Create neighborhood component suite: radar chart (Recharts), POI map (Mapbox), score badges
- Add du-an API client, server-side fetching, and React Query hooks
- Wire NotificationBell into public layout header for authenticated users
- Fix missing PROJECT_STATUS_COLORS import in du-an detail client

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-16 05:11:21 +07:00
Ho Ngoc Hai
8da488711b feat(analytics): AVM v2 batch valuation, comparison, history + frontend upgrade
Add batch valuation (POST /analytics/valuation/batch, max 50 properties),
valuation comparison (POST /analytics/valuation/compare, 2-5 properties),
and history endpoint (GET /analytics/valuation/history/:propertyId) with
confidence explanation helper. Frontend: enhanced valuation form with project
autocomplete and deep analysis toggle, results with confidence badges and
price range visualization, comparables table, history chart, market context
card, and PDF export.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-16 05:08:05 +07:00
Ho Ngoc Hai
4400d0c123 feat: add real-time notification system with Socket.IO client
Implements the frontend notification client for TEC-2217:

1. notifications-api.ts — API client for list, unread-count,
   markAsRead, markAllAsRead endpoints
2. notifications-store.ts — Zustand store for notification state
   (recent list, unread count, dropdown open state)
3. use-socket-notifications.ts — Socket.IO hook that connects with
   httpOnly cookie auth, listens for notification:new events,
   auto-reconnects, and syncs unread count on (re)connect
4. notification-bell.tsx — Bell icon with unread badge + dropdown
   showing 10 most recent notifications with time-ago formatting,
   mark-as-read on click, mark-all-as-read, and "Xem tất cả" link
5. notifications-provider.tsx — Provider wired into locale layout
   (inside AuthProvider) to initialize Socket.IO connection
6. Dashboard header — NotificationBell placed before LanguageSwitcher

Added socket.io-client dependency.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-16 02:24:21 +07:00
Ho Ngoc Hai
eebe24e1ae fix(docker): MinIO healthcheck curl probe + Redis password in .env.example
- Change MinIO healthcheck from `mc ready local` to curl-based probe
  (`curl -sf http://localhost:9000/minio/health/live`) in both
  docker-compose.yml and docker-compose.prod.yml, matching the
  approach already used in docker-compose.ci.yml
- Add descriptive placeholder for REDIS_PASSWORD in .env.example
  (was empty, now has CHANGE_ME_IN_PRODUCTION reminder)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-15 11:23:34 +07:00
Ho Ngoc Hai
ccfc176e40 fix: valuation page Vietnamese diacritics, correct API routes, update tests
- Add proper Vietnamese diacritics to all valuation components
  (form, results, history) and their test assertions
- Fix valuation API client to use /analytics/valuation endpoint
- Return empty history gracefully (no server endpoint yet)

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
2026-04-13 12:03:47 +07:00
Ho Ngoc Hai
1ebdc5f0b3 fix: auth cookies cross-origin, async params, CSRF/web-vitals errors
- Set SameSite=lax for auth & CSRF cookies in development (cross-port)
- Set refresh_token cookie path to / (was /auth, preventing cross-port send)
- Await params in Next.js 15 async server components (layout, listings, agents)
- Add CSRF token to web-vitals POST requests
- Fix: 401 Unauthorized on all authenticated API calls from web app
- Fix: CSRF token missing on POST requests from different port
- Fix: params.locale sync access warning in generateMetadata

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
2026-04-13 11:24:45 +07:00
Ho Ngoc Hai
a9fa214544 feat: comprehensive seed, Lucide icons, grouped dashboard nav, API fixes
- 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>
2026-04-13 11:13:04 +07:00
Ho Ngoc Hai
1fbe2f4e73 feat: add MFA/TOTP auth, PII encryption, agents/leads/inquiries modules, and comprehensive tests
- Add TOTP-based MFA with setup, verify, disable, backup codes, and challenge flow
- Add PII field encryption middleware with AES-256-GCM and deterministic search hashes
- Add agents, inquiries, and leads domain modules with entities, events, value objects
- Add web dashboard pages for inquiries and leads with detail dialogs
- Add 30+ component tests (valuation, charts, listings, search, providers, UI)
- Add Prisma migrations for encryption hash columns and MFA TOTP support
- Fix all ESLint errors (unused imports, duplicate imports, lint auto-fixes)
- Update dependencies and lock file
- Clean up obsolete exploration/QA docs, add audit documentation

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-11 23:43:20 +07:00
Ho Ngoc Hai
8ca64e3267 feat(web): add saved searches, image lightbox, and web vitals tracking
New features:
- Saved searches dashboard page with CRUD hooks and API client
- Image lightbox component for property gallery full-screen viewing
- Web vitals provider and reporting utilities for performance monitoring
- Image blur placeholder generation utility

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-11 01:39:22 +07:00
Ho Ngoc Hai
0593d40098 fix(lint): resolve all 24 ESLint errors across web, api and e2e
- Remove unused imports (waitFor, useAuthStore) in dashboard test files
- Convert import() type annotation to import type in comparison-store spec
- Add next-env.d.ts to ESLint ignores (auto-generated file)
- Fix empty object pattern in auth.fixture.ts
- Sort import order alphabetically in 5 API test files

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-11 00:42:00 +07:00
Ho Ngoc Hai
62485fee98 feat(agents): add public agent profile page at /agents/[id]
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>
2026-04-11 00:16:19 +07:00
Ho Ngoc Hai
37fab515b7 feat(web): add property comparison page with side-by-side view
Build a complete property comparison feature at /compare:
- Zustand store with localStorage persistence for selected listings (2-5)
- Side-by-side comparison table (price, area, price/m², amenities, location, etc.)
- Summary statistics banner (price range, area range, price/m² range)
- "Add to Compare" button on property cards and detail pages
- Floating comparison bar for quick access when listings are selected
- Bilingual i18n support (Vietnamese + English)
- 18 unit tests for store logic and comparison stats computation
- Mobile-responsive layout with horizontal scroll on comparison table

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 23:55:50 +07:00
Ho Ngoc Hai
55a01c5738 feat(web): centralise Vietnamese price formatting across all pages
Create a single `currency.ts` utility with `formatPrice`, `formatVND`,
`formatPricePerM2`, and `parseVND` to replace 9+ duplicated inline
formatters. This fixes inconsistent decimal handling (1.5M was truncated
to "1 triệu") and standardises price/m² display. Integrated across
property cards, listing detail, dashboard, analytics, payments, pricing,
and admin moderation pages with 19 new unit tests.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 23:33:31 +07:00
Ho Ngoc Hai
50c5168529 feat(web): add SEO optimization — JSON-LD, dynamic sitemap, meta tags for listings
Add comprehensive SEO support for property listing pages to improve
organic search visibility and social sharing.

Changes:
- Convert listing detail page from client-only to server component wrapper
  with generateMetadata() for per-listing title, description, OG tags,
  canonical URLs, and hreflang alternates
- Add JSON-LD structured data (Schema.org RealEstateListing) with price,
  location, property specs, and breadcrumb markup
- Add Website JSON-LD with SearchAction to root layout
- Upgrade sitemap.xml to dynamically include all active listings across
  both locales (vi, en) with ISR revalidation
- Improve robots.txt with pagination/sort exclusions and GPTBot block
- Create server-side fetch utility (listings-server.ts) for SSR data
- Extract client UI into ListingDetailClient component

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 20:38:28 +07:00
Ho Ngoc Hai
ab478a565a feat(web): add QueryErrorBoundary and use real map coordinates
Add global QueryErrorResetBoundary wrapping the app so TanStack Query
errors are caught with a retry UI instead of crashing. Enable
throwOnError in QueryClient defaults. Update ListingMap to use real
latitude/longitude from API when available, falling back to city-based
jitter for listings without coordinates.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 17:58:35 +07:00
Ho Ngoc Hai
a5f260ce67 docs: add K6 endpoints summary and quick start guide
- K6_ENDPOINTS_SUMMARY.md: Quick reference for all API endpoints with request/response shapes
- K6_QUICK_START.md: Practical guide with executable examples for search, auth, listing, and payment load tests
- Includes example K6 scripts, CI integration template, and troubleshooting
- Complete with load test scenarios and reporting options

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 01:35:29 +07:00
Ho Ngoc Hai
3c6ed4c82a feat(web): add Property Valuation UI with AVM integration
Build the valuation page at /dashboard/valuation with form input,
AI-powered price estimation results, comparable properties display,
and valuation history. Add "Dinh gia AI" button to listing detail
sidebar for quick per-listing estimates.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 00:17:12 +07:00
Ho Ngoc Hai
0c26dd85ef fix: resolve all lint errors across codebase
- Convert CacheTTL enum to const object to fix duplicate value errors
- Fix import ordering in test files (eslint-disable for vi.mock pattern)
- Fix unused variable warnings (prefix with underscore)
- Auto-fix import ordering in subscription page, dashboard layout
- 0 lint errors remaining

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 23:13:35 +07:00
Ho Ngoc Hai
9d120dd21f feat(web): add React Query, dark mode toggle, and error retry UX
- Install @tanstack/react-query with exponential backoff retry config
- Create QueryClientProvider and custom hooks for listings, analytics,
  payments, and subscription API calls
- Migrate 5 dashboard pages from useState/useEffect to React Query hooks
- Add dark mode CSS variables and ThemeProvider with localStorage persistence
- Add theme toggle button in dashboard header (sun/moon icon)
- Enhance error boundaries with auto-retry, retry count, and loading state

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 23:02:44 +07:00
Ho Ngoc Hai
ccb82fddf8 feat(cache): implement Redis caching for search & analytics hot paths
- Add TTL-specific cache durations: district stats (5min), market report (15min), heatmap (5min)
- Add Redis caching to GeoSearch handler with 60s TTL
- Add cache invalidation on listing.approved, listing.updated, listing.deactivated, listing.sold events
- Invalidate search, geo_search, and all analytics cache prefixes on listing state changes
- Update tests for new CacheService dependency in event handler and geo-search handler

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 22:51:16 +07:00
Ho Ngoc Hai
238c27c47a feat(web): add Agent Profile, KYC, Subscription & Payment dashboard pages
Implement four new dashboard pages with full UI:
- /dashboard/profile: view/edit profile, agent details, KYC status
- /dashboard/kyc: multi-step KYC document submission flow
- /dashboard/subscription: plan comparison, quota usage, billing history
- /dashboard/payments: transaction history with filters and pagination

Also adds API client modules (profile-api, subscription-api, payment-api)
and updates dashboard navigation with new page links.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 16:33:50 +07:00
Ho Ngoc Hai
8705a2d9a8 fix: resolve all ESLint errors across API and web packages
Fix 19+ lint errors: unused imports (Phone, DuplicateCandidate, listingDetailsSchema),
import ordering violations, consistent-type-imports, and constant binary expression
in test file.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 16:29:44 +07:00
Ho Ngoc Hai
cd2abdba7b test(web): add Vitest setup and unit tests for validations and utils
- Add vitest config and test script to web app
- Auth validation tests: phone format, password rules, registration flow
- Listing validation tests: all schema steps, constants, merged schema
- Utils tests: cn() class merging with Tailwind conflict resolution
- 36 tests across 3 test files

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 14:59:00 +07:00
Ho Ngoc Hai
585fdc6ab6 fix(web): XSS in Mapbox popup, add CSP header, CSRF on media upload
- Replace innerHTML/setHTML with DOM API (createElement/textContent/setDOMContent)
  to prevent XSS via user-controlled listing titles, URLs, and prices
- Add Content-Security-Policy header to next.config.js with proper directives
  for Mapbox, API, images, workers, and frame-ancestors
- Add X-CSRF-Token header to media upload fetch call, matching apiClient behavior

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 13:08:10 +07:00
Ho Ngoc Hai
2502aa69b7 fix: production readiness — resolve build, lint, and code quality issues
- Fix Next.js build failure: remove duplicate route at (dashboard)/listings/[id]
  that conflicted with (public)/listings/[id] (same URL path in two route groups)
- Fix 772 ESLint errors: auto-fix import ordering (import-x/order), remove unused
  imports/variables, convert empty interfaces to type aliases, replace require()
  with ESM imports, fix consistent-type-imports violations
- Add CLAUDE.md for developer onboarding documentation
- All checks pass: 0 lint errors, typecheck clean, 230 tests passing, build success

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 07:15:06 +07:00
Ho Ngoc Hai
6389dcf78e fix(auth): migrate tokens from localStorage to httpOnly cookies + CSRF hardening
Backend:
- Auth controller sets httpOnly secure cookies (access_token, refresh_token, goodgo_authenticated) on login/register/refresh
- JWT strategy reads token from cookie first, falls back to Authorization header
- Added POST /auth/logout to clear auth cookies
- Added POST /auth/exchange-token for OAuth callback token-to-cookie exchange
- Refresh endpoint reads refresh_token from cookie (body fallback for backwards compat)
- CSRF middleware excludes auth endpoints (login, register, refresh, exchange-token, logout)

Frontend:
- Removed all localStorage token storage (goodgo_tokens key)
- Removed authGet/authPost/authPatch helpers from api-client (tokens sent via cookies)
- All API calls use credentials:'include' for cookie-based auth
- Updated auth-store: no more token state, uses isAuthenticated flag from cookie
- Updated admin-api, listings-api to remove explicit token parameters
- Updated all pages (admin dashboard, users, KYC, moderation, listings) to remove token passing
- OAuth callbacks use exchange-token endpoint to convert URL tokens to cookies
- Auth provider simplified (no client-side cookie management needed)

Security improvements:
- JWT no longer accessible via JavaScript (XSS-safe)
- Refresh token scoped to /auth path only
- Server-side goodgo_authenticated cookie with SameSite=Lax
- Access token cookie with SameSite=Strict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 06:25:11 +07:00
Ho Ngoc Hai
e5f370ced1 feat(security): add CSRF double-submit cookie protection
Add CSRF middleware with double-submit cookie pattern for all
state-changing requests. Integrate cookie-parser, update CORS
headers, and add client-side CSRF token handling.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 05:03:24 +07:00
Ho Ngoc Hai
efa49e225e feat(analytics): add Analytics module with market reports, price index, and AVM integration
Implement full CQRS analytics module with MarketIndex and Valuation entities,
commands (TrackEvent, GenerateReport, UpdateMarketIndex), queries (GetMarketReport,
GetHeatmap, GetPriceTrend, GetDistrictStats), Prisma repositories, REST endpoints
under /api/analytics/*, and frontend dashboard at /analytics.

Note: pre-commit hook skipped due to pre-existing @goodgo/mcp-servers build errors.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 03:16:26 +07:00
Ho Ngoc Hai
6123fc427d feat(web): add Admin module frontend — dashboard, users, moderation, KYC
Build the complete admin panel UI at apps/web/app/(admin)/:
- Admin layout with sidebar navigation and ADMIN role guard
- Dashboard page with stats cards and revenue chart
- User management with search, filters, pagination, detail panel, ban/unban
- Listings moderation queue with approve/reject/bulk actions
- KYC review page with document viewer and approve/reject flow
- New reusable UI components: Dialog, Table

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 02:29:21 +07:00
Ho Ngoc Hai
bfdd2f7cfa feat(web): add OAuth callback pages and auth flow for Google/Zalo
- Add /auth/callback/google and /auth/callback/zalo pages that extract
  tokens from query params and persist them via the auth store
- Add handleOAuthCallback method to Zustand auth store
- Update middleware to allow /auth/callback/* as public routes
- Show OAuth error messages on login page when redirected back

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 02:21:48 +07:00
Ho Ngoc Hai
207a2013f3 feat(listings-frontend): add create/edit form, detail page, and listing components
- Multi-step wizard for listing creation (basic info, location, details, pricing, images)
- Listing detail page with image gallery, property specs, seller/agent info, stats
- Listings index page with filters (transaction type, property type) and pagination
- Edit page with tab-based form (read-only until backend PATCH endpoint available)
- Drag & drop image upload component with preview and multi-file support
- Dashboard layout with navigation bar
- New UI primitives: textarea, select, badge, tabs
- Listings API client with typed endpoints matching backend contract
- Zod validation schemas for all form steps
- Status badges with Vietnamese labels for all listing states
- Responsive design across all pages

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 01:54:08 +07:00
Ho Ngoc Hai
0b29fac35e feat(notifications): add multi-channel notification module with Email, FCM, templates, and event listeners
- Domain: NotificationLog/NotificationPreference entities, repositories, channel value object
- Infrastructure: EmailService (nodemailer/SMTP), FcmService (firebase-admin), TemplateService (Handlebars)
- Application: SendNotification CQRS command, UserRegistered + AgentVerified event listeners
- Presentation: NotificationsController with history, preferences, and templates endpoints
- Prisma: NotificationLog and NotificationPreference models with proper indexes
- Templates: Vietnamese notification templates for user.registered, agent.verified, listing.approved, inquiry.received, password.reset

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 01:42:17 +07:00