- 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>
- 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>
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>
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>
- 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>