diff --git a/08 - Operations/Handover - Request Network Intent Duplicate Key Bug.md b/08 - Operations/Handover - Request Network Intent Duplicate Key Bug.md index 5bdfe00..5ca5080 100644 --- a/08 - Operations/Handover - Request Network Intent Duplicate Key Bug.md +++ b/08 - Operations/Handover - Request Network Intent Duplicate Key Bug.md @@ -72,7 +72,9 @@ Exact payload that reproduces is captured in the original ticket (`amount: 12`, ## 5. Solutions -Three layered fixes. **(c) is implemented as of 2026-05-27** in `backend/src/services/payment/requestNetwork/{requestNetworkPayInService,requestNetworkRoutes}.ts`. Apply (a) once to clear the existing stuck doc. (b) is a frontend hygiene improvement worth keeping on the backlog but is no longer required to unblock checkouts. +Three layered fixes. **(c) is implemented as of 2026-05-27** in `backend/src/services/payment/requestNetwork/{requestNetworkPayInService,requestNetworkRoutes}.ts` (`nick/backend@bdbcc32`). Apply (a) once to clear the existing stuck doc. (b) is a frontend hygiene improvement worth keeping on the backlog but is no longer required to unblock checkouts. + +> **Secondary fix shipped at the same time (`nick/backend@40750d3`, 2.6.20).** Once the idempotency check passed, every call was failing with `Request Network secure payment creation failed: HTTP 400` because the adapter was sending a flat payload to `/v2/secure-payments`, while the v2 endpoint requires `{ reference, requests:[{ destinationId, amount, metadata? }], redirectUrl?, callbackUrl? }`. The translation now happens inside `createSecurePaymentRequest` (the rich internal payload object is still passed to the response mapper for `paymentCurrency`/`network` context). Verified end-to-end with `backend/scripts/smoke/rn-payload-shape.mjs` against the real RN API: HTTP 201 with `securePaymentUrl` + `requestIds[]`. ### a) Hot unblock — clear the stale pending document diff --git a/RTK.md b/RTK.md new file mode 100644 index 0000000..fa644a1 --- /dev/null +++ b/RTK.md @@ -0,0 +1,45 @@ +# RTK + +Repository rules agents must follow for Amanat escrow work. + +## Version and Build Numbers + +- **Every build of `frontend/` or `backend/` must bump the patch component (`Z` in `X.Y.Z`) by one.** Container images on `git.manko.yoga` are tagged from `package.json` version — a build with an unchanged version overwrites the previous image and erases history. Patch bump on every build, no exceptions. + - Bump together so frontend and backend stay aligned (e.g. both go `2.6.18 → 2.6.19`). + - Bumping `Y` (minor) or `X` (major) is only for explicit milestone releases the user requests; never as a side-effect of an ordinary build. +- For any product or code change that affects `frontend/` or `backend/`, bump both versions together before final response in: + - `frontend/package.json` + - `frontend/package-lock.json` + - tracked frontend env files that set `NEXT_PUBLIC_APP_VERSION` + - `backend/package.json` + - `backend/package-lock.json` +- Backend runtime/version reporting should read from `backend/package.json`, not a hardcoded fallback. +- Keep frontend and backend on the same version/build number unless the user explicitly asks otherwise. +- Do not bump versions for docs-only changes unless the user asks for a release/build number. +- Mention the resulting frontend and backend version numbers in the final response. + +## Pre-Deploy CLI Verification + +- For any backend or frontend change, run the focused CLI smoke test for the touched area **before pushing a commit that would trigger a build**. The image tracker patch-bumps per build, so a failed build still consumes a version slot. +- Smoke-test scripts live under `backend/scripts/smoke/*.sh` (and the equivalent frontend dir). `scripts/test-*` is in `.gitignore`, so put committed smoke tests in `scripts/smoke/`. They must accept `BASE_URL` so the same script can target a local backend, dev, or production. +- Confirm the script passes against a local backend (or, where local isn't feasible, an explicitly named target) before pushing. After the deploy completes, re-run the same script against the deployed URL to confirm production behavior matches. +- If no smoke-test script exists for the touched area, create one as part of the change. + +## CI Notification Safety + +- Telegram CI notifications (`appleboy/drone-telegram` in `.woodpecker/*.yml`) must HTML-escape commit messages and strip git trailers (`Co-Authored-By:`, `Signed-off-by:`, `Reviewed-by:`, `Reported-by:`) before sending. Unescaped `` trailers cause "Bad Request: can't parse entities" 400 errors from the Telegram API. +- Use a `compose-notify` shell step that writes the rendered message into `.tgmsg`, then have the telegram plugin send `message_file: .tgmsg`. Do not interpolate `{{commit.message}}` directly into an `html`-formatted message body. +- Woodpecker eats `${VAR}` in command strings — always use `$VAR` (or `$$VAR` to escape) in pipeline command shells. + +## Telegram Authentication + +- `POST /api/auth/telegram` must allow Telegram Mini App retries with the same signed `initData`; Telegram may reuse launch data across reloads, retries, and duplicate client calls. +- Do not add one-time replay rejection to first-class Telegram login. Use signature verification, `auth_date` freshness, bot rejection, blocked-link checks, and rate limiting for this login path. +- Keep replay/deduplication checks scoped to routes where the payload is actually a one-time operation, such as webhook update handling or explicit Mini App session creation. +- Preserve or add regression tests whenever Telegram auth behavior changes. + +## Verification + +- Run focused tests for the changed area and a typecheck/build when practical. +- If Redis, email, or other optional infrastructure is unavailable during tests, successful auth paths should fail open only where the production code already treats that dependency as non-critical, and the final response should mention any noisy but non-failing warnings. +- Before final response, report the important verification commands and whether they passed.