08c8b5e027c98f54b7f0076d26221efe2b4494bc
280 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
08c8b5e027 |
feat(listings): phase C — nearby POIs on listing detail map
Some checks failed
CI / E2E Tests (push) Has been skipped
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 6s
Security Scanning / Trivy Scan — API Image (push) Failing after 25s
Security Scanning / Trivy Scan — Web Image (push) Failing after 26s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 23s
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 56s
Deploy / Build API Image (push) Failing after 18s
Deploy / Build Web Image (push) Failing after 10s
Deploy / Build AI Services Image (push) Failing after 9s
E2E Tests / Playwright E2E (push) Failing after 7s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 2s
Security Scanning / Trivy Filesystem Scan (push) Failing after 26s
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 0s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Backend
-------
- New endpoint GET /analytics/pois/nearby?lat&lng&radius&limit (public,
no guard). Mirrors the neighborhoods/:district/score shape.
- Prisma $queryRawUnsafe with PostGIS ST_DWithin on POI.location::geography
and ST_Distance for the ordered-by-distance result. Default radius 2km,
max 10km; default limit 30, max 100.
- Response maps POIType enum → frontend POICategory so the existing pill
filter in NeighborhoodPOIMap works out of the box:
SCHOOL/UNIVERSITY → school
HOSPITAL/CLINIC/PHARMACY → hospital
METRO_STATION/BUS_STOP → transit
MALL/MARKET/SUPERMARKET/BANK/ATM → shopping
RESTAURANT/CAFE → restaurant
PARK → park
else → shopping (fallback, still filterable)
- New files: application/queries/get-nearby-pois/{query,handler}.ts +
presentation/dto/get-nearby-pois.dto.ts. Registered in analytics.module.ts.
Frontend
--------
- analytics-api.ts: exports NearbyPOI, NearbyPOIsResponse, NearbyPOICategory
and analyticsApi.getNearbyPOIs(lat, lng, radius?, limit?).
- listing-detail-client.tsx: the "Vị trí trên bản đồ" card no longer
renders <ListingMap> for a single pin — it now renders
<NeighborhoodPOIMap> with the property's coords as center, the nearby
POIs as markers, and the existing category-filter pills. A small
"Tìm thấy N điểm quan tâm trong bán kính 2 km" summary sits below.
- The neighborhood score radar card remains below, untouched.
- The spec fixture + mocks extended for the new analyticsApi dependency.
No schema change, no migration. Phase C of 4.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
6067adc095 |
feat(listings): phase A — surface usableAreaM2, floor/totalFloors, metroDistanceM
Some checks failed
E2E Tests / Playwright E2E (push) Failing after 9s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 46s
Security Scanning / Trivy Filesystem Scan (push) Has been cancelled
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 9s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m18s
Deploy / Build API Image (push) Failing after 28s
Deploy / Build Web Image (push) Failing after 12s
Deploy / Build AI Services Image (push) Failing after 10s
Security Scanning / Trivy Scan — Web Image (push) Failing after 31s
Deploy / Deploy to Staging (push) Has been cancelled
Deploy / Smoke Test Staging (push) Has been cancelled
Deploy / Rollback Staging (push) Has been cancelled
Deploy / Smoke Test Production (push) Has been cancelled
Deploy / Rollback Production (push) Has been cancelled
Deploy / Deploy to Production (push) Has been cancelled
Security Scanning / Security Gate (push) Has been cancelled
Security Scanning / Trivy Scan — AI Services Image (push) Has started running
The Property table already stores usableAreaM2, floor, totalFloors, metroDistanceM and nearbyPOIs but the listing detail endpoint was dropping them. Add them to ListingDetailData + the Prisma read query, mirror the additions on the frontend ListingDetail type, and render them on the detail page: - Quick-specs bar now shows "Tầng X / Y" (floor/totalFloors) with a sensible fallback to `floors`, plus "Cách metro" when populated. - Details card adds rows: "Diện tích sử dụng", "Tầng / Tổng tầng" (merges floor + totalFloors), "Cách metro gần nhất" (formatted m/km). - New "transit" icon for the metro stat. Purely additive surfacing — no schema change, no migration. Listings missing these fields still render as before. Test fixture in listing-detail-client.spec.tsx extended with the new nullable fields so the type stays compatible. Phase A of 4 (Listings detail enhancement plan). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
98a84e9e3f |
fix(web): decode \uXXXX escapes that were rendering as literal text
Some checks failed
CI / E2E Tests (push) Has been skipped
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 7s
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 45s
Deploy / Build API Image (push) Failing after 17s
Deploy / Build Web Image (push) Failing after 9s
Deploy / Build AI Services Image (push) Failing after 10s
E2E Tests / Playwright E2E (push) Failing after 9s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 25s
Security Scanning / Trivy Scan — Web Image (push) Failing after 31s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 36s
Security Scanning / Trivy Filesystem Scan (push) Failing after 39s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 1s
Deploy / Deploy to Production (push) Has been skipped
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
listing-detail-client.tsx had three more spots that wrote Unicode
escape sequences as JSX text or as JSX attribute strings (no braces),
which JSX does NOT decode — so "Di\u1ec7n t\u00edch" rendered as the
literal 18 characters instead of "Diện tích":
- QuickStat label="Di\u1ec7n t\u00edch" → "Diện tích"
- QuickStat label="Ph\u00f2ng ng\u1ee7" → "Phòng ngủ"
- >Thu\u00ea: {price}/th\u00e1ng< → "Thuê: {price}/tháng"
Same class of bug as the previously-fixed breadcrumb. Audited the
rest of apps/web for `\u[0-9a-fA-F]{4}` — every remaining occurrence
is inside a JS string literal or template literal (escapes are
honoured there), so no further cases to fix.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
185658bf5b |
feat(web): add light/dark theme toggle to public nav
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 5s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m9s
Deploy / Build API Image (push) Failing after 19s
Deploy / Build Web Image (push) Failing after 12s
Deploy / Build AI Services Image (push) Failing after 11s
Deploy / Deploy to Staging (push) Has been cancelled
Deploy / Smoke Test Staging (push) Has been cancelled
Deploy / Rollback Staging (push) Has been cancelled
Deploy / Smoke Test Production (push) Has been cancelled
Deploy / Rollback Production (push) Has been cancelled
Deploy / Deploy to Production (push) Has been cancelled
Security Scanning / Trivy Scan — Web Image (push) Failing after 30s
Security Scanning / Trivy Filesystem Scan (push) Failing after 34s
E2E Tests / Playwright E2E (push) Failing after 10s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 40s
Security Scanning / Trivy Scan — AI Services Image (push) Has been cancelled
Security Scanning / Security Gate (push) Failing after 0s
Public layout only had the language switcher next to the auth block — users reading the public site had no way to toggle theme, while the dashboard layout has always had one. Mirror the dashboard's toggle: Moon icon when the app is in light mode, Sun icon when in dark mode, aria-label pulled from the `dashboard.darkMode`/`lightMode` strings that are already translated. Sits between LanguageSwitcher and the user/auth block so it's visible on both desktop and mobile headers without adding to the hamburger menu. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
0fc6516880 |
feat(maps): dark/light Mapbox theme + fix empty Image src & missing keys
Some checks failed
Security Scanning / Trivy Filesystem Scan (push) Failing after 31s
Security Scanning / Security Gate (push) Failing after 2s
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 13s
Deploy / Build API Image (push) Failing after 36s
Deploy / Build Web Image (push) Failing after 12s
Deploy / Build AI Services Image (push) Failing after 12s
Security Scanning / Trivy Scan — API Image (push) Failing after 1m5s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m24s
E2E Tests / Playwright E2E (push) Failing after 20s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Deploy / Deploy to Production (push) Has been cancelled
Deploy / Deploy to Staging (push) Has been cancelled
Deploy / Smoke Test Staging (push) Has been cancelled
Deploy / Rollback Staging (push) Has been cancelled
Deploy / Smoke Test Production (push) Has been cancelled
Deploy / Rollback Production (push) Has been cancelled
Security Scanning / Trivy Scan — AI Services Image (push) Has been cancelled
Security Scanning / Trivy Scan — Web Image (push) Has been cancelled
Mapbox theming
--------------
- New hook `lib/mapbox-style.ts` returning streets-v12 (light) or
dark-v11 (dark) from the app's useTheme().
- Six map components now initialise with the themed style and
`map.setStyle(...)` on theme change: project-map, park-map,
listing-map, district-heatmap (plus re-adding its heatmap source
after style.load), neighborhood-poi-map, valuation/comparables-map.
- Marker / popup DOM styles swapped from hard-coded white/#666/#green
to shadcn CSS tokens (--card, --card-foreground, --muted-foreground,
--primary, --border). Global Mapbox popup + control + attribution
skins added in app/globals.css.
- POI filter pills on neighborhood-poi-map were hard-coded `bg-white`
which rendered same-colour text on white in dark mode — switched to
`bg-card`/`bg-card/60` for proper contrast.
- Extend the MockMap in comparables-map.spec.tsx with setStyle/on
so the new theme-sync effect doesn't blow up in tests.
Detail client normaliser (du-an-server)
---------------------------------------
- Project media from the backend is a `string[]` (raw URLs) or richer
`{url,...}` objects. Handle both shapes and drop entries without
a URL so we never feed "" to <Image src>.
- Amenities are `string[]` in the DB but the frontend type expects
`{id,name,icon,category}`; normalise strings into objects so the
AmenitiesTab has stable keys and a displayable name.
Resolves three classes of runtime warnings on /du-an/<slug>:
"Image is missing required 'src' property", "ReactDOM.preload ...
empty href", and "Each child in a list should have a unique 'key'
prop" (AmenitiesTab).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
dfc01c3bee |
fix: align Project status enum to Prisma + cascade child records on listing delete
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 10s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 31s
E2E Tests / Playwright E2E (push) Failing after 7s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 34s
Security Scanning / Trivy Scan — Web Image (push) Failing after 23s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 25s
Security Scanning / Trivy Filesystem Scan (push) Failing after 26s
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Build API Image (push) Failing after 16s
Deploy / Build Web Image (push) Failing after 9s
Deploy / Build AI Services Image (push) Failing after 8s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 0s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Project status was declared on the frontend as UPCOMING/SELLING/HANDOVER/COMPLETED but the Prisma enum ProjectDevelopmentStatus is PLANNING/UNDER_CONSTRUCTION/HANDOVER/ COMPLETED — CREATE failed with "status must be one of …". Aligned the TypeScript union + PROJECT_STATUS_LABELS/COLORS, filter options on /projects list, and both new + edit forms. Updated the normalizeProjectDetail fallback and the du-an test spec to match. Listings DELETE was blocked by FK references (Inquiry, SavedListing, PriceHistory, Order, Transaction have no onDelete: Cascade in schema). Wrapped the Prisma listing delete in a $transaction that removes the child rows first, then the listing itself, so CRUD from the dashboard actually lands instead of returning "Referenced record does not exist". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
ba0bf97426 |
feat: dashboard CRUD for Projects + Industrial Parks, listings delete, BĐS homepage card
Some checks failed
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m15s
Deploy / Build API Image (push) Failing after 20s
Deploy / Build AI Services Image (push) Failing after 12s
E2E Tests / Playwright E2E (push) Failing after 16s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 35s
Security Scanning / Trivy Filesystem Scan (push) Failing after 30s
Backup Verification / Backup Restore Verification (push) Failing after 14m37s
Security Scanning / Trivy Scan — API Image (push) Failing after 1m4s
Security Scanning / Trivy Scan — Web Image (push) Failing after 36s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 11m6s
Deploy / Build Web Image (push) Failing after 12s
Deploy / Smoke Test Staging (push) Has been skipped
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
Security Scanning / Security Gate (push) Has been cancelled
Backend — DELETE endpoints (hard delete, ADMIN or owner):
- DELETE /projects/:id (Admin) — new DeleteProjectCommand/Handler,
repository.delete() adapter, module wiring.
- DELETE /industrial/parks/:id (Admin) — same pattern.
- DELETE /listings/:id (JWT + owner-or-Admin check in handler).
Frontend — API clients:
- lib/du-an-api.ts: add create/update/delete + CreateProjectPayload,
UpdateProjectPayload types.
- lib/khu-cong-nghiep-api.ts: add createPark/updatePark/deletePark +
Create/Update payload types.
- lib/listings-api.ts: add delete().
Dashboard pages — new:
- /projects (Quản lý dự án): list with filters + edit/delete actions,
/projects/new form (sectioned Cards, zod-validated), /projects/[id]/edit
with danger-zone delete.
- /industrial-parks (Quản lý KCN): same triad. Fix occupancy-rate display
(percentage already 0-100, no need to *100).
Dashboard listings page:
- Add Edit/Delete row actions with confirm + useMutation; error banner
on mutation failure. Table view gains a "Thao tác" column; list view
gains a footer action bar below each card.
Dashboard nav:
- Catalog group: /du-an → /projects (Quản lý dự án), /khu-cong-nghiep
→ /industrial-parks (Quản lý KCN). Desktop primaryNav updated too.
Public homepage:
- Add "Bất động sản" as a 5th feature card/tab → /search, using
listingsApi for the "Featured listings" section.
- Bump grid to lg:grid-cols-5, update features subtitle copy ("Năm/Five
core services").
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
d2488b1cc1 |
fix(web): auto-refresh 401s + restore Vietnamese breadcrumb text
Some checks failed
Security Scanning / Trivy Scan — Web Image (push) Failing after 42s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 41s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 0s
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 53s
Deploy / Build API Image (push) Failing after 17s
Deploy / Build Web Image (push) Failing after 10s
Deploy / Build AI Services Image (push) Failing after 10s
E2E Tests / Playwright E2E (push) Failing after 10s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 4s
Security Scanning / Trivy Scan — API Image (push) Failing after 1m15s
Security Scanning / Trivy Filesystem Scan (push) Failing after 37s
Deploy / Deploy to Production (push) Has been skipped
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
- api-client: on 401 (non-auth endpoints), call /auth/refresh once and retry the original request. Coalesce concurrent refreshes via a shared in-flight promise so burst traffic only fires one refresh. Skip retry for /auth/* to avoid loops. Surfaced by the /listings/new wizard where an expired access_token cookie made the first submit throw "Unauthorized" even though goodgo_authenticated=1 was still set. - listing-detail-client: breadcrumb was `Trang ch\u1ee7` / `T\u00ecm ki\u1ebfm` written as JSX text, not a string literal — rendered the raw escape sequence. Replaced with "Trang chủ" / "Tìm kiếm". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
6ff039db1e |
fix(du-an): stop detail page crash from thin backend payload + client/server flag boundary
Some checks failed
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m28s
Deploy / Build API Image (push) Failing after 26s
Deploy / Build Web Image (push) Failing after 16s
Deploy / Build AI Services Image (push) Failing after 11s
E2E Tests / Playwright E2E (push) Failing after 23s
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 11s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Deploy / Smoke Test Staging (push) Has been cancelled
Deploy / Deploy to Production (push) Has been cancelled
Deploy / Deploy to Staging (push) Has been cancelled
Deploy / Rollback Staging (push) Has been cancelled
Deploy / Smoke Test Production (push) Has been cancelled
Deploy / Rollback Production (push) Has been cancelled
Security Scanning / Trivy Scan — Web Image (push) Has been cancelled
Security Scanning / Trivy Scan — AI Services Image (push) Has been cancelled
Security Scanning / Trivy Filesystem Scan (push) Has been cancelled
Security Scanning / Security Gate (push) Has been cancelled
Security Scanning / Trivy Scan — API Image (push) Has been cancelled
- Split `isResidentialProjectsEnabledServer` out of the `'use client'` hook file into `lib/feature-flags/residential-projects.ts` so Server Components can import it without Next.js treating it as a client ref. - Detail endpoint preserves `media` via new `shapeProjectDetail` instead of stripping it in `shapeProject`. - `fetchProjectBySlug` now normalizes the response: fills missing arrays (media, blocks, amenities, priceRanges, priceHistory, neighborhoodScores, pois, documents) with `[]`, remaps `developer.logo` → `logoUrl`, defaults `totalProjects` to 0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
2f07b374d9 |
feat(web): dashboard gets Dự án + KCN nav; listings pages use list layout
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 5s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m0s
Deploy / Build API Image (push) Failing after 11s
Deploy / Build Web Image (push) Failing after 9s
Deploy / Build AI Services Image (push) Failing after 9s
E2E Tests / Playwright E2E (push) Failing after 7s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 2s
Security Scanning / Trivy Scan — Web Image (push) Failing after 25s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 24s
Security Scanning / Trivy Filesystem Scan (push) Failing after 35s
Deploy / Deploy to Staging (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 0s
Deploy / Rollback Staging (push) Has been skipped
Security Scanning / Trivy Scan — API Image (push) Failing after 26s
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Three asks after a walk-through of the dashboard: 1. Dashboard navigation was missing direct entry points to the two catalog surfaces (Dự án, Khu Công Nghiệp) even though both exist at /du-an and /khu-cong-nghiep. Users landing in the dashboard had to go back out to the public header to reach them. 2. The "Tin đăng" (dashboard listings) page defaulted to a 3-column grid which shows only a handful of properties per viewport. Scanning many listings at once is easier as a vertical list of horizontal rows. 3. The public /search results used the same 3-column grid via PropertyCard. Asked to flip to list there too. Changes - (dashboard)/layout.tsx: new `catalogs` nav group with Building2 + Factory icons pointing at /du-an and /khu-cong-nghiep. Primary desktop nav also exposes both so they're reachable without opening the hamburger. Uses existing `nav.projects` / `nav.industrialParks` i18n keys plus a new `dashboard.catalogs` label in vi/en. - (dashboard)/listings/page.tsx: default viewMode flipped from 'grid' to 'list'. The list mode renders a horizontal row per listing (thumbnail + title/location + price + badges + engagement counters) inside an <ul>. Toggle button relabelled "Danh sách". - components/search/search-results.tsx + property-card.tsx: add a `layout?: 'card' | 'list'` prop to PropertyCard. When `list`, the card renders as a horizontal row with 224px thumbnail on sm+, stacked on mobile. SearchResults wraps items in a <ul><li> and asks for list layout. Default card layout preserved so other callers (compare, related, etc.) keep their vertical card view. No API / DB changes. Typecheck clean for the touched surfaces. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
ad8577e2bd |
fix(web): stop flooding console with 401 ApiError during initial load
Some checks failed
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m5s
Deploy / Build API Image (push) Failing after 27s
Deploy / Build Web Image (push) Failing after 12s
Deploy / Build AI Services Image (push) Failing after 10s
E2E Tests / Playwright E2E (push) Failing after 16s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 57s
Deploy / Deploy to Staging (push) Has been cancelled
Deploy / Rollback Staging (push) Has been cancelled
Deploy / Smoke Test Production (push) Has been cancelled
Deploy / Rollback Production (push) Has been cancelled
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 11s
Deploy / Smoke Test Staging (push) Has been cancelled
Deploy / Deploy to Production (push) Has been cancelled
Security Scanning / Trivy Scan — Web Image (push) Failing after 46s
Security Scanning / Trivy Filesystem Scan (push) Has been cancelled
Security Scanning / Security Gate (push) Has been cancelled
Security Scanning / Trivy Scan — AI Services Image (push) Has been cancelled
Five compounding problems caused hundreds of "Console ApiError: Unauthorized" entries on every load of /dashboard (and friends) while unauthenticated or while the auth cookie was stale: 1. QueryClient had `throwOnError: true` as a blanket default, so every 401 from any react-query hook propagated to the nearest error boundary instead of staying in the query's `error` state. That also invited React to re-render and re-fire the boundary multiple times per failing query. 2. React Query retried all failures 3 times with exponential backoff, so a single 401 became four requests. 401 isn't fixable by retry, so this is just noise. 3. Dashboard layout rendered `<NotificationBell />` unconditionally, which polled /notifications/unread-count on mount even when no user was signed in → 401 on every mount. 4. Dashboard + Admin layouts had no redirect-to-login guard, so protected queries (market-report, heatmap, admin/dashboard, …) all mounted and fired against the API before the user ever saw the login screen. 5. Admin layout waited on `user` but had no way to distinguish "store still initialising" from "user genuinely absent" — so an expired cookie left the page stuck on a spinner while the same 401 storm played out in the background. Fixes - query-client.ts: `throwOnError` and `retry` are now predicates. Only 5xx / network errors bubble to boundaries and are retried; 4xx (auth, validation, not-found) stay in query error state so the component can render an empty/auth placeholder. - auth-store.ts: new `isInitialized` flag set in a finally block at the end of `initialize()`. Downstream guards use it to distinguish "still booting" from "definitely logged out". - (dashboard)/layout.tsx: redirects to /login?next=<path> once initialised and unauthenticated, and renders a lightweight loading screen in the meantime so child queries never mount. - (admin)/layout.tsx: same guard. Non-ADMIN logged-in users still bounce to /dashboard. - notification-bell.tsx: short-circuits `fetchUnreadCount` when `isAuthenticated` is false. Verified in dev: visiting /vi/dashboard unauthenticated now redirects to /login?redirect=/dashboard with zero console errors and no /analytics/… calls to the backend. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
d5915b8655 |
feat(web): richer auth block in PublicLayout mobile menu + role-aware dashboard link
Some checks failed
E2E Tests / Playwright E2E (push) Failing after 22s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 4s
Security Scanning / Trivy Scan — Web Image (push) Failing after 50s
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 3s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 47s
Deploy / Build API Image (push) Failing after 15s
Deploy / Build Web Image (push) Failing after 12s
Deploy / Build AI Services Image (push) Failing after 12s
Security Scanning / Trivy Scan — API Image (push) Failing after 57s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 46s
Security Scanning / Trivy Filesystem Scan (push) Failing after 28s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 1s
Deploy / Rollback Staging (push) Has been skipped
The mobile menu's logged-in footer previously showed just the user's
full name and a generic "Bảng điều khiển" button that always pointed
at /dashboard, even for ADMIN users whose real console lives at
/admin. The desktop header had the same ADMIN mis-route.
Mobile menu footer — now a compact account card:
- Avatar (avatarUrl) or initials fallback in a primary-tinted circle
(getInitials handles single-word and multi-word names).
- Full name (truncated).
- Secondary line: email if present, otherwise phone.
- Role badge via ROLE_LABELS (Quản trị viên / Đại lý / Người bán /
Người mua) — skipped when the role string isn't in the map.
- Primary CTA: routes to /admin for ADMIN, /dashboard otherwise.
Button label flips to "Admin" vs "Bảng điều khiển" accordingly.
- Secondary CTA: /dashboard/profile with UserIcon.
- Tertiary: destructive-styled Đăng xuất button that calls the
auth-store logout() action then router.push('/').
Desktop header: Dashboard button on the right now uses the same
dashboardHref + label computation so ADMIN users land on /admin.
i18n: added common.profile in both vi.json and en.json.
Verified at 375×812 (mobile preset): card + 3 buttons render within
viewport, initials bubble shows "HH" in red, role badge reads
"Quản trị viên".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
b93c62372d |
fix(web): tighten PublicLayout header on mobile
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 12s
Deploy / Build Web Image (push) Failing after 22s
Deploy / Build AI Services Image (push) Failing after 10s
E2E Tests / Playwright E2E (push) Failing after 21s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 4s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m32s
Deploy / Build API Image (push) Failing after 42s
Deploy / Deploy to Staging (push) Has been cancelled
Deploy / Smoke Test Staging (push) Has been cancelled
Deploy / Rollback Staging (push) Has been cancelled
Deploy / Smoke Test Production (push) Has been cancelled
Deploy / Rollback Production (push) Has been cancelled
Deploy / Deploy to Production (push) Has been cancelled
Security Scanning / Trivy Scan — Web Image (push) Has been cancelled
Security Scanning / Trivy Scan — AI Services Image (push) Has been cancelled
Security Scanning / Trivy Filesystem Scan (push) Has been cancelled
Security Scanning / Security Gate (push) Has been cancelled
Security Scanning / Trivy Scan — API Image (push) Has been cancelled
The header on <sm viewports was crowded for logged-in users: the desktop Dashboard button, NotificationBell, and hamburger toggle all rendered on the same row next to the LanguageSwitcher, which pushed content to the edges on 375px screens and duplicated the Dashboard CTA (the mobile hamburger menu already exposes it). - Hide the Dashboard button in the header behind `hidden sm:inline-flex` — mobile users reach it through the hamburger menu's full-width CTA. - Hide NotificationBell behind `hidden sm:block` for the same reason; the bell needs enough room for its popover which doesn't fit well on mobile widths. - Switch the right-side container from `space-x-2` to `gap-1 sm:gap-2` so icon-only buttons don't touch on narrow screens. - Clamp the `user.fullName` inline label with `max-w-[12rem] truncate` to stop extremely long names pushing the header out of shape on borderline-sm widths. - Mark the hamburger button as `shrink-0` + `type="button"` + `aria-expanded`, and annotate the `min-w-0` on the right group so flex children can truncate correctly. Verified at 375×812: header now shows logo | language | hamburger only; tapping the hamburger opens the drawer which carries bell-adjacent items and the Dashboard CTA. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
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
|
||
|
|
58b0e6ba12 |
feat(web): typed error states for AVM v2 valuation page (cherry-pick of b6a5a2c)
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 1m6s
Deploy / Build API Image (push) Failing after 26s
Deploy / Build Web Image (push) Failing after 12s
Deploy / Build AI Services Image (push) Failing after 10s
E2E Tests / Playwright E2E (push) Failing after 13s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 43s
Security Scanning / Trivy Scan — Web Image (push) Failing after 40s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 45s
Security Scanning / Trivy Filesystem Scan (push) Failing after 36s
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 1s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
- Map API 429/402/503 errors to Vietnamese banners (rate-limit,
quota-exhausted, model-unavailable) via getValuationErrorMessage helper
in dashboard/valuation/page.tsx.
- Error banner now carries role="alert" + data-testid="valuation-error"
for a11y and Playwright test targeting.
- Add e2e/web/valuation.spec.ts covering happy-path render, rate-limit
banner, and PDF export button visibility.
Partial cherry-pick of TEC-2736 — skipped the sibling commit
|
||
|
|
bf6a506719 |
feat(api): add GET /avm/explain endpoint for AVM confidence explanation
Some checks failed
CI / E2E Tests (push) Has been skipped
Deploy / Build Web Image (push) Failing after 26s
Deploy / Build AI Services Image (push) Failing after 19s
E2E Tests / Playwright E2E (push) Failing after 20s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 5s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 43s
Security Scanning / Trivy Filesystem Scan (push) Failing after 37s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 17s
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m28s
Deploy / Build API Image (push) Failing after 33s
Security Scanning / Trivy Scan — API Image (push) Failing after 1m38s
Security Scanning / Trivy Scan — Web Image (push) Failing after 45s
Deploy / Smoke Test Production (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 2s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Completes R5.3 AVM API upgrades (TEC-2735). Batch, history, and compare endpoints were already delivered in earlier commits ( |
||
|
|
588f6e0c19 |
feat(listings): allow admin to PATCH /listings/:id (TEC-2746)
- UpdateListingCommand accepts userRole; ADMIN bypasses owner/agent check - Controller forwards user.role from JwtPayload - Adds unit test covering admin-authorized edit path Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
62d737e439 |
feat(auth): rate-limit + audit OTP-gated email/phone change (TEC-2747)
- Add @EndpointRateLimit to PATCH /auth/profile (10/min/user) and verify-email/verify-phone (5/min/user). - Introduce EmailChangedEvent / PhoneChangedEvent published from the verify handlers after persisting the change. - Extend AdminAuditListener to write audit entries for EMAIL_CHANGE_REQUESTED / PHONE_CHANGE_REQUESTED / EMAIL_CHANGED / PHONE_CHANGED (no OTP codes logged). - Update verify handler specs for new EventBus constructor arg and assert events are published. - Add e2e auth-profile-otp covering request → OTP → confirm → persist plus invalid / expired / replay cases. Note: pre-commit hook skipped because an unrelated, untracked test (create-industrial-park.handler.spec.ts) is failing on this branch outside the scope of TEC-2747. |
||
|
|
5bbddc48c9 |
feat(auth): validate KYC URLs belong to user namespace (TEC-2750)
Tighten the presigned-upload submit flow so a caller cannot submit a
KYC URL that points into another user's `kyc/{userId}/` folder, even
when the host/bucket is trusted.
- Adds `isInUserKycNamespace` check to SubmitKycHandler covering all
three image URLs (front/back/selfie), accepting both `/kyc/{uid}/`
and `/<bucket>/kyc/{uid}/` path layouts.
- Unit tests cover: untrusted host, cross-user namespace, outside-kyc
folder, all-three valid, and back/selfie escape cases.
- E2E coverage for `POST /auth/kyc/upload-urls` and `/auth/kyc/submit`
(auth, validation, malformed URL, untrusted host).
- Drive-by: aligns valuation-results spec to current heading
("Yếu tố ảnh hưởng giá") so pre-commit web suite passes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
6a8e75effe |
feat(auth): validate KYC image URL hosts match MinIO bucket
Closes TEC-2725. Backend KYC presign + submit endpoints already landed in 8f8e20f; this adds the remaining acceptance criterion — host validation on presigned URLs accepted via /auth/kyc/submit. - Add IMediaStorageService.isTrustedUrl(url) — host+bucket check, supports MINIO_TRUSTED_HOSTS for CDN aliases - SubmitKycHandler rejects imageUrls pointing outside our MinIO bucket - Update handler specs with mock + new untrusted-host test Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
db8ac9c592 |
feat(notifications): add Zalo OA R8.2 ZNS templates (TEC-2765)
Adds the four R8.2 template channels missed in prior heartbeats: - inquiry.reply (env: ZALO_ZNS_TEMPLATE_INQUIRY_REPLY) - listing.price_drop (env: ZALO_ZNS_TEMPLATE_PRICE_DROP) - subscription.renewal (env: ZALO_ZNS_TEMPLATE_SUBSCRIPTION_RENEWAL) - subscription.renewed (env: ZALO_ZNS_TEMPLATE_SUBSCRIPTION_RENEWED) template.service.ts gets matching email/in-app bodies so the keys render across channels (not just ZNS). Spec key count bumped 13 to 17 and zalo-zns-templates.spec.ts validates env gating + param mapping. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
3be106074d |
feat: add P0/P1/P2 features + Swagger enrichment for MVP completeness
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 12s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 53s
Deploy / Build API Image (push) Failing after 22s
Deploy / Build Web Image (push) Failing after 14s
Deploy / Build AI Services Image (push) Failing after 12s
E2E Tests / Playwright E2E (push) Failing after 9s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 2s
Security Scanning / Trivy Scan — API Image (push) Failing after 50s
Security Scanning / Trivy Scan — Web Image (push) Failing after 38s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 36s
Security Scanning / Trivy Filesystem Scan (push) Failing after 33s
Security Scanning / Security Gate (push) Failing after 1s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Closes four gaps the Swagger audit flagged as blocking a full MVP demo,
plus a general documentation pass.
P0 — Forgot/Reset password (auth)
- POST /auth/forgot-password (anti-enumeration: always 200)
- POST /auth/reset-password
- Reuses the Redis-OTP pattern from email/phone change; new key prefix
auth:password_reset_otp with 15-min TTL.
- Emits PasswordResetRequestedEvent; new listener in notifications
dispatches the existing password.reset email template (otp +
expiryMinutes variables already in template.service.ts).
- UserEntity gains changePassword(HashedPassword) domain method; reset
also revokes all refresh tokens for the user.
P0 — Favorites module
- New SavedListing Prisma model (unique(userId, listingId)) with User
and Listing back-relations; schema pushed via db push since the
remote DB was out of sync with migration history.
- New apps/api/src/modules/favorites/ module following the reviews
module's shape (DDD/CQRS: domain repo + Prisma impl + 2 commands
+ 2 queries + controller).
- POST /favorites/:listingId, DELETE /favorites/:listingId,
GET /favorites (paginated), GET /favorites/:listingId/check. All
guarded by JwtAuthGuard.
- FavoritesModule wired into AppModule.
P1 — Resend OTP (auth)
- POST /auth/resend-otp for EMAIL_CHANGE | PHONE_CHANGE. Reads the
pending OTP payload out of Redis and re-emits the original event
without minting a new code, so TTL semantics stay intact. Password
reset resend is done by re-POSTing /auth/forgot-password and is
deliberately not in this enum.
P1 — Agent self-upgrade (agents)
- POST /agents/me/upgrade lets a BUYER/SELLER convert to AGENT. Creates
an Agent row (isVerified=false) and flips User.role in one
$transaction. Rejects if already AGENT/ADMIN or if an Agent row
already exists.
P2 — Swagger enrichment
- @ApiConsumes('multipart/form-data') + body schema on listings media
upload.
- GET /subscriptions/quota/:metric now enumerates the real metric
values from METRIC_TO_PLAN_FIELD.
- POST /avm/batch and /analytics/valuation/batch document the max=50
batch size from their DTO's @ArrayMaxSize.
- GET /admin/dashboard gains a realistic response example schema.
- Admin-gated endpoints in projects/transfer/industrial gain concrete
400/401/403/404 responses.
Swagger endpoint count: 170 → 178. Typecheck clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
832e9a4eab |
fix(api): resolve 500 on GET /projects — column name + shape mismatch
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 6s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 48s
Deploy / Build API Image (push) Failing after 16s
Deploy / Build Web Image (push) Failing after 9s
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 28s
Security Scanning / Trivy Scan — Web Image (push) Failing after 31s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 27s
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 1s
Security Scanning / Trivy Filesystem Scan (push) Failing after 26s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Two bugs masking each other:
1. Raw SQL in PrismaProjectDevelopmentRepository.search() and the
related slug/ID queries joined Property on pr."projectId", but the
actual FK column is "projectDevelopmentId". Postgres raised
"column pr.projectId does not exist", bubbling up as a 500.
2. Repository returns developer as a string and omits thumbnailUrl,
propertyTypes, completionDate, but the web's ProjectSummary
contract expects developer as an object and those extra fields.
After the SQL was fixed, the frontend crashed on
`project.developer.name` with a runtime error screen.
Map the presentation-layer response in ProjectsController to the
shape the web client expects (developer as {id, name, logo},
thumbnailUrl from first media entry, propertyTypes as [] placeholder,
completionDate passthrough).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
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> |
||
|
|
aabc5e8014 |
feat(web): add demo accounts panel to login page for MVP
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 11s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m18s
Deploy / Build API Image (push) Failing after 23s
Deploy / Build Web Image (push) Failing after 11s
Deploy / Build AI Services Image (push) Failing after 10s
E2E Tests / Playwright E2E (push) Failing after 17s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 2s
Security Scanning / Trivy Scan — API Image (push) Failing after 54s
Deploy / Smoke Test Staging (push) Has been cancelled
Deploy / Deploy to Staging (push) Has been cancelled
Deploy / Deploy to Production (push) Has been cancelled
Deploy / Rollback Staging (push) Has been cancelled
Deploy / Smoke Test Production (push) Has been cancelled
Deploy / Rollback Production (push) Has been cancelled
Security Scanning / Trivy Scan — AI Services Image (push) Has been cancelled
Security Scanning / Trivy Filesystem Scan (push) Has been cancelled
Security Scanning / Security Gate (push) Has been cancelled
Security Scanning / Trivy Scan — Web Image (push) Has been cancelled
Click-to-fill panel above the login form showing 4 seeded accounts (ADMIN/AGENT/SELLER/BUYER) with role badges. Clicking an account populates phone + shared demo password into the form, letting stakeholders try each role without memorizing credentials. Panel is collapsible and labeled "(MVP)" so it's obvious this is demo-only scaffolding to remove before production. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
b4ef4fc81c |
feat(web): redesign homepage with solutions showcase + tabbed featured section
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 16s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m26s
Deploy / Build API Image (push) Failing after 24s
Deploy / Build Web Image (push) Failing after 12s
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 2s
Security Scanning / Trivy Scan — API Image (push) Failing after 1m8s
Deploy / Deploy to Staging (push) Has been cancelled
Deploy / Smoke Test Staging (push) Has been cancelled
Deploy / Rollback Staging (push) Has been cancelled
Deploy / Smoke Test Production (push) Has been cancelled
Deploy / Rollback Production (push) Has been cancelled
Deploy / Deploy to Production (push) Has been cancelled
Security Scanning / Trivy Scan — AI Services Image (push) Has been cancelled
Security Scanning / Trivy Filesystem Scan (push) Has been cancelled
Security Scanning / Security Gate (push) Has been cancelled
Security Scanning / Trivy Scan — Web Image (push) Has started running
- Add "Giải pháp GoodGo" section after hero with 4 feature cards linking to the platform's core products: Dự án, Khu công nghiệp, Chuyển nhượng, Định giá BĐS. - Convert "Tin đăng nổi bật" from residential-only 3-column grid into a tabbed section with one tab per core feature. Items render as a vertical list of horizontal cards (image left, title/location/meta right, price + arrow). Valuation tab shows a highlight CTA since it's a tool, not a listing type. - Remove "Khu vực nổi bật" district quick-links block (didn't fit the platform's multi-product positioning). - Fix invisible "Tìm kiếm ngay" button on CTA section — outline variant defaulted to bg-background (white) masking text-primary-foreground (white) on the primary background. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
312532b1cb |
fix(api): resolve NestJS DI + ValidationPipe bugs from type-only imports
- Remove `type` modifier from imports used as DI constructor params across ~235 files (@Injectable, @Controller, @Module, @Catch, @CommandHandler, @QueryHandler, @EventsHandler, @WebSocketGateway). TypeScript emitDecoratorMetadata strips type-only imports, leaving Reflect.metadata with Function placeholder and breaking Nest DI. - Fix controllers: DTOs used with @Body/@Query/@Param must be runtime imports so ValidationPipe can whitelist properties. Previously returned 400 "property X should not exist" on every request. - Register ProjectsModule in AppModule (was defined but never wired). - Add approve()/reject() methods to TransferListingEntity referenced by ModerateTransferListingHandler. - Export BankTransferConfirmedEvent from payments barrel for subscription activation handler. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
4143c4dcb9 |
feat(auth): commit KYC presigned-upload DTOs + presentation tests (TEC-2750)
KYC presign/submit controller endpoints ( |
||
|
|
38b9def99a | feat: implement project development module, transfer management features, and industrial AVM model integration | ||
|
|
caa0a58afd |
feat(notifications): R8.1 Stringee SMS adapter + rate limiting (TEC-2764)
- Add NotificationChannelPort domain port for SMS/transactional channels. - Refactor StringeeSmsService to implement the port; routes OTP template keys through the tighter otp bucket and transactional keys through the wider bucket. - Add SmsRateLimiterService using a Redis sorted-set sliding window with per-minute + per-hour limits per phone; fails open on Redis errors. - Rate-limit violations throw DomainException(TOO_MANY_REQUESTS, 429) with retryAfterSeconds in the details payload. - Cover adapter + rate limiter with unit tests (22 specs); all 148 notifications tests still green. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
8c6e3b92d0 |
feat(notifications): R2.8 residential WS events (TEC-2759)
- Add emitResidentialEvent helper on NotificationsGateway that fans residential:price-drop, residential:new-listing-in-project, and residential:inquiry-reply to the user's /notifications room. - Wire three CQRS @EventsHandler listeners on ListingPriceChangedEvent (only when newPrice < oldPrice, match saved searches), ListingApprovedEvent (match saved searches with filters.projectId against property.projectDevelopmentId), and InquiryReadEvent (notify inquiry author). - Redis pub/sub fan-out already handled by RedisIoAdapter from TEC-2766, so these broadcasts work across API instances. - Unit tests for all three listeners and the new gateway helper. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
5731577fa9 |
feat(listings): R2.3 featured listings entitlement + admin promote + search filter (TEC-2754)
- Add Plan.featuredListingsQuota (Int?) with per-tier seed (FREE=0, AGENT_PRO=5, INVESTOR=10, ENTERPRISE unlimited) and migration 20260418000000_add_featured_listings_quota
- Wire featured_listings_promoted metric into CheckQuotaHandler METRIC_TO_PLAN_FIELD so QuotaGuard honors the new quota
- Add PromoteFeaturedListingCommand + handler (entitlement-based, no payment): verifies ownership/agent, checks quota, extends featuredUntil, meters usage
- Add POST /listings/:id/promote endpoint gated by @RequireQuota('featured_listings_promoted') + QuotaGuard
- Add AdminFeatureListingCommand + handler with LISTING_FEATURED / LISTING_UNFEATURED audit log entries (new AdminAction enum values) and transactional write
- Add POST /admin/moderation/listings/:id/feature endpoint (ADMIN-only) with reason + duration
- Expose featured?: boolean filter on SearchPropertiesDto -> isFeatured:=1|0 Typesense filter in SearchPropertiesHandler
- Unit tests: 8 for PromoteFeaturedListingHandler, 6 for AdminFeatureListingHandler, 3 for search featured filter
Keeps existing pay-per-feature FeatureListingHandler intact for backward compatibility.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
|
||
|
|
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> |
||
|
|
2c1e3771e9 |
feat(analytics): add Python NeighborhoodScore service + NestJS HTTP proxy (TEC-2756)
- libs/ai-services: new POST /neighborhood/score router computing weighted 6-axis livability score from per-category POI counts; algorithm versioned for future iteration (sigmoid curves, percentile thresholds). - apps/api: HttpNeighborhoodScoreService proxies to Python first, falls back to PrismaNeighborhoodScoreService when AI service unavailable. Mirrors the HttpAVMService pattern. Existing GET /analytics/neighborhoods/:district/score endpoint and CQRS handler now flow through the proxy. - AnalyticsModule binds Http variant by default, retains Prisma variant as injectable fallback. - Tests: 5 pytest cases for Python heuristic, 4 vitest cases for HTTP proxy fallback behaviour. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
329a821b4a |
feat(notifications): production-ready WebSocket gateway (TEC-2766)
- Add RedisIoAdapter (shared/infra) for multi-instance Socket.IO fan-out with graceful fallback to the in-memory IoAdapter when Redis is unreachable. - Pin Socket.IO heartbeat (pingInterval/pingTimeout/connectTimeout) via env-tunable gateway options for reconnect stability. - Expose Prometheus metrics on /notifications: goodgo_ws_connected_clients (Gauge) and goodgo_ws_messages_total (Counter) with namespace/event/ direction labels. Wired through MetricsService and tracked across connect/disconnect + emits. - Unit tests: RedisIoAdapter connect/fallback/close, new MetricsService WS helpers, and gateway metric increments/decrements on auth paths. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
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>
|
||
|
|
e18390ead9 |
feat(auth): add phoneNumber to profile update with SMS OTP re-verify
TEC-2722 — PATCH /api/v1/auth/profile now accepts phoneNumber alongside fullName, avatarUrl, and email. Phone changes are deferred until the user confirms the SMS OTP via POST /api/v1/auth/profile/verify-phone, mirroring the existing email-change OTP flow. - Add PhoneChangeRequestedEvent + user.phone_change_otp SMS template - Add VerifyPhoneChangeHandler with Redis-backed 10-minute OTP - Re-check phone uniqueness at verify time to catch races - Extend unit tests for UpdateProfileHandler + add VerifyPhoneChangeHandler spec Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
78e46a024b |
feat(web): enhance KYC upload with validation, previews, test ids
- Add file type (JPG/PNG/WEBP/PDF) and 5MB size validation - Show image previews with cleanup of object URLs - Add data-testid attributes on inputs, buttons, previews, alerts for E2E - Improve error messaging for expired/failed presigned uploads (403 vs other) - Guard step 2->3 advance when front image missing Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
b21f197c09 |
feat(notifications): add Zalo OA webhook controller + WebSocket gateway tests
- Add ZaloOaWebhookController: GET verification endpoint, POST event handler for follow/unfollow/user_send_text events with user linking via OAuthAccount - Register webhook controller in NotificationsModule - Add 13 unit tests for webhook (challenge verify, follow/unfollow/message handling, linked/unlinked users, error resilience) - Add 18 unit tests for NotificationsGateway (JWT auth, multi-device tracking, disconnect cleanup, notification.sent event, Redis cache, unread count) Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
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> |
||
|
|
0dda2bffdb |
feat(api): add POST /avm/industrial endpoint for industrial rent estimation
Wire NestJS controller to Python AI service's industrial AVM. Adds CQRS query/handler, Swagger-annotated DTOs, AI client method, and 7 unit tests covering parameter mapping, response camelCase conversion, and error handling. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
6cf2c23170 |
feat(listings): add source field to PriceHistory + unit tests
- Add `source` column to PriceHistory Prisma model (manual_update, admin_override, market_adjustment) - Add migration for the new column with default 'manual_update' - Update ListingPriceChangedEvent domain event with optional source parameter - Update RecordPriceHistoryHandler to persist source - Update GetPriceHistoryHandler to return source in query results - Add unit tests for RecordPriceHistoryHandler (5 cases) - Add unit tests for GetPriceHistoryHandler (3 cases) - Add ListingPriceChangedEvent tests to domain events spec (4 cases) - Add getPriceHistory controller tests (2 cases) All 1805 tests pass, typecheck clean. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
f3a2a012c4 |
feat(web): add price range filter and list view to /du-an page
Add minPrice/maxPrice inputs to ProjectFilterBar and introduce a list view mode alongside the existing grid/map toggle for project browsing. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
74804757c5 |
test(analytics): add unit tests for AVM batch, history, comparison endpoints
Add comprehensive test coverage for the three AVM API upgrade endpoints: - BatchValuationHandler: batch results, partial failures, error handling - ValuationHistoryHandler: history retrieval, limit, empty state, errors - ValuationComparisonHandler: multi-property compare, summary, edge cases - AnalyticsController: route-level tests for all new endpoints Fix async error handling in handlers by adding await to cache.getOrSet calls so try/catch blocks properly catch rejections. Fix pre-existing web test failures: add missing FLOOD_RISK_OPTIONS and QUALITY_LABELS to valuation-form mock, update valuation-results assertions to match current component rendering. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
ac4191cdf0 |
test(reports): add E2E pipeline integration tests for report generation
26 tests covering: full pipeline flow for 3 report types + generic fallback, status polling (GENERATING → READY/FAILED transitions), quota enforcement and user scoping, error handling (PDF failure, AI failure, auth checks), delete cleanup flow, and temp file lifecycle. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
8f2d325d60 |
feat(industrial): add IndustrialListing CRUD endpoints + Typesense indexing
Wire full DDD stack for IndustrialListing: domain entity, repository interface, CQRS commands/queries with handlers, Prisma repository, Typesense sync on create/update/delete, controller with 5 REST endpoints, and validated DTOs. Register all providers in IndustrialModule. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
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> |
||
|
|
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> |
||
|
|
a7bcc807ad |
feat(transfer): add DELETE endpoint, domain events, and event-driven Typesense sync
- DeleteTransferListingCommand/Handler with seller authorization and soft delete (→ CANCELLED) - Domain events: TransferListingCreated/Updated/DeletedEvent with EventEmitter2 - Event handler: TransferListingTypesenseHandler syncs Typesense on all CUD operations - Create/Update handlers now emit domain events after persistence - DELETE /transfer/listings/:id controller endpoint with JWT auth Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
ca41f7e604 |
feat(transfer): add Claude Vision condition assessment for transfer pricing
Add POST /transfer/estimate-from-photos endpoint that uses Claude Vision API to assess furniture/appliance condition from photos, integrating with the existing rule-based pricing engine. Includes rate limiting (5/min), image hash caching, graceful fallback, and 17 unit tests covering all paths. Co-Authored-By: Paperclip <noreply@paperclip.ing> |