diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..3238dc0 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,56 @@ +# maestro — development policy + +Maestro is the NestJS BFF between the Angular frontend and the gRPC services +(pi-factory, in-factory) / platform-api. These rules come from code review and +apply to every change; the same rules live in pi-factory and in-factory. + +## Layering +- Controllers are thin: decorators, body validation, one call into a service, + response shape. Orchestration (multi-step calls, rollbacks, platform-api or + gRPC round-trips) lives in a `*.service.ts`. Example: + `platform-api/pipeline-tables.service.ts`. +- One platform-api route per operation. If the platform already dispatches by + pipeline type (batch vs CDC), do not branch on the type here — call the + route that dispatches (e.g. `DELETE /pipeline/{id}/jobs` for table removal, + never `DELETE /jobs/{id}` from maestro). + +## Types +- No `any` / `as any`. gRPC calls take the protospack request type exactly + (`AddCdcTableRequest`, `MarkTableDeletedRequest`, ...); DTOs and interfaces + are explicit classes/interfaces. Use `Record` or `unknown` (with + narrowing) when a shape is genuinely open — never `any`. +- Protospack payloads are built in one mapper per entity (e.g. + `inputs/cdc-table.mapper.ts`), so a field that mirrors another + (`CdcTable.name` == `table_name`) is derived in exactly one place. + +## Pipeline type +- Decide CDC vs batch with `src/utils/cdc.ts` (`isCdcPlugin`, `isCdcJob`, + `isCdcPipeline`), never with inline `plugin.endsWith('_cdc')`, `!!x`, or + the absence of some other data (e.g. "no run history ⇒ editable"). +- The platform-api stamps `job.input.connector === 'cdc'` on CDC jobs; that + is the authoritative discriminator once a pipeline exists. + +## Dependencies +- `@dadosfera/protospack-v2` is consumed from CodeArtifact, pinned to an exact + version (`npm i @dadosfera/protospack-v2@ --save-exact`). A `file:` + / tarball reference is for local development only and must never be + committed. Note: `^3.40.0-beta.N` resolves to the stable `3.40.0` — + prereleases must be pinned exactly. + +## Commits and releases +- Deploys are cut by semantic-release with the eslint preset: the commit + title MUST start with `FIX:` (patch), `UPDATE:` or `FEAT:` (minor). A + lowercase `feat(scope): ...` merges without producing a version, so the + code never reaches stg/prd. +- Pushing to `beta` deploys stg; `main` deploys prd. + +## Tests +- Every service method with a rollback path has a spec covering the + happy path, the platform failure (rollback fires) and a rollback failure + (does not mask the original error). Run `npx jest ` for a folder, + `npx tsc --noEmit -p tsconfig.json` for types. +- Several gRPC client configs read `process.env` at import time, so the full + suite needs the service URLs set (any `0.0.0.0:` value works): + `DUC_URL=0.0.0.0:50051 INFACTORY_URL=0.0.0.0:50052 PIFACTORY_URL=0.0.0.0:50053 npx jest`. + A `Cannot read properties of undefined (reading 'startsWith')` at import is + this, not a broken test.