Identity (backend)

This commit is contained in:
David Arranz 2026-07-05 11:44:10 +02:00
parent 55b8bb8473
commit 494c675483
15 changed files with 42 additions and 65 deletions

16
modules/auth/README.md Normal file
View File

@ -0,0 +1,16 @@
# `@erp/auth`
Estado actual:
- Este módulo está en estado legacy para backend.
- El runtime nuevo de autenticación backend vive en `modules/identity`.
- Los módulos backend nuevos deben usar `@erp/identity/api`.
- Para rutas tenant-scoped usar `requireIdentityTenant(params)`.
- Para rutas solo autenticadas usar `requireIdentityAuthenticated(params)`.
- `@erp/auth/api` se mantiene temporalmente solo por `supplier`.
- No añadir nuevos imports backend a `@erp/auth/api`.
Importante:
- Este paquete sigue exponiendo `@erp/auth/client`, por lo que no debe retirarse todavía.
- No cambiar ni borrar exports legacy mientras `supplier` siga sin migrarse.

View File

@ -1,3 +1,10 @@
/**
* Legacy backend auth exports.
*
* Nuevos consumidores backend deben usar `@erp/identity/api`.
* Este punto de entrada se mantiene temporalmente mientras `supplier`
* siga dependiendo de `@erp/auth/api`.
*/
export * from "./mock-user.middleware"; export * from "./mock-user.middleware";
export * from "./require-authenticated.middleware"; export * from "./require-authenticated.middleware";
export * from "./require-company-context.middleware"; export * from "./require-company-context.middleware";

View File

@ -39,10 +39,10 @@
"@dnd-kit/core": "^6.3.1", "@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0", "@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2", "@dnd-kit/utilities": "^3.2.2",
"@erp/auth": "workspace:*",
"@erp/core": "workspace:*", "@erp/core": "workspace:*",
"@erp/catalogs": "workspace:*", "@erp/catalogs": "workspace:*",
"@erp/customers": "workspace:*", "@erp/customers": "workspace:*",
"@erp/identity": "workspace:*",
"@hookform/resolvers": "^5.2.2", "@hookform/resolvers": "^5.2.2",
"@lglab/react-qr-code": "^1.4.10", "@lglab/react-qr-code": "^1.4.10",
"@repo/i18next": "workspace:*", "@repo/i18next": "workspace:*",

View File

@ -8,7 +8,6 @@ import type { IIssuedInvoiceReportSnapshotBuilder } from "../snapshot-builders/r
type ReportIssuedInvoiceUseCaseInput = { type ReportIssuedInvoiceUseCaseInput = {
companyId: UniqueID; companyId: UniqueID;
companySlug: string;
invoice_id: string; invoice_id: string;
format: RendererFormat; format: RendererFormat;
}; };

View File

@ -8,7 +8,6 @@ import type { IProformaReportSnapshotBuilder } from "../snapshot-builders/report
type ReportProformaUseCaseInput = { type ReportProformaUseCaseInput = {
companyId: UniqueID; companyId: UniqueID;
companySlug: string;
proforma_id: string; proforma_id: string;
format: RendererFormat; format: RendererFormat;
}; };

View File

