feat(F-006): users profile, addresses and RBAC
- users module: profile + address CRUD behind use cases (users_profiles, users_addresses) - roles customer/admin on identity_users; role resolved from DB per request - shared auth contract (Authenticate, requireRole, requireOwnerOrAdmin) injected from composition root; users never imports identity - authorization runs before existence checks; address SQL scoped by user_id - @fastify/cookie registered once at app root (cross-module) - migrations 003_identity_roles + 004_users (reversible) - no new npm dependencies; tests: unit 52, integration 22 Gates: reviewer/security/qa APPROVED; verify.sh green
This commit is contained in:
@@ -5,11 +5,13 @@
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { performance } from 'node:perf_hooks';
|
||||
import Fastify, { type FastifyInstance } from 'fastify';
|
||||
import fastifyCookie from '@fastify/cookie';
|
||||
import type { FastifyError, FastifyReply, FastifyRequest } from 'fastify';
|
||||
import type { IncomingMessage } from 'node:http';
|
||||
import type pg from 'pg';
|
||||
import { registerHealthRoutes } from '../modules/health/index.js';
|
||||
import { registerIdentityRoutes } from '../modules/identity/index.js';
|
||||
import { registerIdentityRoutes, createSessionAuthenticator } from '../modules/identity/index.js';
|
||||
import { registerUsersRoutes } from '../modules/users/index.js';
|
||||
import { createFlagStore, type FeatureFlagProvider } from '../modules/flags/index.js';
|
||||
import { AppError, errorEnvelope } from '../shared/errors.js';
|
||||
import { createLogger, type Logger } from '../infrastructure/logging/logger.js';
|
||||
@@ -113,6 +115,9 @@ export async function buildApp(deps: BuildAppDeps = {}): Promise<FastifyInstance
|
||||
await registerHealthRoutes(instance);
|
||||
});
|
||||
|
||||
// Cookie infrastructure is cross-module (identity + users): register once at root.
|
||||
await app.register(fastifyCookie);
|
||||
|
||||
if (deps.pool) {
|
||||
await app.register(async (instance) => {
|
||||
await registerIdentityRoutes(instance, {
|
||||
@@ -120,6 +125,16 @@ export async function buildApp(deps: BuildAppDeps = {}): Promise<FastifyInstance
|
||||
cookieSecure: deps.cookieSecure,
|
||||
});
|
||||
});
|
||||
|
||||
// Session resolution is identity's; users receives it by injection so no
|
||||
// module ever imports another module.
|
||||
const authenticate = createSessionAuthenticator(deps.pool);
|
||||
await app.register(async (instance) => {
|
||||
await registerUsersRoutes(instance, {
|
||||
pool: deps.pool as pg.Pool,
|
||||
authenticate,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return app;
|
||||
|
||||
Reference in New Issue
Block a user