Files
goodgo-platform/apps
Ho Ngoc Hai 631e1200a1
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 38s
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 9s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 30s
Security Scanning / Trivy Scan — Web Image (push) Failing after 25s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 20s
Deploy / Smoke Test Production (push) Has been skipped
Deploy / Rollback Staging (push) Has been skipped
Security Scanning / Trivy Filesystem Scan (push) Failing after 29s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 2s
Deploy / Rollback Production (push) Has been skipped
feat(listings): AI advisor on listing detail — valuation + qualitative advice
New endpoint POST /analytics/listings/:id/ai-advice (JwtAuthGuard).
Orchestrates a single-listing AI analysis in Vietnamese via Anthropic
Claude, using the key/URL/model configured in admin settings.

Backend
-------
- New CQRS: get-listing-ai-advice/{query,handler}.ts under analytics.
  Injects LISTING_REPOSITORY, QueryBus (for nearby POIs + neighborhood
  score), SystemSettingsService (from @modules/admin), LoggerService.
- Controller @Post('listings/:id/ai-advice') in analytics.controller.ts.
- analytics.module.ts now imports ListingsModule + AdminModule.
- Anthropic call: native fetch to ${apiUrl}/messages with
  x-api-key + anthropic-version: 2023-06-01 +
  anthropic-beta: prompt-caching-2024-07-31. System block marked
  cache_control:{type:'ephemeral'} for cheap subsequent cache hits.
  30s AbortController timeout.
- Response validation without adding zod to the API workspace —
  lightweight isRecord/asInt/asString/asStringArray helpers.
  Strips ```json fences before JSON.parse.
- Error handling:
  * 503 AI_NOT_CONFIGURED when the admin hasn't saved an API key.
  * 502 AI_PROVIDER_ERROR on non-2xx, parse failure, or timeout.
  * Key never logged.
  * POI / score fetch failures are soft — prompt is built without
    them and the model still runs.
- New error codes AI_NOT_CONFIGURED / AI_PROVIDER_ERROR in
  shared/domain/error-codes.ts.

Response shape (returned unchanged to the client):
```
{
  valuation: { estimateVND, lowVND, highVND, confidence, rationale },
  advice: { summary, pros[], cons[], suitableFor[] },
  model, cacheHit
}
```

Frontend
--------
- analytics-api.ts: exports AiConfidence, ListingAiValuation,
  ListingAiAdviceBody, ListingAiAdvice + getListingAiAdvice(id).
- New components/listings/ai-advice-cards.tsx.
  * Default state: outline <Button><Sparkles/> Xem phân tích AI</Button>
  * On click: useMutation fires + skeleton with Sparkles spinner.
  * On success: two sidebar cards:
    - "AI định giá" — big mid VND, low–high range, Low/Medium/High
      confidence badge, rationale with line-clamp-3.
    - "AI nhận định" — 2-sentence summary + two-column Pros/Cons
      (Check / AlertTriangle icons) + "AI gợi ý" chips for extra
      personas, plus a "Làm mới" link that re-triggers the mutation.
  * 503 → amber banner. ADMIN users see a link to /admin/settings/ai.
  * Other errors → red banner with retry.
- listing-detail-client.tsx mounts <AiAdviceCards listingId=... /> in
  the sidebar between the social-share card and the stats block.
  Existing <AiEstimateButton> kept untouched next to it.

Constraints preserved
---------------------
- No new npm packages; no @anthropic-ai/sdk.
- Runtime imports for NestJS DI classes.
- API key read at request time only — nothing persists it outside
  SystemSetting.

Verification
------------
- API typecheck clean; 1975 / 1975 tests pass.
- Web typecheck clean in touched files; 624 / 624 tests pass.
- AiAdviceCards spec-mocked in listing-detail-client.spec so
  QueryClientProvider isn't required.

User can now set their Anthropic key via /admin/settings/ai and click
"Xem phân tích AI" on any listing detail to get valuation + advice.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:20:24 +07:00
..