This commit is contained in:
David Arranz 2026-02-10 13:39:55 +01:00
parent 2b3dfce72c
commit 3a1c7e0844
47 changed files with 183 additions and 158 deletions

2
.vscode/launch.json vendored
View File

@ -1,5 +1,5 @@
{
"version": "0.2.7",
"version": "0.3.6",
"configurations": [
{
"name": "WEB: Vite (Chrome)",

View File

@ -1,53 +0,0 @@
# ───────────────────────────────
# Identidad de la compañía
# ───────────────────────────────
COMPANY=rodax
CTE_COMPANY_ID=5e4dc5b3-96b9-4968-9490-14bd032fec5f
# Dominios
DOMAIN=factuges.rodax-software.local
# ───────────────────────────────
# Base de datos (Sequelize / MySQL-MariaDB)
# ───────────────────────────────
DB_ROOT_PASS=verysecret
DB_USER=rodax_usr
DB_PASS=supersecret
DB_NAME=rodax_db
DB_PORT=3306
# Log de Sequelize (true|false)
DB_LOGGING=false
# Alterar estructura BD
DB_SYNC_MODE=none # none | alter | force
# ───────────────────────────────
# API
# ───────────────────────────────
API_PORT=3002
API_IMAGE=factuges-server:rodax-latest
# Plantillas
TEMPLATES_PATH=/repo/apps/server/templates
# Documentos generados
DOCUMENTS_PATH=/home/rodax/Documentos/uecko-erp/out/rodax/documents
# Firma de documentos
SIGN_DOCUMENTS=false
SIGNED_DOCUMENTS_PATH=/home/rodax/Documentos/uecko-erp/out/rodax/signed-documents
# Chrome executable path (Puppeteer)
# PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome
# URL pública del frontend (CORS)
FRONTEND_URL=factuges.rodax-software.local
# Tiempo máximo para cada warmup() de un módulo, en milisegundos.
WARMUP_TIMEOUT_MS=10000
# Si es true, un fallo de warmup aborta el arranque. Si es false, continúa con warning.
WARMUP_STRICT=false

View File

@ -1,6 +1,6 @@
{
"name": "@erp/factuges-server",
"version": "0.2.7",
"version": "0.3.6",
"private": true,
"scripts": {
"build": "tsup src/index.ts --config tsup.config.ts",

View File

@ -52,6 +52,14 @@ const DOCUMENTS_PATH = process.env.DOCUMENTS_PATH ?? "./documents";
// Proxy (no usáis ahora, pero dejamos la variable por si se activa en el futuro)
const TRUST_PROXY = asNumber(process.env.TRUST_PROXY, 0);
const SIGNING_SERVICE_URL = process.env.SIGNING_SERVICE_URL;
const SIGNING_SERVICE_METHOD = process.env.SIGNING_SERVICE_METHOD ?? "POST";
const SIGNING_SERVICE_TIMEOUT_MS = asNumber(process.env.SIGNING_SERVICE_TIMEOUT_MS, 15_000);
const SIGNING_SERVICE_MAX_RETRIES = asNumber(process.env.SIGNING_SERVICE_MAX_RETRIES, 2);
const COMPANY_SLUG = process.env.COMPANY_SLUG ?? "acme";
const COMPANY_CERTIFICATES_JSON = process.env.COMPANY_CERTIFICATES_JSON ?? {};
export const ENV = {
NODE_ENV,
API_PORT,
@ -67,9 +75,18 @@ export const ENV = {
DB_SYNC_MODE,
APP_TIMEZONE,
TRUST_PROXY,
TEMPLATES_PATH,
DOCUMENTS_PATH,
FASTREPORT_BIN,
SIGNING_SERVICE_URL,
SIGNING_SERVICE_METHOD,
SIGNING_SERVICE_TIMEOUT_MS,
SIGNING_SERVICE_MAX_RETRIES,
COMPANY_SLUG,
COMPANY_CERTIFICATES_JSON,
} as const;
export const Flags = {

View File

@ -215,6 +215,7 @@ process.on("uncaughtException", async (error: Error) => {
logger.info(`FRONTEND_URL: ${ENV.FRONTEND_URL}`);
logger.info(`DB_DIALECT: ${ENV.DB_DIALECT}`);
logger.info(`DB_HOST: ${ENV.DB_HOST}`);
logger.info(`DB_PORT: ${ENV.DB_PORT}`);
logger.info(`DB_NAME: ${ENV.DB_NAME}`);
@ -225,6 +226,9 @@ process.on("uncaughtException", async (error: Error) => {
logger.info(`FASTREPORT_BIN: ${ENV.FASTREPORT_BIN}`);
logger.info(`TEMPLATES_PATH: ${ENV.TEMPLATES_PATH}`);
logger.info(`SIGNING_SERVICE_URL: ${ENV.SIGNING_SERVICE_URL}`);
logger.info(`SIGNING_SERVICE_METHOD: ${ENV.SIGNING_SERVICE_METHOD}`);
const database = await tryConnectToDatabase();
// Lógica de inicialización de DB, si procede:

View File

@ -0,0 +1,14 @@
{
"mimeType": "application/pdf",
"filename": "issued-invoice.pdf",
"metadata": {
"documentType": "issued-invoice",
"documentId": "019c1ef1-7c3d-79ed-a12f-995cdc40252f",
"companyId": "5e4dc5b3-96b9-4968-9490-14bd032fec5f",
"companySlug": "rodax",
"format": "PDF",
"languageCode": "es",
"filename": "factura-021.pdf",
"cacheKey": "issued-invoice:5e4dc5b3-96b9-4968-9490-14bd032fec5f:021:v1"
}
}

View File

@ -1,7 +1,7 @@
{
"name": "@erp/factuges-web",
"private": true,
"version": "0.2.7",
"version": "0.3.6",
"type": "module",
"scripts": {
"dev": "vite --host --clearScreen false",

View File

@ -1,6 +1,6 @@
{
"name": "@erp/auth",
"version": "0.1.7",
"version": "0.3.6",
"private": true,
"type": "module",
"sideEffects": false,

View File

@ -1,6 +1,6 @@
{
"name": "@erp/core",
"version": "0.1.7",
"version": "0.3.6",
"private": true,
"type": "module",
"sideEffects": false,

View File

@ -2,6 +2,7 @@ export interface IDocumentMetadata {
readonly documentType: string;
readonly documentId: string;
readonly companyId: string;
readonly companySlug: string;
readonly format: "PDF" | "HTML";
readonly languageCode: string;
readonly filename: string;

View File

@ -76,6 +76,7 @@ export class DocumentGenerationService<TSnapshot> {
try {
document = await this.postProcessor.process(document, metadata);
} catch (error) {
console.error(error);
return Result.fail(DocumentGenerationError.postProcess(error));
}
}

View File

@ -1,3 +1,4 @@
export * from "./documents";
export * from "./presenters";
export * from "./renderers";
export * from "./snapshot-builders";

View File

@ -0,0 +1,4 @@
export * from "./presenter";
export * from "./presenter.interface";
export * from "./presenter-registry";
export * from "./presenter-registry.interface";

View File

@ -1,6 +1,6 @@
import type { DTO } from "@erp/core/common";
import type { ISnapshotBuilder } from "./snapshot-builder.interface";
import type { IPresenter } from "./presenter.interface";
/**
* 🔑 Claves de proyección comunes para seleccionar presenters
@ -25,17 +25,17 @@ export interface IPresenterRegistry {
*/
getPresenter<TSource, F extends PresenterFormat = "DTO">(
key: Omit<PresenterKey, "format"> & { format?: F }
): ISnapshotBuilder<TSource, PresenterFormatOutputMap[F]>;
): IPresenter<TSource, PresenterFormatOutputMap[F]>;
/**
* Registra un mapper de dominio bajo una clave de proyección.
*/
registerPresenter<TSource, TOutput>(
key: PresenterKey,
presenter: ISnapshotBuilder<TSource, TOutput>
presenter: IPresenter<TSource, TOutput>
): this;
registerPresenters(
presenters: Array<{ key: PresenterKey; presenter: ISnapshotBuilder<unknown, unknown> }>
presenters: Array<{ key: PresenterKey; presenter: IPresenter<unknown, unknown> }>
): this;
}

View File

@ -1,10 +1,10 @@
import { ApplicationError } from "@repo/rdx-ddd";
import type { IPresenter } from "./presenter.interface";
import type { IPresenterRegistry, PresenterKey } from "./presenter-registry.interface";
import type { ISnapshotBuilder } from "./snapshot-builder.interface";
export class InMemoryPresenterRegistry implements IPresenterRegistry {
private registry: Map<string, ISnapshotBuilder<any, any>> = new Map();
private registry: Map<string, IPresenter<any, any>> = new Map();
private _normalizeKey(key: PresenterKey): PresenterKey {
return {
@ -29,13 +29,13 @@ export class InMemoryPresenterRegistry implements IPresenterRegistry {
private _registerPresenter<TSource, TOutput>(
key: PresenterKey,
presenter: ISnapshotBuilder<TSource, TOutput>
presenter: IPresenter<TSource, TOutput>
): void {
const exactKey = this._buildKey(key);
this.registry.set(exactKey, presenter);
}
getPresenter<TSource, TOutput>(key: PresenterKey): ISnapshotBuilder<TSource, TOutput> {
getPresenter<TSource, TOutput>(key: PresenterKey): IPresenter<TSource, TOutput> {
const exactKey = this._buildKey(key);
// 1) Intentar clave exacta
@ -76,7 +76,7 @@ export class InMemoryPresenterRegistry implements IPresenterRegistry {
registerPresenter<TSource, TOutput>(
key: PresenterKey,
presenter: ISnapshotBuilder<TSource, TOutput>
presenter: IPresenter<TSource, TOutput>
): this {
this._registerPresenter(key, presenter);
return this;
@ -85,7 +85,7 @@ export class InMemoryPresenterRegistry implements IPresenterRegistry {
* Registro en lote de presentadores.
*/
registerPresenters(
presenters: Array<{ key: PresenterKey; presenter: ISnapshotBuilder<any, any> }>
presenters: Array<{ key: PresenterKey; presenter: IPresenter<any, any> }>
): this {
for (const { key, presenter } of presenters) {
this._registerPresenter(key, presenter);

View File

@ -0,0 +1,7 @@
import type { DTO } from "../../../common/types";
export type IPresenterOutputParams = Record<string, unknown>;
export interface IPresenter<TSource, TOutput = DTO> {
toOutput(source: TSource, params?: IPresenterOutputParams): TOutput | Promise<TOutput>;
}

View File

@ -0,0 +1,11 @@
import type { IPresenter, IPresenterOutputParams } from "./presenter.interface";
import type { IPresenterRegistry } from "./presenter-registry.interface";
export abstract class Presenter<TSource = unknown, TOutput = unknown>
implements IPresenter<TSource, TOutput>
{
constructor(protected presenterRegistry: IPresenterRegistry) {
//
}
abstract toOutput(source: TSource, params?: IPresenterOutputParams): TOutput;
}

View File

@ -1,4 +1,2 @@
export * from "./presenter-registry";
export * from "./presenter-registry.interface";
export * from "./snapshot-builder";
export * from "./snapshot-builder.interface";

View File

@ -1,4 +1,5 @@
import type { IPresenterRegistry } from "./presenter-registry.interface";
import type { IPresenterRegistry } from "../presenters";
import type { ISnapshotBuilder, ISnapshotBuilderParams } from "./snapshot-builder.interface";
export abstract class SnapshotBuilder<TSource = unknown, TOutput = unknown>

View File

@ -22,9 +22,14 @@ export const buildCoreDocumentsDI = (env: NodeJS.ProcessEnv) => {
const signingContextResolver = new EnvCompanySigningContextResolver(env);
const signingService = new RestDocumentSigningService({
signUrl: String(env.SIGNING_BASE_URL),
timeoutMs: env.SIGNING_TIMEOUT_MS ? Number.parseInt(env.SIGNING_TIMEOUT_MS, 10) : 15_000,
maxRetries: env.SIGNING_MAX_RETRIES ? Number.parseInt(env.SIGNING_MAX_RETRIES, 10) : 2,
signUrl: String(env.SIGNING_SERVICE_URL),
method: String(env.SIGNING_SERVICE_METHOD),
timeoutMs: env.SIGNING_SERVICE_TIMEOUT_MS
? Number.parseInt(env.SIGNING_SERVICE_TIMEOUT_MS, 10)
: 15_000,
maxRetries: env.SIGNING_SERVICE_MAX_RETRIES
? Number.parseInt(env.SIGNING_SERVICE_MAX_RETRIES, 10)
: 2,
});
// Cache para documentos firmados

View File

@ -52,20 +52,15 @@ export class EnvCompanySigningContextResolver implements ISigningContextResolver
}
}
async resolveForCompany(companyId: string): Promise<ICompanyCertificateContext | null> {
/**
* En esta implementación:
* - companyId === companySlug
* - No hay lookup adicional
*/
const record = this.records[companyId];
async resolveForCompany(companySlug: string): Promise<ICompanyCertificateContext | null> {
const record = this.records[companySlug];
if (!record) {
return null;
}
return {
companySlug: companyId,
companySlug,
certificateSecretName: record.certificateSecretName,
certificatePasswordSecretName: record.certificatePasswordSecretName,
};

View File

@ -1,7 +1,7 @@
import { spawn } from "node:child_process";
import fs from "node:fs/promises";
import { Result, buildSafePath } from "@repo/rdx-utils";
import { Result } from "@repo/rdx-utils";
import { FastReportExecutionError } from "./fastreport-errors";
@ -18,7 +18,7 @@ export type FastReportProcessRunnerArgs = {
templatePath: string; // Path to FRX template (required)
data: string; // JSON data as string
format: "PDF" | "HTML";
workdir: string; // Directorio de trabajo temporal
output: string; // Directorio de trabajo temporal
};
export class FastReportProcessRunner {
@ -26,40 +26,40 @@ export class FastReportProcessRunner {
executablePath: string,
executableArgs: FastReportProcessRunnerArgs
): Promise<Result<Buffer | string, FastReportExecutionError>> {
const { templatePath, data, format, workdir } = executableArgs;
const { templatePath, data, format, output } = executableArgs;
// Guardar datos de entrada en JSON
const dataPath = buildSafePath({ basePath: workdir, segments: [], filename: "data.json" });
//const dataPath = buildSafePath({ basePath: workdir, segments: [], filename: "data.json" });
// Path de output según formato y con
const outputPath = buildSafePath({
/*const outputPath = buildSafePath({
basePath: workdir,
segments: [],
filename: format === "PDF" ? "output.pdf" : "output.html",
});
await fs.writeFile(dataPath, data, "utf-8");
await fs.writeFile(dataPath, data, "utf-8");*/
const args = this.buildArgs({
templatePath,
dataPath,
outputPath,
data,
output,
format,
});
return this.executeProcess(executablePath, args, outputPath, executableArgs.format);
return this.executeProcess(executablePath, args, output, executableArgs.format);
}
private buildArgs(params: {
templatePath: string;
dataPath: string;
outputPath: string;
data: string;
output: string;
format: "PDF" | "HTML";
}): string[] {
return [
`--template=${params.templatePath}`,
`--data=${params.dataPath}`,
`--output=${params.outputPath}`,
`--data=${params.data}`,
`--output=${params.output}`,
`--format=${params.format}`,
];
}

View File

@ -38,7 +38,7 @@ export class FastReportRenderer extends Renderer<unknown, FastReportRenderOutput
await this.processRunner.run(executablePath, {
templatePath: options.templatePath,
data: inputPath,
workdir: outputPath,
output: outputPath,
format: options.format,
});

View File

@ -31,6 +31,7 @@ export class RestDocumentSigningService implements IDocumentSigningService {
async sign(payload: Buffer, context: ICompanyCertificateContext): Promise<Buffer> {
if (!this.circuitBreaker.canExecute()) {
console.error(`Document signing service unavailable (${this.signUrl})`);
throw new Error("Document signing service unavailable (circuit open)");
}

View File

@ -169,11 +169,13 @@ const defaultRules: ReadonlyArray<ErrorToApiRule> = [
matches: (e) => isDocumentGenerationError(e),
build: (e) => {
const error = e as DocumentGenerationError;
const cause = error.cause as Error;
console.error(cause.message, cause);
const title =
error.documentErrorType === "METADATA"
? "Invalid document render error"
: "Unexcepted document render error";
return new InternalApiError(error.message, title);
return new InternalApiError(cause.message, title);
},
},
{

View File

@ -1,6 +1,6 @@
{
"name": "@erp/customer-invoices",
"version": "0.1.7",
"version": "0.3.6",
"private": true,
"type": "module",
"sideEffects": false,

View File

@ -4,6 +4,7 @@ import type { IssuedInvoiceReportTaxSnapshot } from "./issued-invoice-report-tax
export interface IssuedInvoiceReportSnapshot {
id: string;
company_id: string;
company_slug: string;
invoice_number: string;
series: string;
status: string;

View File

@ -1,25 +0,0 @@
import type { IDocumentSigningService } from "../../services";
import {
type IIssuedInvoiceDocumentRenderer,
IssuedInvoiceDocumentReportService,
} from "../services";
export const buildIssuedInvoiceDocumentService = (
renderer: IIssuedInvoiceDocumentRenderer,
signingService: IDocumentSigningService,
certificateResolver: ICompanyCertificateResolver
) => {
const { fastReport } = renderers;
const issuedInvoiceReportRenderer = new IssuedInvoiceFastReportRenderer(
fastReport.executableResolver,
fastReport.processRunner,
fastReport.templateResolver,
fastReport.reportStorage
);
const issuedInvoiceDocumentRenderer = new IssuedInvoiceDocumentRenderer(
issuedInvoiceReportRenderer
);
return new IssuedInvoiceDocumentReportService(renderer, signingService, certificateResolver);
};

View File

@ -1,4 +1,3 @@
export * from "./documents.di";
export * from "./finder.di";
export * from "./snapshot-builders.di";
export * from "./use-cases.di";

View File

@ -25,6 +25,7 @@ export class IssuedInvoiceDocumentMetadataFactory
documentType: "issued-invoice",
documentId: snapshot.id,
companyId: snapshot.company_id,
companySlug: snapshot.company_slug,
format: "PDF",
languageCode: snapshot.language_code ?? "es",
filename: this.buildFilename(snapshot),

View File

@ -37,6 +37,7 @@ export class IssuedInvoiceReportSnapshotBuilder implements IIssuedInvoiceReportS
return {
id: snapshot.id,
company_id: snapshot.company_id,
company_slug: "rodax",
invoice_number: snapshot.invoice_number,
series: snapshot.series,
status: snapshot.status,

View File

@ -1,9 +1,9 @@
import type {
ICertificateResolver,
IDocument,
IDocumentMetadata,
IDocumentPostProcessor,
IDocumentSigningService,
ISigningContextResolver,
} from "@erp/core/api";
/**
@ -15,18 +15,21 @@ import type {
*/
export class DigitalSignaturePostProcessor implements IDocumentPostProcessor {
constructor(
private readonly certificateResolver: ICertificateResolver,
private readonly certificateResolver: ISigningContextResolver,
private readonly signingService: IDocumentSigningService
) {}
async process(document: IDocument, metadata: IDocumentMetadata): Promise<IDocument> {
// Validación defensiva mínima
if (document.mimeType !== "application/pdf") {
throw new Error("DigitalSignaturePostProcessor can only sign PDF documents");
throw new Error("[DigitalSignaturePostProcessor] can only sign PDF documents");
}
// 1. Resolver certificado de la empresa
const certificate = await this.certificateResolver.resolveForCompany(metadata.companyId);
const certificate = await this.certificateResolver.resolveForCompany(metadata.companySlug);
if (!certificate) {
throw new Error("[DigitalSignaturePostProcessor] Compny certificate is undefined");
}
// 2. Firmar payload
const signedPayload = await this.signingService.sign(document.payload, certificate);

View File

@ -41,15 +41,15 @@ export class ReportIssuedInvoiceController extends ExpressController {
});
return result.match(
({ data, filename }) => {
({ payload, filename }) => {
if (format === "PDF") {
return this.downloadPDF(data as Buffer<ArrayBuffer>, String(filename));
return this.downloadPDF(payload as Buffer<ArrayBuffer>, String(filename));
}
if (format === "HTML") {
return this.downloadHTML(data as string);
return this.downloadHTML(payload as unknown as string);
}
// JSON
return this.json(data);
return this.json(payload);
},
(err) => this.handleError(err)
);

View File

@ -1,6 +1,6 @@
{
"name": "@erp/customers",
"version": "0.1.7",
"version": "0.3.6",
"private": true,
"type": "module",
"sideEffects": false,

View File

@ -1,7 +1,8 @@
import { Presenter } from "@erp/core/api";
import { toEmptyString } from "@repo/rdx-ddd";
import { GetCustomerByIdResponseDTO } from "../../../../common/dto";
import { Customer } from "../../../domain";
import type { GetCustomerByIdResponseDTO } from "../../../../common/dto";
import type { Customer } from "../../../domain";
export class CustomerFullPresenter extends Presenter<Customer, GetCustomerByIdResponseDTO> {
toOutput(customer: Customer): GetCustomerByIdResponseDTO {

View File

@ -1,10 +1,11 @@
import { CriteriaDTO } from "@erp/core";
import type { CriteriaDTO } from "@erp/core";
import { Presenter } from "@erp/core/api";
import { Criteria } from "@repo/rdx-criteria/server";
import type { Criteria } from "@repo/rdx-criteria/server";
import { toEmptyString } from "@repo/rdx-ddd";
import { Collection } from "@repo/rdx-utils";
import { ListCustomersResponseDTO } from "../../../../common/dto";
import { CustomerListDTO } from "../../../infrastructure/mappers";
import type { Collection } from "@repo/rdx-utils";
import type { ListCustomersResponseDTO } from "../../../../common/dto";
import type { CustomerListDTO } from "../../../infrastructure/mappers";
export class ListCustomersPresenter extends Presenter {
protected _mapCustomer(customer: CustomerListDTO) {

View File

@ -4,15 +4,16 @@ import {
InMemoryPresenterRegistry,
SequelizeTransactionManager,
} from "@erp/core/api";
import {
CreateCustomerUseCase,
CustomerApplicationService,
CustomerFullPresenter,
GetCustomerUseCase,
ListCustomersPresenter,
ListCustomersUseCase,
UpdateCustomerUseCase,
} from "../application";
import { CustomerApplicationService } from "../application/customer-application.service";
import { CustomerFullPresenter, ListCustomersPresenter } from "../application/presenters";
import { CustomerDomainMapper, CustomerListMapper } from "./mappers";
import { CustomerRepository } from "./sequelize";

View File

@ -1,6 +1,6 @@
{
"name": "@erp/doc-numbering",
"version": "0.1.7",
"version": "0.3.6",
"private": true,
"type": "module",
"sideEffects": false,

View File

@ -1,6 +1,6 @@
{
"name": "@repo/rdx-criteria",
"version": "0.2.7",
"version": "0.3.6",
"private": true,
"type": "module",
"sideEffects": false,

View File

@ -1,6 +1,6 @@
{
"name": "@repo/rdx-ddd",
"version": "0.2.7",
"version": "0.3.6",
"private": true,
"type": "module",
"sideEffects": false,

View File

@ -1,6 +1,6 @@
{
"name": "@repo/rdx-logger",
"version": "0.2.7",
"version": "0.3.6",
"private": true,
"type": "module",
"sideEffects": false,

View File

@ -1,6 +1,6 @@
{
"name": "@repo/rdx-utils",
"version": "0.2.7",
"version": "0.3.6",
"private": true,
"type": "module",
"sideEffects": false,

View File

@ -66,7 +66,7 @@ services:
traefik.http.routers.factuges_rodax_phpmyadmin.middlewares: "factuges_rodax_phpmyadmin_strip"
# --- API (imagen versionada generada por build-api.sh) ---
# --- API ---
api:
image: ${API_IMAGE}
container_name: factuges_rodax_api
@ -76,18 +76,32 @@ services:
condition: service_healthy
environment:
NODE_ENV: production
COMPANY: rodax
PORT: ${SERVER_PORT:-3002}
DB_DIALECT: "mysql"
COMPANY_SLUG: ${COMPANY_SLUG}
FRONTEND_URL: ${FRONTEND_URL}
API_PORT: ${API_PORT}
DB_HOST: "db"
DB_PORT: ${DB_PORT}
DB_DIALECT: ${DB_DIALECT}
DB_NAME: ${DB_NAME}
DB_USER: ${DB_USER}
DB_PASS: ${DB_PASS}
FRONTEND_URL: ${FRONTEND_URL}
TEMPLATES_PATH: ${TEMPLATES_PATH}
FASTREPORT_BIN: ${FASTREPORT_BIN}
DOCUMENTS_PATH: ${DOCUMENTS_PATH}
FASTREPORT_BIN: ${FASTREPORT_BIN}
SIGNED_DOCUMENTS_PATH: ${SIGNED_DOCUMENTS_PATH}
SIGNED_DOCUMENTS_CACHE_PATH: ${SIGNED_DOCUMENTS_CACHE_PATH}
SIGNING_SERVICE_URL: ${SIGNING_SERVICE_URL}
SIGNING_SERVICE_METHOD: ${SIGNING_SERVICE_METHOD}
SIGNING_SERVICE_TIMEOUT_MS: ${SIGNING_SERVICE_TIMEOUT_MS}
SIGNING_SERVICE_MAX_RETRIES: ${SIGNING_SERVICE_MAX_RETRIES}
COMPANY_CERTIFICATES_JSON: ${COMPANY_CERTIFICATES_JSON}
volumes:
- ./volumes/templates:/shared/templates:ro
- ./volumes/certificates:/shared/certificates:ro

View File

@ -1,15 +1,18 @@
# Identidad de la compañía
COMPANY=rodax
COMPANY_SLUG=rodax
# Dominios
DOMAIN=factuges.rodax-software.local
# MariaDB
DB_ROOT_PASS=verysecret
DB_HOST=db
DB_PORT=3306
DB_DIALECT=mysql
DB_NAME=rodax_db
DB_USER=rodax_usr
DB_PASS=supersecret
DB_NAME=rodax_db
DB_PORT=3306
DB_ROOT_PASS=verysecret
# API
API_PORT=3002
@ -23,6 +26,22 @@ TEMPLATES_PATH=/shared/templates
FASTREPORT_BIN=/repo/tools/FastReportCliGenerator
DOCUMENTS_PATH=/shared/documents
# Firma de documentos
SIGNED_DOCUMENTS_PATH=/shared/documents
SIGNED_DOCUMENTS_CACHE_PATH=/shared/cache
SIGNING_SERVICE_URL=http://signing-service:8000/documents/sign
SIGNING_SERVICE_METHOD=POST
SIGNING_SERVICE_TIMEOUT_MS=15_000
SIGNING_SERVICE_MAX_RETRIES=2
COMPANY_CERTIFICATES_JSON='{
"rodax": {
"certificateId": "no se que poner aqui",
"certificateSecretName": "certificate_secret_name",
"certificatePasswordSecretName": "certificate_password_secret_name"
}
}'
# SYNC
ENV = development