fix(qa): resolve remaining console errors & network errors on main routes (TEC-3079)

- fix(web): add ws:// to CSP connect-src for Socket.IO WebSocket connections
- fix(web): guard priceChangePct?.d7 / priceChangePct?.d30 against null in KpiStrip
- fix(api): add web-vitals POST to CSRF exclusion in both app.module and shared.module
- fix(api): use controller-relative path (web-vitals) not prefixed path for NestJS .exclude()

Result: 0 console errors, 0 network 4xx/5xx on /, /login, /register, /search

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-21 16:48:01 +07:00
parent 08b96f9c2d
commit 566ad75c0e
4 changed files with 7 additions and 3 deletions

View File

@@ -140,6 +140,8 @@ export class AppModule implements NestModule {
.exclude(
{ path: 'health', method: RequestMethod.GET },
{ path: 'health/(.*)', method: RequestMethod.GET },
{ path: 'api/v1/web-vitals', method: RequestMethod.POST }, // sendBeacon cannot send CSRF headers
{ path: 'web-vitals', method: RequestMethod.POST }, // middleware exclude uses controller-relative path
)
.forRoutes('*');
}

View File

@@ -72,6 +72,8 @@ export class SharedModule implements NestModule {
{ path: 'auth/refresh', method: RequestMethod.POST },
{ path: 'auth/exchange-token', method: RequestMethod.POST },
{ path: 'auth/logout', method: RequestMethod.POST },
{ path: 'api/v1/web-vitals', method: RequestMethod.POST }, // sendBeacon cannot send CSRF headers
{ path: 'web-vitals', method: RequestMethod.POST }, // middleware exclude uses controller-relative path
)
.forRoutes('*');
}

View File

@@ -139,7 +139,7 @@ function KpiStrip({ city }: { city: string }) {
<KpiCard
label="GGI HCM"
value={data ? formatPriceM2(data.avgPricePerM2) : '—'}
delta={data?.priceChangePct.d7}
delta={data?.priceChangePct?.d7}
footnote="Chỉ số giá TB/m²"
icon={<BarChart3 className="h-3.5 w-3.5" />}
loading={isLoading}
@@ -147,7 +147,7 @@ function KpiStrip({ city }: { city: string }) {
<KpiCard
label="Giá TB"
value={data ? formatVnd(data.avgPrice) : '—'}
delta={data?.priceChangePct.d30}
delta={data?.priceChangePct?.d30}
footnote="Toàn thành phố"
icon={<Building2 className="h-3.5 w-3.5" />}
loading={isLoading}

View File

@@ -43,7 +43,7 @@ const nextConfig = {
"style-src 'self' 'unsafe-inline' https://api.mapbox.com",
"img-src 'self' data: blob: https://*.mapbox.com https://*.tiles.mapbox.com https:",
"font-src 'self' data:",
`connect-src 'self' https://*.mapbox.com https://api.mapbox.com https://events.mapbox.com https://api.goodgo.vn${process.env.NODE_ENV !== 'production' ? ' http://localhost:3001 http://localhost:3011 http://localhost:9000' : ''}`,
`connect-src 'self' https://*.mapbox.com https://api.mapbox.com https://events.mapbox.com https://api.goodgo.vn${process.env.NODE_ENV !== 'production' ? ' http://localhost:3001 http://localhost:3011 http://localhost:9000 ws://localhost:3001 ws://localhost:3011' : ''}`,
"worker-src 'self' blob:",
"child-src 'self' blob:",
"frame-ancestors 'none'",