FactuGES_ERP/docs/companies/company-requirements.md

235 lines
8.0 KiB
Markdown
Raw Normal View History

# Requisitos de `companies`
Estado documental: `CURRENT`
Fecha de actualizacion: 2026-08-26
## Proposito y fuente de verdad
`companies` es el bounded context y la fuente de verdad de la ficha operativa
de cada empresa tenant del ERP. Este documento define el contrato funcional
vigente del contexto.
La autenticacion, las cuentas y las memberships no pertenecen a `companies`.
Esas responsabilidades corresponden a `identity`. Para las decisiones de
integracion entre ambos contextos, prevalece
[`identity-and-companies.md`](../architecture/identity-and-companies.md). Para
la resolucion del tenant, prevalece
[`tenant-context.md`](../architecture/tenant-context.md).
## Alcance actual
El contexto debe gestionar:
- la ficha legal y operativa basica de `Company`;
- el identificador funcional `slug`;
- el estado operativo de la empresa (`active` o `disabled`);
- el plazo de pago por defecto de la empresa;
- la consulta de empresas disponibles para una cuenta autenticada;
- la consulta y actualizacion de la empresa activa.
El contexto no debe gestionar:
- autenticacion, sesiones, refresh tokens o cuentas;
- `CompanyMembership`, roles o permisos por cuenta;
- datos de la empresa dentro de `identity`;
- clientes como representacion de la empresa tenant;
- fiscalidad avanzada, perfiles VeriFactu, series documentales, medios de pago,
direccion, branding, bancos, idiomas, divisas o zona horaria.
Los requisitos de VeriFactu empresarial viven en `customer-invoices` y no
amplian por si mismos el aggregate `Company`.
## Modelo funcional
Una empresa se identifica por un UUID y contiene los siguientes datos:
| Campo | Regla vigente |
| --- | --- |
| `legal_name` | Obligatorio. Nombre legal de la empresa. |
| `trade_name` | Opcional y nullable. Nombre comercial. |
| `tin` | Opcional y nullable. Identificador fiscal. |
| `slug` | Obligatorio, unico, normalizado a minusculas; solo letras, numeros y guiones, de 2 a 100 caracteres. |
| `email` | Opcional y nullable; debe tener formato valido. |
| `phone` | Opcional y nullable. |
| `website` | Opcional y nullable; debe tener formato URL valido. |
| `default_payment_term_id` | Opcional y nullable; referencia viva a un plazo de pago activo de la misma empresa. |
| `status` | `active` o `disabled`. |
La persistencia de `companies` debe conservar tambien `created_at` y
`updated_at`. `slug` es unico; deben existir indices para `status` y `tin`.
## Separacion con `identity`
- `identity` es propietario de `Account` y `CompanyMembership`.
- `companies` es propietario de `Company` y de su ficha operativa.
- El access token solo identifica la cuenta; no contiene `companyId`,
`companySlug`, roles ni permisos.
- `identity` resuelve que IDs de empresa son accesibles para una cuenta.
- `companies` resuelve las fichas completas de esas empresas y valida que una
empresa este activa.
- No se deben crear `GET /identity/companies` ni `GET /account/companies`.
- No se debe crear una dependencia `identity -> companies`.
## Contexto tenant y autorizacion V1
Las rutas tenant-scoped deben recibir:
```http
Authorization: Bearer <access_token>
X-Company-Id: <uuid-company>
```
El contexto tenant es valido solo si la cuenta esta autenticada, el header es
un UUID valido, existe una membership `active` para esa empresa y la empresa
tiene estado `active`. La empresa destino se toma de ese contexto, nunca de un
`companyId` libre en body, query o ruta cuando se trate de la API actual de
empresa activa.
En la V1, cualquier miembro activo de una empresa activa puede actualizar los
datos generales de esa empresa mediante `PATCH /companies/current`. No existe
todavia enforcement runtime de RBAC ni un permiso granular efectivo como
`identity:companies:update`.
Una empresa deshabilitada no puede actualizarse. Los endpoints legacy con
`:company_id` deben exigir que dicho ID coincida exactamente con la empresa
resuelta en el contexto tenant.
## Contratos HTTP vigentes
### Alta y seleccion de empresa
```http
POST /companies
GET /companies/available
```
`POST /companies` crea una empresa activa. Recibe `id`, `legal_name` y `slug`
como datos obligatorios; el resto de datos de ficha son opcionales. Al crearla,
`default_payment_term_id` queda vacio y el estado es `active`.
`GET /companies/available` requiere autenticacion, pero no `X-Company-Id`.
Debe devolver solo las empresas que cumplan simultaneamente:
```txt
membership activa de la cuenta
+
empresa activa
```
La respuesta no debe modificar la sesion ni el access token.
### Empresa activa
```http
GET /companies/current
PATCH /companies/current
```
Estas son las rutas canonicamente usadas por Settings para
`/settings/company/details`. Requieren contexto tenant valido y operan siempre
sobre la empresa resuelta mediante `X-Company-Id`.
`PATCH /companies/current` admite exclusivamente:
```txt
legal_name
trade_name
tin
email
phone
website
default_payment_term_id
```
No admite modificar `slug` ni `status`. La semantica es PATCH real:
- un campo omitido conserva su valor;
- un campo nullable presente con `null` limpia su valor;
- un campo presente con valor valido actualiza su valor;
- la respuesta del servidor es el estado autoritativo de la ficha.
### Rutas legacy por ID
```http
GET /companies/:company_id
PATCH /companies/:company_id
POST /companies/:company_id/enable
POST /companies/:company_id/disable
```
Estas rutas siguen expuestas por compatibilidad. Requieren contexto tenant
valido y el `:company_id` debe ser la misma empresa activa del header. En la
actualizacion legacy se permite adicionalmente modificar `slug`; su unicidad
debe validarse antes de persistir.
## Plazo de pago por defecto
`default_payment_term_id` es una referencia nullable y company-scoped hacia
`catalogs`. Su contrato es:
- omitido: conservar la asociacion actual;
- `null`: desvincular el plazo de pago;
- UUID: asociar solo si identifica un plazo activo de la misma empresa.
Una referencia inexistente, de otra empresa o inactiva debe responder `422` con
el mensaje opaco `Default payment term is not assignable to the active company.`
No se debe revelar cual de esas causas se produjo. La validacion y la
actualizacion deben formar una unica transaccion: si falla la referencia, no se
persisten otros cambios del mismo PATCH.
## Respuesta de empresa
Las consultas y mutaciones de ficha devuelven:
```ts
type CompanyResponseDTO = {
id: string;
legal_name: string;
trade_name: string | null;
tin: string | null;
slug: string;
email: string | null;
phone: string | null;
website: string | null;
default_payment_term_id: string | null;
status: "active" | "disabled";
};
```
La lista de `GET /companies/available` devuelve el mismo subconjunto de ficha
necesario para seleccionar empresa, sin `default_payment_term_id`, y con
`status: "active"`.
## Errores esperados
| Situacion | Respuesta |
| --- | --- |
| Sin autenticacion, token invalido o cuenta no autenticable | `401` |
| UUID tenant mal formado o body invalido | `400` |
| Sin `X-Company-Id`, membership no activa, empresa no accesible, deshabilitada o destino distinto al tenant | `403` |
| Colision de `slug` | `409` |
| Campo con regla de dominio invalida o plazo de pago no asignable | `422` |
| Error no controlado | `500` |
## Auditoria y consistencia
Las operaciones de alta y actualizacion de empresa deben registrar sus eventos
de auditoria. Las mutaciones deben ser transaccionales para no dejar la ficha y
el registro de auditoria en estados divergentes.
## Fuera de alcance y evolucion futura
No se deben inferir como requisitos actuales:
- RBAC granular o administracion global de empresas;
- cambios de `status` autorizados por un rol administrativo real;
- direccion, pais, idioma, moneda, zona horaria o branding;
- cuentas bancarias, logo, medios de pago o `defaultPaymentMethodId`;
- fiscalidad avanzada, configuracion VeriFactu o series documentales.
Estas capacidades requieren un contrato propio antes de incorporarse a
`companies`. Hasta entonces, los documentos de otros bounded contexts deben
enlazar esta especificacion al describir la ficha de empresa, sin duplicar ni
reasignar su ownership.