@ -15,7 +15,7 @@ export type { IProformaPublicServices } from "./application";
export const customerInvoicesAPIModule: IModuleServer = { export const customerInvoicesAPIModule: IModuleServer = {
name: "customer-invoices", name: "customer-invoices",
version: "1.0.0", version: "1.0.0",
dependencies: ["catalogs", "customers"], dependencies: ["catalogs", "customers", "identity"],
/** /**
* Fase de SETUP * Fase de SETUP

View File

@ -29,14 +29,12 @@ export class ReportIssuedInvoiceController extends ExpressController {
return this.forbiddenError("Tenant ID not found"); return this.forbiddenError("Tenant ID not found");
} }
const { companySlug } = this.getUser();
const { invoice_id } = this.req.params; const { invoice_id } = this.req.params;
const { format } = this.req.query as ReportIssueInvoiceByIdQueryRequestDTO; const { format } = this.req.query as ReportIssueInvoiceByIdQueryRequestDTO;
const result = await this.useCase.execute({ const result = await this.useCase.execute({
invoice_id, invoice_id,
companyId, companyId,
companySlug,
format: format as RendererFormat, format: format as RendererFormat,
}); });

View File

@ -1,5 +1,5 @@
import { mockUser, requireAuthenticated, requireCompanyContext } from "@erp/auth/api"; import { type StartParams, validateRequest } from "@erp/core/api";
import { type RequestWithAuth, type StartParams, validateRequest } from "@erp/core/api"; import { requireIdentityTenant } from "@erp/identity/api";
import { type NextFunction, type Request, type Response, Router } from "express"; import { type NextFunction, type Request, type Response, Router } from "express";
import { import {
@ -25,21 +25,7 @@ export const issuedInvoicesRouter = (params: StartParams) => {
// ---------------------------------------------- // ----------------------------------------------
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "production") { router.use(...requireIdentityTenant(params));
// 🔐 Autenticación + Tenancy para TODO el router
router.use(
(req: Request, res: Response, next: NextFunction) =>
mockUser(req as RequestWithAuth, res, next) // Debe ir antes de las rutas protegidas
);
}
router.use([
(req: Request, res: Response, next: NextFunction) =>
requireAuthenticated()(req as RequestWithAuth, res, next), // Debe ir antes de las rutas protegidas
(req: Request, res: Response, next: NextFunction) =>
requireCompanyContext()(req as RequestWithAuth, res, next), // Debe ir antes de las rutas protegidas
]);
// ---------------------------------------------- // ----------------------------------------------

View File

@ -29,14 +29,12 @@ export class ReportProformaController extends ExpressController {
return this.forbiddenError("Tenant ID not found"); return this.forbiddenError("Tenant ID not found");
} }
const { companySlug } = this.getUser();
const { proforma_id } = this.req.params; const { proforma_id } = this.req.params;
const { format } = this.req.query as ReportProformaByIdQueryRequestDTO; const { format } = this.req.query as ReportProformaByIdQueryRequestDTO;
const result = await this.useCase.execute({ const result = await this.useCase.execute({
proforma_id, proforma_id,
companyId, companyId,
companySlug,
format: format as RendererFormat, format: format as RendererFormat,
}); });

View File

@ -1,5 +1,5 @@
import { mockUser, requireAuthenticated, requireCompanyContext } from "@erp/auth/api"; import { type StartParams, validateRequest } from "@erp/core/api";
import { type RequestWithAuth, type StartParams, validateRequest } from "@erp/core/api"; import { requireIdentityTenant } from "@erp/identity/api";
import { type NextFunction, type Request, type Response, Router } from "express"; import { type NextFunction, type Request, type Response, Router } from "express";
import { import {
@ -43,21 +43,7 @@ export const proformasRouter = (params: StartParams) => {
// ---------------------------------------------- // ----------------------------------------------
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "production") { router.use(...requireIdentityTenant(params));
// 🔐 Autenticación + Tenancy para TODO el router
router.use(
(req: Request, res: Response, next: NextFunction) =>
mockUser(req as RequestWithAuth, res, next) // Debe ir antes de las rutas protegidas
);
}
router.use([
(req: Request, res: Response, next: NextFunction) =>
requireAuthenticated()(req as RequestWithAuth, res, next), // Debe ir antes de las rutas protegidas
(req: Request, res: Response, next: NextFunction) =>
requireCompanyContext()(req as RequestWithAuth, res, next), // Debe ir antes de las rutas protegidas
]);
// ---------------------------------------------- // ----------------------------------------------

View File

@ -2,7 +2,8 @@
"extends": "../../tsconfig.json", "extends": "../../tsconfig.json",
"compilerOptions": { "compilerOptions": {
"paths": { "paths": {
"@erp/customer-invoices/*": ["./src/*"] "@erp/customer-invoices/*": ["./src/*"],
"@erp/identity/*": ["../identity/src/*"]
}, },
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",

View File

@ -21,11 +21,11 @@
"typescript": "^6.0.2" "typescript": "^6.0.2"
}, },
"dependencies": { "dependencies": {
"@erp/auth": "workspace:*",
"@erp/core": "workspace:*", "@erp/core": "workspace:*",
"@erp/catalogs": "workspace:*", "@erp/catalogs": "workspace:*",
"@erp/customer-invoices": "workspace:*", "@erp/customer-invoices": "workspace:*",
"@erp/customers": "workspace:*", "@erp/customers": "workspace:*",
"@erp/identity": "workspace:*",
"@repo/i18next": "workspace:*", "@repo/i18next": "workspace:*",
"@repo/rdx-criteria": "workspace:*", "@repo/rdx-criteria": "workspace:*",
"@repo/rdx-ddd": "workspace:*", "@repo/rdx-ddd": "workspace:*",

View File

@ -6,7 +6,7 @@ import { buildFactugesDependencies } from "./infraestructure/di";
export const factugesAPIModule: IModuleServer = { export const factugesAPIModule: IModuleServer = {
name: "factuges", name: "factuges",
version: "1.0.0", version: "1.0.0",
dependencies: ["catalogs", "customers", "customer-invoices"], dependencies: ["catalogs", "customers", "customer-invoices", "identity"],
/** /**
* Fase de SETUP * Fase de SETUP

View File

@ -1,8 +1,8 @@
import { mockUser, requireAuthenticated, requireCompanyContext } from "@erp/auth/api"; import { type StartParams, validateRequest } from "@erp/core/api";
import { type RequestWithAuth, type StartParams, validateRequest } from "@erp/core/api";
import type { IProformaPublicServices } from "@erp/customer-invoices/api"; import type { IProformaPublicServices } from "@erp/customer-invoices/api";
import type { ICustomerPublicServices } from "@erp/customers/api"; import type { ICustomerPublicServices } from "@erp/customers/api";
import { CreateProformaFromFactugesRequestSchema } from "@erp/factuges/common"; import { CreateProformaFromFactugesRequestSchema } from "@erp/factuges/common";
import { requireIdentityTenant } from "@erp/identity/api";
import { type NextFunction, type Request, type Response, Router } from "express"; import { type NextFunction, type Request, type Response, Router } from "express";
import type { FactugesInternalDeps } from "../di/factuges.di"; import type { FactugesInternalDeps } from "../di/factuges.di";
@ -27,21 +27,7 @@ export const factugesRouter = (params: StartParams) => {
const router: Router = Router({ mergeParams: true }); const router: Router = Router({ mergeParams: true });
// 🔐 Autenticación + Tenancy para TODO el router // 🔐 Autenticación + Tenancy para TODO el router
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "production") { router.use(...requireIdentityTenant(params));
router.use(
(req: Request, res: Response, next: NextFunction) =>
mockUser(req as RequestWithAuth, res, next) // Debe ir antes de las rutas protegidas
);
}
//router.use(/*authenticateJWT(),*/ enforceTenant() /*checkTabContext*/);
router.use([
(req: Request, res: Response, next: NextFunction) =>
requireAuthenticated()(req as RequestWithAuth, res, next), // Debe ir antes de las rutas protegidas
(req: Request, res: Response, next: NextFunction) =>
requireCompanyContext()(req as RequestWithAuth, res, next), // Debe ir antes de las rutas protegidas
]);
// ---------------------------------------------- // ----------------------------------------------

View File

@ -2,7 +2,8 @@
"extends": "../../tsconfig.json", "extends": "../../tsconfig.json",
"compilerOptions": { "compilerOptions": {
"paths": { "paths": {
"@erp/factuges/*": ["./src/*"] "@erp/factuges/*": ["./src/*"],
"@erp/identity/*": ["../identity/src/*"]
}, },
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",