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:
@@ -3,7 +3,6 @@
|
||||
* calls use cases, maps domain errors to the shared error envelope.
|
||||
*/
|
||||
import type { FastifyInstance, FastifyReply } from 'fastify';
|
||||
import fastifyCookie from '@fastify/cookie';
|
||||
import { z } from 'zod';
|
||||
import { parseJson } from '../../../shared/http-input.js';
|
||||
import { AppError } from '../../../shared/errors.js';
|
||||
@@ -47,8 +46,6 @@ export async function registerIdentityRoutes(
|
||||
app: FastifyInstance,
|
||||
deps: IdentityRoutesDeps,
|
||||
): Promise<void> {
|
||||
await app.register(fastifyCookie);
|
||||
|
||||
const cookieSecure = deps.cookieSecure ?? true;
|
||||
const hasher = deps.hasher ?? new Argon2PasswordHasher();
|
||||
const users = new PgUserRepository(deps.pool);
|
||||
@@ -70,7 +67,9 @@ export async function registerIdentityRoutes(
|
||||
const input = parseJson(credentialsSchema, request.body);
|
||||
try {
|
||||
const user = await registerUser.execute(input);
|
||||
return reply.code(201).send({ id: user.id, email: user.email, createdAt: user.createdAt });
|
||||
return reply
|
||||
.code(201)
|
||||
.send({ id: user.id, email: user.email, role: user.role, createdAt: user.createdAt });
|
||||
} catch (error) {
|
||||
if (error instanceof EmailAlreadyRegisteredError) {
|
||||
throw new AppError(409, 'EMAIL_ALREADY_REGISTERED', 'Email already registered');
|
||||
@@ -84,7 +83,9 @@ export async function registerIdentityRoutes(
|
||||
try {
|
||||
const result = await login.execute(input);
|
||||
setSessionCookie(reply, result.token, cookieSecure);
|
||||
return reply.code(200).send({ id: result.user.id, email: result.user.email });
|
||||
return reply
|
||||
.code(200)
|
||||
.send({ id: result.user.id, email: result.user.email, role: result.user.role });
|
||||
} catch (error) {
|
||||
if (error instanceof RateLimitedError) {
|
||||
void reply.header('Retry-After', String(Math.ceil(error.retryAfterMs / 1000)));
|
||||
|
||||
Reference in New Issue
Block a user