# GapCode Agent Instructions # AGENTS.md Operational guide for AI/coding agents working in `consumer_api`. --- # ⚡ RTK LOW-TOKEN EXECUTION POLICY (MANDATORY) This repository uses **RTK (Rust Token Killer)**. All shell interactions MUST prefer RTK wrappers to reduce token usage. If an RTK equivalent exists, **never use the raw command**. This repository can be large; uncontrolled shell output will quickly exhaust model context. --- # ✅ COMMAND REWRITE RULES (STRICT) Always rewrite commands using RTK: git status → rtk git status git diff → rtk git diff git log → rtk git log ls → rtk ls tree → rtk ls cat → rtk read grep → rtk grep rg → rtk grep find → rtk find Never run: - raw git commands for inspection - raw cat - raw grep - raw ls - raw tree --- # 📂 CODE NAVIGATION WORKFLOW (MANDATORY) When working in this repository follow this order: 1️⃣ Discover structure rtk ls 2️⃣ Search before opening files rtk grep 3️⃣ Read only the necessary files rtk read 4️⃣ For large files (>300 lines) rtk read -l aggressive 5️⃣ For quick understanding rtk smart Never open many files blindly. Never read entire modules without searching first. --- # 🧠 DIFF INSPECTION RULES For reviewing repository changes: Use: rtk git diff For large diffs: rtk git diff -l aggressive Never run raw `git diff`. --- # 📁 FORBIDDEN PATHS Never inspect or read these directories unless explicitly required: node_modules/ dist/ build/ coverage/ .prisma/ prisma/migrations/ These folders produce extremely large outputs and waste tokens. --- # 📄 FILE READING POLICY Preferred: rtk read file.ts Large file: rtk read file.ts -l aggressive Quick overview: rtk smart file.ts Never use `cat` for source code inspection. --- # 🔎 SEARCH POLICY Always search before opening files. Use: rtk grep Avoid raw recursive searches. --- # 🎯 TOKEN SAFETY RULES - Never scan the entire repository. - Never dump full logs. - Never output entire large files. - Prefer targeted inspection. Token preservation is mandatory for this project. --- ## Scope - Applies to the whole repository. - Stack: NestJS + Prisma + TypeScript. ## Primary Goals - Deliver minimal, safe, and focused changes. - Preserve existing API behavior unless explicitly requested. - Keep Prisma schema/data operations forward-safe. ## Project Conventions - Keep module layering consistent: `controller -> service -> prisma/shared service`. - Reuse shared services for cross-module business logic (for example, sales invoice create flow). - Keep DTO validation at API boundaries; avoid unchecked `any` in new code. - Keep response shaping aligned with existing `ResponseMapper` usage. - Prefer explicit Prisma `select`/`include` to control payload shape. ## Sales Invoice / TSP Rules - `originalSend`, `correctionSend`, and `revoke` flows should be consistent and auditable. - For correction/revoke creation, prepare data from the related invoice when required. - Persist attempt records with clear status transitions (`QUEUED` -> final status). - Store request/response payloads for traceability. - Avoid changing fiscal/tax status semantics without explicit approval. ## Prisma and Migration Safety - Treat committed migrations as immutable history. - Prefer forward migrations; avoid destructive resets unless explicitly requested. - For data-affecting changes: - use transactions, - verify expected row scope, - keep logic idempotent where possible. ## Editing Principles - Do not modify unrelated files. - Do not revert user changes unless asked. - Keep functions cohesive; extract shared logic when duplication appears. - Remove debug leftovers (`console.log`, dead code) before finishing unless explicitly needed. ## Validation Checklist (before handoff) 1. Read target module/service/DTO end-to-end before edits. 2. Apply minimal patch with consistent naming. 3. Run typecheck: `pnpm -s tsc --noEmit`. 4. If behavior changed, run targeted checks/tests where possible. 5. Summarize changed files and behavior impact clearly. ## Useful Commands - Typecheck: `pnpm -s tsc --noEmit` - Migration status: `pnpm prisma migrate status` - Create migration: `pnpm prisma migrate dev --name ` - Deploy migrations: `pnpm prisma migrate deploy` ## Communication Style - Be concise and implementation-focused. - Call out assumptions/risk before risky steps. - Provide practical next actions after task completion. ## Do / Don't (Repo-Specific) ### Do - Do derive correction/revoke invoice creation data from `relatedInvoice` when the flow requires historical consistency. - Do keep TSP attempt lifecycle explicit (`QUEUED`, then update with provider result and timestamps). - Do use shared invoice-creation service instead of duplicating create logic across modules. - Do normalize numeric DB values (`Decimal`) with `Number(...)` before DTO/payload composition. - Do keep Prisma queries tight with `select`/`include` only for fields you actually use. ### Don't - Don't pass undefined/out-of-scope variables in TSP flows (common regressions: `invoice_id`, `attemptId`, `pos_id` mismatches). - Don't leave placeholder query blocks (for example empty `select: {}`) in production code. - Don't mix method semantics (`send` vs `originalSend`) across services without verifying signatures. - Don't leave debug logs (`console.log`) in critical invoice/tax paths unless explicitly requested. - Don't change invoice type semantics (`ORIGINAL`, `CORRECTION`, `REVOKE`) implicitly. ### Common Pitfalls To Recheck - Incorrect relation field names (`tax_id` on wrong model, missing relation selects). - Building payloads from the wrong invoice (must match the expected new/ref invoice in each flow). - Creating attempts without persisting request payload and final response payload. - Mismatch between DTO shapes and shared service input contracts. ## Thread Notes (May 2026) - Shared sale-invoice creation was introduced and must be injected/exported correctly in consuming modules (example failure: `UnknownDependenciesException` for `SharedSaleInvoiceCreateService`). - In `SalesInvoiceTspService.revoke`, prepare all creation/update data from `relatedInvoice` (no external `dataToUpdate` argument expected). - Prisma client is generated to `src/generated/prisma` via: - `provider = "prisma-client"` - `output = "../../src/generated/prisma"` - `moduleFormat = "cjs"` - Docker/runtime must include generated Prisma artifacts and `@prisma/client` runtime; missing `@prisma/client/runtime/client` indicates build/copy/install mismatch. - Seeder commands that use `tsx` require dev dependencies/runtime tools; if running in slim production container, use a dedicated seed target/container or run seed from build/dev image. - `pnpm` invocation in containers should use executable form (`pnpm ...`), not `node /app/pnpm`. - Added SQL/Prisma error normalization utility: `src/common/utils/prisma-error.util.ts`; prefer mapping duplicate/constraint DB errors to domain-friendly messages. - Partner-module list endpoints were standardized toward `ResponseMapper.paginate` where pagination response contract is expected. - For heavy license provisioning (100+), request path should not synchronously insert all licenses; queue/background + batching is required. ## Migration Drift Playbook (Prisma/MySQL) - If Prisma reports `modified after applied`, never edit an already-applied migration in-place for shared environments; create a new forward migration instead. - If migration history and DB drift mismatch: 1. Verify local migration folders are complete and ordered. 2. Check `_prisma_migrations` for missing/applied names. 3. Use `prisma migrate resolve` only to reconcile history state, then apply a forward fix migration. - Duplicate FK error seen in this repo: `sales_invoices_ref_id_fkey` (MySQL 1826). Recheck migration SQL for repeated `ADD CONSTRAINT` statements before rerun. - Drift that repeatedly showed in this project: missing FK/unique on `sale_invoice_tsp_attempts.invoice_id`. Validate both schema and migration SQL produce the same final state. - `prisma migrate status` may show up-to-date while `migrate dev` still detects drift (shadow DB/application history issue); treat `migrate dev` output as source of truth for fixing local history. ## Redis Cache Conventions (May 2026) - Use `RedisKeyMaker` in `src/common/utils/redis-key-maker.util.ts` for all cache keys and wildcard patterns; do not inline key strings in services. - Keep invalidation domain-based (for example `src/modules/admin/guilds/cache/*`, `src/modules/admin/partners/cache/*`, `src/modules/pos/cache/*`) and avoid duplicating delete logic across modules. - For list APIs that are expensive or frequently read, prefer read-through cache with TTL and invalidation on every related write path. - For entity endpoints, use list + detail split: - list key(s): invalidated broadly on writes, - detail key(s): invalidated per entity id. - Partner domain rules: - Shared partner cache namespace is `partners:*` (not admin-prefixed) because writes occur in both `admin/partners` and `partners` modules. - Use shared invalidation service `src/modules/partners/cache/partners-cache-invalidation.service.ts` from both admin and partner write paths. - Invalidate `partners:list` and `partners:{id}:detail` on partner create/update/delete and license-affecting writes. - Invalidate partner license caches (activated-licenses list, charge-transactions list/detail) via the shared invalidation service. - POS goods rules: - Cache key shape is BA + guild scoped (`pos:ba:{businessActivityId}:guild:{guildId}:goods:list`) because results combine guild-default and BA-owned goods. - Invalidate POS goods cache by guild when admin guild goods/category/sku changes. - Invalidate POS goods cache by business activity when consumer BA goods create/update/delete. - Consumer/Partner hierarchy rules: - Consumer profile cache key: `consumers:{consumerId}:info`. - Partner-consumer profile cache key: `partners:{partnerId}:consumers:{consumerId}:info`. - On partner-consumer single read, write both keys when practical to share warm cache across modules. - On consumer info update or partner-consumer update, invalidate both consumer and partner-consumer profile keys. - For business activities, invalidate both list and detail layers; child updates may invalidate parent single cache when parent aggregates depend on child state. - Wildcard invalidation implementation: - Use `RedisService.deleteByPattern` / `RedisService.deleteByPatterns` for all pattern deletes. - Do not implement ad-hoc scan/delete loops inside domain services. - Pattern deletion uses `SCAN` + pipelined `DEL`; multi-pattern deletes run in parallel.