Vietnam dropped the district administrative level in the 2025 reform
(Nghị quyết về sắp xếp đơn vị hành chính). Only two levels remain:
province (level=4) and ward/commune (level=6).
OSM has updated tagging accordingly: every former xã/phường/thị trấn
that survived the merge is now `admin_level=6`, no `admin_level=8`
features for VN. Our sync confirmed this — 3,189 level=6 units inserted
across 33 provinces, level=8 returns zero.
The schema column "vn_districts" stays as-is to avoid a cascade-rename
across IndustrialPark / ProjectDevelopment / Property FKs. Documented
the semantic shift in osm-data-model.md so future ops don't think
something is broken when wards are empty.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Listing detail: drop the new <NearbyPoiSidebar> below the price card
with default 1.5km radius and 6 categories (school/secondary/hospital/
market/bank/metro). Reads property.lat/lng — no-op when unset.
* KCN detail: same component but 3km radius with the categories that
matter for industrial parks (hospital/bank/gas/bus/metro/police).
* New <PoiSearchFilter> widget for the search page: pill button →
popover with radius dropdown (300m..5km), 3 quick presets ("Family",
"Commute", "Convenience"), and 6 grouped category checkboxes. Wires
to a `PoiNearbyConstraint` value so callers can pass it into search
filters when they're ready.
* docs/osm-data-model.md: canonical reference for every OSM-sourced
table, sync cadence, quality gates, runbook for ops, and a clear
"how to add a new POI category" guide.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Finishes the half-implemented MFA enforcement work and ships the SLO
monitoring rules at the same time.
MFA grace period (auth):
- New `mfa-policy.ts` central source of truth: `MFA_REQUIRED_ROLES = [ADMIN]`,
`MFA_GRACE_PERIOD_DAYS = 14`, `MFA_REAUTH_WINDOW_MINUTES = 15`.
- New columns `User.mfaGraceStartedAt` + `User.mfaLastVerifiedAt`
(migration `20260429000000_add_mfa_grace_columns`).
- `JwtPayload.mfa: 'none' | 'grace' | 'enrollment_required'` claim now
carried in every access token so the FE + admin guards can react.
- `LoginUserHandler.resolveMfaGraceClaim()`:
* If role requires MFA and user has not enrolled, lazy-stamp
`mfaGraceStartedAt` on first login (returns `mfa: 'grace'`,
`remainingDays: 14`).
* After window expires → `mfa: 'enrollment_required'`, `remainingDays: 0`
(callers must force enrolment on sensitive routes).
* Otherwise → `mfa: 'none'`.
- `LocalStrategy` now passes `totpEnabled` + `mfaGraceStartedAt` through
to the command so the handler can branch without an extra query.
- `IUserRepository` + `PrismaUserRepository` get
`updateMfaGraceStartedAt` / `updateMfaLastVerifiedAt`.
- `UserEntity` carries the two new fields end-to-end (props, getters,
`createNew` + `createPasswordless` factories). Fixed an orphan-property
syntax bug in `createPasswordless` that was breaking typecheck.
- `oauth.service.ts` `UserEntity` construction now includes `deletedAt`
+ the two MFA fields (was missing required props).
- Add missing `jsonwebtoken` + `@types/jsonwebtoken` to `apps/api`
(transitively pulled in via `jwt-rotation.ts` from commit 3705193 but
never declared, so `tsc --noEmit` was failing).
- Update `login-user.handler.spec.ts` + `local.strategy.spec.ts` to cover
grace-window + enrolment-required branches. 338/338 auth tests pass.
Ops monitoring:
- New `monitoring/prometheus/slo-rules.yml` with recording + alerting
rules for the agreed SLOs.
- Wire it into `prometheus.yml` + alertmanager routing.
- Capture the SLO soak-test results in
`docs/audits/slo-soak-test-log.md`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extract shared `verifyWithRotation` helper and `makeSecretOrKeyProvider` into
`jwt-rotation.ts` so both REST (passport-jwt strategy) and WebSocket
(TokenService.verifyAccessToken) paths honour JWT_SECRET_PREVIOUS during
secret rotation. Add env-validation for optional previous secrets and
document the rotation policy for WebSocket sessions.
Resolves GOO-237
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
- Move 8 stray .md (+5 .txt) from ~/Desktop into docs/explorations/from-desktop/
- Reorganize 27 .md/.txt at workspace root:
- audit reports -> docs/audits/
- exploration reports -> docs/explorations/
- design system -> docs/design-system/
- Keep only README/CHANGELOG/CONTRIBUTING/CLAUDE at repo root
- Refresh docs/README.md as canonical index with links to all groups
- Note: pre-existing docs/audits/AUDIT_INDEX.md and AUDIT_SUMMARY.md were
overwritten by the newer root-level versions during the move
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Hoàn tất đợt cuối của nhiệm vụ chuyển toàn bộ tài liệu sang tiếng Việt.
Đã dịch 22 file `.md` còn sót (~9.7k dòng) — gồm RUNBOOK, audits,
docs/architecture, docs/load-testing, libs READMEs và các quick references.
Giữ nguyên code blocks, đường dẫn, identifier kỹ thuật, URL và biến môi trường.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The .md files (CLAUDE.md, architecture docs) already referenced Next.js 15
correctly. Fixed the two remaining .txt audit files that still said Next.js 14.
libs/ai-services and libs/mcp-servers were already documented in CLAUDE.md
and both had comprehensive READMEs.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Update stale Next.js 14 references to 15 in audit docs
- Add libs/ai-services and libs/mcp-servers to CLAUDE.md project structure
Resolves TEC-2259
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Previously, `docker image prune` ran immediately after deploying new
containers, potentially deleting the old images needed for rollback
if smoke tests subsequently failed. Now the deploy pipeline:
1. Tags current images as :rollback before pulling new versions
2. Only runs `docker image prune` after smoke tests pass
3. Uses explicit :rollback tags for rollback instead of relying on
Docker layer cache (which is fragile)
Applied to:
- scripts/deploy-production.sh (manual deploy script)
- .github/workflows/deploy.yml (staging + production CI jobs)
- docs/deployment.md (updated rollback documentation)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Expand production monitoring with full alert coverage for database connections,
Redis memory/connections, container resources, disk usage, service health, and
backup integrity. Add Alertmanager service with Slack routing for critical and
warning alerts, and add automated backup verification to the pg-backup cron
schedule. Update runbook with DR validation procedures and quarterly checklist.
- Expand Prometheus alert rules from 4 to 24 alerts across 7 groups
- Add Alertmanager container (prom/alertmanager:v0.27.0) with Slack routing
- Configure inhibition rules (critical suppresses warning for same service)
- Schedule automated backup verification at 04:00 UTC daily
- Add Alertmanager datasource to Grafana provisioning
- Update runbook with Section 9: DR Validation (automated + manual procedures)
- Add SLACK_WEBHOOK_URL and Grafana vars to .env.example
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Move remaining root-level audit and CQRS handler analysis files
to the centralized docs/audits/ directory for consistency.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Move 36 root-level audit/analysis documents and 7 web app audit documents
into docs/audits/ directory to declutter the project root. Remove stale
EXPLORATION_SUMMARY.txt.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Trigger deploy workflow on push to `develop` branch (in addition to `master`)
- Add `staging-latest` Docker image tag for develop branch builds
- Add `rollback-staging` job: auto-reverts to previous images on smoke test failure
- Add Slack success notification for staging deploys (previously only failure was notified)
- Record pre-deploy image digests for rollback capability
- Update deployment docs with CI/CD pipeline details, rollback procedures, and required secrets
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Create comprehensive docs/RUNBOOK.md covering all 14 production services,
health checks, 10 common incident scenarios with diagnosis/resolution,
recovery procedures (DB restore, Redis flush, rolling restart, rollback),
escalation matrix, monitoring dashboards, and PromQL queries.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Fix port numbers across all docs (API :3001, Web :3000)
- Add 6 missing modules to README, CLAUDE.md, and architecture doc
(agents, health, inquiries, leads, reviews, metrics/web-vitals)
- Add Swagger UI reference and /api/v1 prefix notes
- Create docs/api-endpoints.md with complete REST API reference
- Create docs/README.md as documentation index
- Update deployment guide with Loki, Promtail, pg-backup services
- Update health check table with all current endpoints
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Root directory had accumulated audit/exploration markdown files cluttering
the project root. Moved all audit-related files to docs/audits/ with a
README.md index, and updated cross-references in K6_LOAD_TESTING_GUIDE.md
and README_FRONTEND_DOCS.md.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Document all 33 structured errorCode values from DomainException/ErrorCode
enum across all modules (auth, user, listing, property, media, payment,
subscription, course). Includes HTTP status mapping, Vietnamese error
messages, usage examples per module, alphabetical quick-reference table,
and TypeScript integration guide for frontend error handling.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Remove hardcoded minioadmin/minioadmin_secret fallback from docker-compose.yml,
require MINIO_ACCESS_KEY/MINIO_SECRET_KEY env vars (fail-fast with :? syntax)
- Align docker-compose.yml env var names with .env.example (MINIO_ACCESS_KEY/SECRET_KEY)
- Update CI e2e workflow to use GitHub vars with non-default fallbacks
- Update .env.test to use non-default test credentials
- Add @aws-sdk/s3-request-presigner and getPresignedUploadUrl() method to
MinioMediaStorageService for properly signed client-side uploads
- Remove hardcoded credentials from dev-environment docs
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Add pg-backup container with daily automated pg_dump (02:00 UTC) and 7-day retention
- Add backup/restore scripts with documented recovery procedure
- Add Loki + Promtail for centralized log aggregation from all Docker containers
- Add Loki as Grafana datasource with correlation ID derived fields
- Add Grafana logs dashboard with volume, error rate, HTTP request, and log viewer panels
- Configure Promtail to parse Pino structured JSON logs with level/context labels
- Enhance LoggerService with string-level formatter and service base field
- Configure 15-day log retention in Loki
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Setup code quality tooling for the monorepo:
- ESLint 9 flat config with TypeScript, import ordering, and NestJS rules
- Prettier with consistent formatting across all files
- dependency-cruiser enforcing module boundary rules (no cross-module internals, no circular deps)
- Husky + lint-staged for pre-commit hooks
- Auto-fixed existing files for type imports and import ordering
Co-Authored-By: Paperclip <noreply@paperclip.ing>