API bootstrap fixes (DI wiring):
- analytics.module: add forwardRef(() => AdminModule) to import
AI_CONFIG_PROVIDER for GetListingAiAdviceHandler + GetProjectAiAdviceHandler
- listings.module: add PaymentsModule to imports so PAYMENT_INITIATOR is
resolvable by FeatureListingHandler
- metrics.module: register 3 missing Prometheus providers that MetricsService
injects (READ_MODEL_PROJECTOR_LAG_SECONDS / REFRESH_DURATION /
RECONCILIATION_DRIFT_TOTAL) — caused boot failure previously
- get-listing-ai-advice.handler: switch LISTING_REPOSITORY import from barrel
@modules/listings to direct internal path to break circular reference that
made the symbol evaluate as undefined at decorator time
- shared.module: comment out broken EVENT_BUS / OutboxService / OutboxRelay
providers (depend on @goodgo/contracts-events workspace pkg not yet wired)
CSRF middleware:
- Rewrite exclude logic as inline path-check inside the middleware itself.
Nest 11 + path-to-regexp v8 changed how MiddlewareConsumer.exclude() matches
against forRoutes('*') — the previous string patterns silently stopped
matching, causing every POST to /auth/login to return 403 CSRF Forbidden.
Inlined exempt list strips the /api/v1 prefix and checks against a Set.
Admin revenue stats:
- admin-stats.queries: use Prisma.sql template fragments for DATE_TRUNC unit
('day'|'month'). Passing the unit as a bind parameter caused Postgres error
42803 (column must appear in GROUP BY) because the planner treats $1 as an
opaque scalar and cannot prove SELECT and GROUP BY expressions are equal.
Admin audit-log page:
- SeverityPill: add ?? 'info' fallback — backend AuditLogEntry does not
include a `severity` field, so SEVERITY_CONFIG[undefined] was undefined
and .dir threw TypeError, crashing the whole audit-log page.
DB seed fixes:
- seed.ts: replace Vietnamese enum literals ('Sổ hồng', 'Sổ đỏ') with
correct enum keys ('SO_HONG', 'SO_DO') for the LegalStatus column
- seed-industrial-parks.ts: gate the standalone main() behind
require.main === module so importing the file from seed.ts doesn't
immediately close the pg.Pool used by the orchestrator
- scripts/seed-industrial-listings.ts: restore from tmp/ stash; was missing
from scripts/ causing seed.ts import to fail at startup
- migration 20260429010000_add_property_certificate_verified: Property table
was missing the certificateVerified column required by seed + Prisma schema
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a 5 s polling collector that publishes BullMQ queue depth as the
goodgo_queue_depth gauge (labels: queue, state) and a
goodgo_queue_job_outcomes_total counter for processor hooks. The collector
fails-soft on Redis errors so a queue blip cannot crash the app.
- New constants: QUEUE_DEPTH_GAUGE, QUEUE_JOB_OUTCOMES_TOTAL,
QUEUE_METRICS_QUEUE_NAMES (extend as Phase 2 adds queues)
- New QueueMetricsCollector with injectable timer/clock for tests
- MetricsModule.withQueueMetrics() dynamic module wires queue tokens via
getQueueToken + factory provider; re-imports BullModule.registerQueue so
ordering between MetricsModule and feature modules does not matter
- AppModule mounts MetricsModule.withQueueMetrics() alongside MetricsModule
- 4 unit tests cover sample → gauge mapping, Redis-down fail-soft,
recordJobOutcome, and timer init/destroy
Bull Board UI mount split into WS3b (needs @bull-board/* deps).
Refs: GOO-175
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- 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>
- Extract metric names into constants with goodgo_ prefix for business metrics
- Add MetricsService for type-safe metric recording
- Add HttpMetricsInterceptor for automatic request duration/count tracking
- Register interceptor globally via APP_INTERCEPTOR
- Include linter auto-fixes for test files
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Fix DI issues: circular MCP module dependency, EventBus type import,
SearchModule provider, CacheService metric counters placement
- Fix Express 5 readonly req.query in SanitizeInputMiddleware
- Fix Typesense client lazy initialization (getter instead of constructor)
- Fix MinIO bucket init error handling (non-fatal on 403)
- Fix missing class-validator decorators on bigint DTO fields (priceVND, amountVND)
- Fix subscription plan 404 (was returning 500 for invalid tier)
- Disable CSRF and raise rate limits in test environment
- Update E2E tests to match actual API response shapes
- Update CI workflow with Redis, Typesense, MinIO services and env vars
All 101 API E2E tests now pass against Docker dev environment.
Co-Authored-By: Paperclip <noreply@paperclip.ing>