feat: add apps/api (NestJS + Fastify) with authentication endpoints
- POST /auth/login, /auth/refresh, /auth/logout, /auth/select-tenant, /auth/change-password, GET /auth/tenants — wired to packages/auth - JwtAuthGuard + DomainExceptionFilter (401/403 without leaking internals) - LoginRateLimitGuard: Redis-backed 5/min per IP and per email (agente.md secao 149), safe across multiple API instances - helmet + restrictive cors (deny-by-default) + global rate limit - GET /health, /health/live, /health/ready checking Postgres and Redis - changePassword() added to packages/auth for the mustChangePassword flow - fixed REDIS_HOST/POSTGRES_HOST docker-compose-only hostnames not resolving from the host process; added REDIS_URL for host-side use - verified end-to-end with curl: login, wrong password / unknown email (same generic error), authenticated route, missing token, refresh rotation, logout revocation, and the 429 rate limit kicking in after 5 attempts
This commit is contained in:
40
apps/api/src/health/health.controller.ts
Normal file
40
apps/api/src/health/health.controller.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Controller, Get, HttpException, HttpStatus } from "@nestjs/common";
|
||||
import { getPrismaClient } from "@b2bcall/database";
|
||||
import { getRedisClient } from "../common/redis";
|
||||
|
||||
@Controller("health")
|
||||
export class HealthController {
|
||||
@Get()
|
||||
root() {
|
||||
return { status: "ok" };
|
||||
}
|
||||
|
||||
@Get("live")
|
||||
live() {
|
||||
return { status: "ok" };
|
||||
}
|
||||
|
||||
@Get("ready")
|
||||
async ready() {
|
||||
const checks: Record<string, "ok" | "fail"> = { postgres: "ok", redis: "ok" };
|
||||
|
||||
try {
|
||||
await getPrismaClient().$queryRaw`SELECT 1`;
|
||||
} catch {
|
||||
checks.postgres = "fail";
|
||||
}
|
||||
|
||||
try {
|
||||
await getRedisClient().ping();
|
||||
} catch {
|
||||
checks.redis = "fail";
|
||||
}
|
||||
|
||||
const healthy = Object.values(checks).every((v) => v === "ok");
|
||||
if (!healthy) {
|
||||
throw new HttpException({ status: "unhealthy", checks }, HttpStatus.SERVICE_UNAVAILABLE);
|
||||
}
|
||||
|
||||
return { status: "ok", checks };
|
||||
}
|
||||
}
|
||||
7
apps/api/src/health/health.module.ts
Normal file
7
apps/api/src/health/health.module.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { HealthController } from "./health.controller";
|
||||
|
||||
@Module({
|
||||
controllers: [HealthController],
|
||||
})
|
||||
export class HealthModule {}
|
||||
Reference in New Issue
Block a user