docs: complete code-reality alignment for remaining docs + reconcile issue set

Remaining docs updated to match code (the docs that the first pass had not covered):
- Flows: Chat, Referral, Rating, Registration, Google OAuth, Negotiation, Payout,
  Trezor Safekeeping — corrected endpoints, socket events, status enums, auth gaps
- API Reference: User API, Trezor API — admin route prefix/verb/status corrections,
  added undocumented endpoints (ton-proof challenge, profile email verify,
  GET /trezor/account, POST /trezor/verify-operation)
- Data Models: Chat, Notification, Payment, PointTransaction, User — corrected
  enums (PaymentProvider, escrowState, PointTransaction.type, User.status),
  90-day notification TTL, soft-delete semantics, wallet fields

Trezor "zero frontend" finding (audit C31/C32) corrected as STALE:
- Verified current code HAS a full frontend Trezor implementation (admin/trezor
  page, TrezorSettingsView, trezorConnector via @trezor/connect-web,
  TrezorSignDialog, actions/trezor.ts building the {message,signature} object)
- Fixed Trezor Safekeeping Flow doc (removed false "no frontend" warnings)
- Reclassified ISSUE-012 as invalid/superseded with explanation

Issue set reconciled to a single canonical numbering (ISSUE-001..054):
- Adopted the comprehensive 51-issue set (long-slug, fully indexed)
- Removed 35 superseded short-slug duplicates from the first pass
- Removed a duplicate ISSUE-046 file
- Added 3 issues the 51-set lacked: ISSUE-052 (completed-not-counted-in-stats),
  ISSUE-053 (axios 401-only interceptor), ISSUE-054 (rate limiter counts all attempts)
- Regenerated Issues Index: 53 open (14 critical, 39 major) + 1 invalid

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-05-29 15:15:02 +04:00
parent 9698ec5809
commit 7a616744f4
118 changed files with 2833 additions and 1788 deletions

View File

@@ -1,50 +0,0 @@
---
issue: "001"
title: "PATCH /api/disputes/:id/status has no role guard — privilege escalation"
severity: critical
domain: dispute
labels: [security, backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 PATCH /api/disputes/:id/status has no role guard — privilege escalation
**Severity:** critical
**Domain:** dispute
**Labels:** security, backend, bug
## Description
`PATCH /api/disputes/:id/status` is mounted with only `authenticateToken` middleware — no `authorizeRoles('admin')` guard. Any authenticated buyer or seller who knows a dispute `_id` can change that dispute's status to `resolved`, `closed`, or any other value including states that release funds or trigger bans.
## Current Behavior
Any authenticated user (buyer or seller) can call:
```
PATCH /api/disputes/{disputeId}/status
{ "status": "resolved" }
```
and receive a 200 response. The dispute status is updated in MongoDB.
## Expected Behavior
Only users with `role: admin` should be permitted to change a dispute's status. Non-admin tokens should receive `403 Forbidden`.
## Reproduction Steps
1. Log in as a buyer or seller, obtain a JWT.
2. Find or create a dispute `_id`.
3. `PATCH /api/disputes/{id}/status` with `{ "status": "resolved" }` and the buyer/seller Bearer token.
4. Observe 200 and the status change in the DB.
## Affected Files
- `backend/src/routes/disputeRoutes.ts` — router missing `authorizeRoles('admin')` before `updateStatus` handler
- `backend/src/controllers/disputeController.ts``updateStatus` method
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding C16
- Related: [[ISSUE-002-dispute-resolve-no-role-guard]]

View File

@@ -0,0 +1,37 @@
---
issue: 001
title: "PATCH /api/disputes/:id/status and POST /api/disputes/:id/resolve have no role guard — privilege escalation"
severity: critical
domain: Dispute
labels: [security, bug, backend, privilege-escalation]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 PATCH /api/disputes/:id/status and POST /api/disputes/:id/resolve have no role guard — privilege escalation
**Severity:** critical
**Domain:** Dispute
**Labels:** security, bug, backend, privilege-escalation
## Description
Any authenticated buyer or seller can change dispute status to 'resolved', 'closed', or 'rejected', and can post a dispute resolution including action=ban_seller. Neither the dashboard updateStatus controller nor the resolveDispute controller call authorizeRoles('admin'). Only authenticateToken is applied on the router.
## Current Behavior
Any authenticated user with the dispute ID can call PATCH /api/disputes/:id/status or POST /api/disputes/:id/resolve and receive 200 with the mutation applied.
## Expected Behavior
Both endpoints should return 403 for non-admin users. authorizeRoles('admin') middleware should be applied at the route level.
## Affected Files
- `backend/src/routes/disputeRoutes.ts`
- `backend/src/controllers/disputeController.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,45 +0,0 @@
---
issue: "002"
title: "POST /api/disputes/:id/resolve has no role guard — any user can resolve disputes and ban sellers"
severity: critical
domain: dispute
labels: [security, backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 POST /api/disputes/:id/resolve has no role guard — any user can resolve disputes and ban sellers
**Severity:** critical
**Domain:** dispute
**Labels:** security, backend, bug
## Description
The dashboard dispute router's `POST /api/disputes/:id/resolve` handler applies only `authenticateToken`. No `authorizeRoles('admin')` guard exists. Any authenticated user can post any resolution action including `action: 'ban_seller'`, `action: 'refund'`, or `action: 'no_action'`, bypassing all admin authority.
Note: the *releaseHold* router's `POST /api/disputes/:purchaseRequestId/resolve` correctly uses `authorizeRoles('admin')`, but the dashboard router does not.
## Current Behavior
A buyer or seller can call:
```
POST /api/disputes/{disputeId}/resolve
{ "action": "ban_seller", "notes": "malicious" }
```
The resolution is persisted with a 200 response.
## Expected Behavior
`POST /api/disputes/:id/resolve` must be protected by `authorizeRoles('admin')`. Non-admin tokens should receive `403`.
## Affected Files
- `backend/src/routes/disputeRoutes.ts` (dashboard router, mounted at `/api/disputes` first)
- `backend/src/controllers/disputeController.ts``resolveDispute` method
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding C17
- Related: [[ISSUE-001-dispute-status-no-role-guard]], [[ISSUE-003-dispute-route-shadowing]]

View File

@@ -0,0 +1,37 @@
---
issue: 002
title: "POST /api/disputes/:id/assign has no role guard — any user can self-assign as admin"
severity: critical
domain: Dispute
labels: [security, bug, backend, privilege-escalation]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 POST /api/disputes/:id/assign has no role guard — any user can self-assign as admin
**Severity:** critical
**Domain:** Dispute
**Labels:** security, bug, backend, privilege-escalation
## Description
The POST /api/disputes/:id/assign endpoint registers only authenticateToken. Any authenticated user can assign themselves or anyone else as the admin handler for a dispute. The admin check is absent at both the middleware and controller level.
## Current Behavior
Any authenticated buyer or seller can call POST /api/disputes/:id/assign and become the assigned admin for the dispute.
## Expected Behavior
Return 403 for non-admin tokens. Apply authorizeRoles('admin') at the route level.
## Affected Files
- `backend/src/routes/disputeRoutes.ts`
- `backend/src/controllers/disputeController.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,41 +0,0 @@
---
issue: "003"
title: "Route shadowing: two dispute routers mounted at /api/disputes cause non-deterministic handler dispatch"
severity: critical
domain: dispute
labels: [backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 Route shadowing: two dispute routers mounted at /api/disputes cause non-deterministic handler dispatch
**Severity:** critical
**Domain:** dispute
**Labels:** backend, bug
## Description
In `backend/src/app.ts`, two separate dispute routers are mounted on the same path `/api/disputes`:
- Line ~521: `dashboardDisputeRoutes` (first — unguarded `POST /:id/resolve`, `PATCH /:id/status`)
- Line ~585: `releaseHold disputeRoutes` (second — admin-guarded `POST /:purchaseRequestId/resolve`, also `GET /:purchaseRequestId/status`)
Express evaluates in registration order. A `POST /api/disputes/{purchaseRequestId}/resolve` request will match the **dashboard router's** `POST /:id/resolve` handler first (since `:id` and `:purchaseRequestId` are identical route patterns). This executes the unguarded Dispute CRUD resolve instead of the admin-guarded escrow release-hold logic.
## Current Behavior
`POST /api/disputes/{purchaseRequestId}/resolve` executes the dashboard `resolveDispute` controller (updates the Dispute document only, no role guard) rather than the intended `releaseHold` handler (admin-only, clears escrow).
## Expected Behavior
The escrow-release resolve handler should be reachable at a distinct, unambiguous path (e.g., `/api/disputes/hold/:purchaseRequestId/resolve` or mounted at a different prefix).
## Affected Files
- `backend/src/app.ts` — two `app.use('/api/disputes', ...)` mount points
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding C18
- Related: [[ISSUE-002-dispute-resolve-no-role-guard]]

View File

@@ -0,0 +1,41 @@
---
issue: 003
title: "Route shadowing: POST /api/disputes/:purchaseRequestId/resolve matches dashboard router first and executes wrong handler"
severity: critical
domain: Dispute
labels: [bug, backend, critical, escrow]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 Route shadowing: POST /api/disputes/:purchaseRequestId/resolve matches dashboard router first and executes wrong handler
**Severity:** critical
**Domain:** Dispute
**Labels:** bug, backend, critical, escrow
## Description
Both the dashboard disputeRoutes and the releaseHold disputeRoutes are mounted at /api/disputes in app.ts. The dashboard router is mounted first (line 521). A POST /api/disputes/{purchaseRequestId}/resolve with a valid purchaseRequestId will match the dashboard router's POST /:id/resolve (Dispute CRUD resolve) before reaching the releaseHold router's escrow-unblocking resolve. The escrow hold is never cleared.
## Current Behavior
The dashboard router intercepts the request and executes Dispute model CRUD resolve only. Escrow hold is not cleared. Outcome is non-deterministic depending on whether the ID matches a Dispute _id.
## Expected Behavior
POST /api/disputes/:purchaseRequestId/resolve should reach the releaseHold handler and clear the escrow hold. Route registration order must be corrected or paths made unambiguous.
## Reproduction Steps
POST /api/disputes/{validPurchaseRequestId}/resolve with admin token — observe that escrow hold is NOT released, only the Dispute document is updated.
## Affected Files
- `backend/src/app.ts`
- `backend/src/routes/disputeRoutes.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,46 +0,0 @@
---
issue: "004"
title: "fetch-tx, auto-fetch-missing, and debug payment endpoints have no authentication"
severity: critical
domain: payment
labels: [security, backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 fetch-tx, auto-fetch-missing, and debug payment endpoints have no authentication
**Severity:** critical
**Domain:** payment
**Labels:** security, backend, bug
## Description
Three backend payment endpoints are mounted with **no `authenticateToken` middleware**, despite being documented as admin-only:
1. `POST /api/payment/payments/:id/fetch-tx` — triggers on-chain transaction fetch for a payment
2. `POST /api/payment/payments/auto-fetch-missing` — triggers bulk on-chain fetch for all pending payments
3. `GET /api/payment/payments/:id/debug` — returns full payment document including blockchain metadata and wallet monitor state
Any unauthenticated caller (no Authorization header needed) can call all three endpoints.
## Current Behavior
```bash
curl -X POST https://api.example.com/api/payment/payments/anyId/fetch-tx
# Returns 200 and triggers on-chain state write
```
## Expected Behavior
All three endpoints should require `authenticateToken` + `authorizeRoles('admin')` and return `401` without credentials.
## Affected Files
- `backend/src/routes/paymentRoutes.js` — route definitions for `fetch-tx`, `auto-fetch-missing`, `debug`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Findings C28, M40
- Related: [[ISSUE-005-scanner-status-no-auth]]

View File

@@ -0,0 +1,37 @@
---
issue: 004
title: "POST /api/disputes/:id/resolve (dashboard) does not trigger escrow release — only updates Dispute model"
severity: critical
domain: Dispute
labels: [bug, backend, escrow, major]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 POST /api/disputes/:id/resolve (dashboard) does not trigger escrow release — only updates Dispute model
**Severity:** critical
**Domain:** Dispute
**Labels:** bug, backend, escrow, major
## Description
The API claims resolveDispute 'triggers refund/release/split escrow action.' DisputeService.resolveDispute only updates the Dispute document. The separate POST /api/disputes/:purchaseRequestId/resolve (releaseHold router) is required to actually unblock escrow. Due to the route shadowing bug, the correct handler may never be reached.
## Current Behavior
DisputeService.resolveDispute only updates the Dispute document. Escrow remains blocked until a separate correct API call is made to the releaseHold router.
## Expected Behavior
Dispute resolution should atomically update the Dispute record AND release/refund the escrow as indicated by the action field.
## Affected Files
- `backend/src/services/disputeService.ts`
- `backend/src/controllers/disputeController.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,40 @@
---
issue: 005
title: "POST /api/payment/payments/:id/fetch-tx, POST /api/payment/payments/auto-fetch-missing, and GET /api/payment/payments/:id/debug have no authentication middleware"
severity: critical
domain: Payment
labels: [security, bug, backend, critical, missing-auth]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 POST /api/payment/payments/:id/fetch-tx, POST /api/payment/payments/auto-fetch-missing, and GET /api/payment/payments/:id/debug have no authentication middleware
**Severity:** critical
**Domain:** Payment
**Labels:** security, bug, backend, critical, missing-auth
## Description
Three payment utility/debug endpoints are mounted with zero authentication. Any unauthenticated caller can read full payment internals (including blockchain metadata and wallet monitor state) or trigger on-chain fetches and state writes. These are exploitable without credentials in production.
## Current Behavior
All three return 200 with full data when called without any Authorization header.
## Expected Behavior
All three endpoints should require at minimum authenticateToken, and ideally authorizeRoles('admin').
## Reproduction Steps
curl -X POST https://api.example.com/api/payment/payments/test123/fetch-tx — expect 401, currently returns 200.
## Affected Files
- `backend/src/routes/paymentRoutes.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,40 +0,0 @@
---
issue: "005"
title: "GET /api/admin/scanner/status has no authentication despite /api/admin/ prefix"
severity: critical
domain: admin
labels: [security, backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 GET /api/admin/scanner/status has no authentication despite /api/admin/ prefix
**Severity:** critical
**Domain:** admin
**Labels:** security, backend, bug
## Description
`GET /api/admin/scanner/status` proxies to `AMN_SCANNER_URL` and returns scanner status data. Despite sitting under the `/api/admin/` prefix (which conventionally implies admin auth), this endpoint has **no `authenticateToken` middleware**. Any unauthenticated request returns scanner data.
## Current Behavior
```bash
curl https://api.example.com/api/admin/scanner/status
# Returns scanner data with 200, no credentials needed
```
## Expected Behavior
Should return `401` without a valid admin JWT.
## Affected Files
- `backend/src/routes/adminRoutes.js` — scanner proxy route definition
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding C29
- Related: [[ISSUE-004-payment-endpoints-no-auth]]

View File

@@ -1,49 +0,0 @@
---
issue: "006"
title: "Frontend deleteAccount action calls DELETE /user/profile which does not exist"
severity: critical
domain: auth
labels: [frontend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 Frontend deleteAccount action calls DELETE /user/profile which does not exist
**Severity:** critical
**Domain:** auth
**Labels:** frontend, bug
## Description
`frontend/src/actions/account.ts` (line ~144) calls:
```ts
axiosInstance.delete(endpoints.users.profile)
// resolves to DELETE /user/profile
```
There is no `DELETE` handler on `/user/profile` in the backend. The actual soft-delete endpoint is:
```
DELETE /api/auth/account
```
which requires a `password` field in the request body and runs `deleteAccountValidation`.
**Result:** Account deletion silently 404s from every UI path. Users cannot delete their accounts.
## Current Behavior
Clicking the delete account button in the dashboard sends `DELETE /user/profile` → 404. The account is not deleted.
## Expected Behavior
The action should send `DELETE /api/auth/account` with `{ password }` in the body. On success, the account status is set to `'deleted'` (soft delete) in MongoDB.
## Affected Files
- `frontend/src/actions/account.ts``deleteAccount` function
- `frontend/src/lib/axios.ts``endpoints.users.profile` key used for the path
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding C3

View File

@@ -0,0 +1,40 @@
---
issue: 006
title: "GET /api/admin/scanner/status has no authentication middleware despite /api/admin/ prefix"
severity: critical
domain: Admin
labels: [security, bug, backend, critical, missing-auth]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 GET /api/admin/scanner/status has no authentication middleware despite /api/admin/ prefix
**Severity:** critical
**Domain:** Admin
**Labels:** security, bug, backend, critical, missing-auth
## Description
The scanner status proxy endpoint at GET /api/admin/scanner/status proxies directly to AMN_SCANNER_URL without any authentication check, despite sitting under the /api/admin/ route prefix which conventionally requires admin auth.
## Current Behavior
Returns scanner data (200) to any unauthenticated request.
## Expected Behavior
Return 401 without Authorization header, 403 for non-admin token. Apply authenticateToken + authorizeRoles('admin').
## Reproduction Steps
curl https://api.example.com/api/admin/scanner/status — should return 401, currently returns scanner data.
## Affected Files
- `backend/src/routes/adminRoutes.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,37 @@
---
issue: 007
title: "Frontend deleteAccount action calls DELETE /user/profile which has no backend route — account deletion is broken"
severity: critical
domain: Authentication
labels: [bug, frontend, critical, broken-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 Frontend deleteAccount action calls DELETE /user/profile which has no backend route — account deletion is broken
**Severity:** critical
**Domain:** Authentication
**Labels:** bug, frontend, critical, broken-feature
## Description
The frontend deleteAccount action in src/actions/account.ts (line 144) calls axiosInstance.delete(endpoints.users.profile) which resolves to DELETE /user/profile. The actual soft-delete route is DELETE /api/auth/account (requires password in body, runs deleteAccountValidation). Account deletion silently returns 404 from every UI path.
## Current Behavior
DELETE /user/profile returns 404. Users cannot delete their accounts from the UI.
## Expected Behavior
deleteAccount action should call DELETE /api/auth/account with the user's password in the request body.
## Affected Files
- `frontend/src/actions/account.ts`
- `frontend/src/lib/axios.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,42 +0,0 @@
---
issue: "007"
title: "SIM_ transaction bypass active in production — no NODE_ENV guard on wallet connection fallback"
severity: critical
domain: payment
labels: [security, frontend, backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 SIM_ transaction bypass active in production — no NODE_ENV guard on wallet connection fallback
**Severity:** critical
**Domain:** payment
**Labels:** security, frontend, backend, bug
## Description
`frontend/src/web3/context/web3-provider.tsx` (lines ~225 and ~232) generates `SIM_` prefixed transaction hashes when wallet connection fails, and passes these to the backend as real transaction hashes.
The backend's payment service skips all on-chain verification for any `paymentHash` starting with `SIM_`. This bypass is controlled **only by the hash prefix** — there is no `process.env.NODE_ENV === 'development'` check in either the frontend or backend.
In production, if a user's wallet connection times out or throws (e.g., network error, MetaMask not responding), the frontend will submit a `SIM_` hash. This can result in a payment record being created as `completed` without any actual on-chain transaction.
## Current Behavior
Wallet connection failure → frontend generates `SIM_xxxxxxxx` hash → sends to backend → backend skips on-chain verification → payment created as completed.
## Expected Behavior
- Frontend: `SIM_` hash generation should be gated on `process.env.NODE_ENV !== 'production'`
- Backend: `SIM_` bypass should additionally check an environment flag (e.g., `process.env.ALLOW_SIM_PAYMENTS !== 'true'`)
## Affected Files
- `frontend/src/web3/context/web3-provider.tsx` — lines ~225, ~232
- `backend/src/services/payment/` — SIM_ prefix check in payment verification logic
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M39

View File

@@ -1,41 +0,0 @@
---
issue: "008"
title: "sendFileMessage posts to wrong endpoint — file uploads always fail in chat"
severity: critical
domain: chat
labels: [frontend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 sendFileMessage posts to wrong endpoint — file uploads always fail in chat
**Severity:** critical
**Domain:** chat
**Labels:** frontend, bug
## Description
`frontend/src/actions/chat.ts` (line ~386) sends file upload multipart form data to `endpoints.chat.sendMessage` which resolves to `POST /api/chat/:id/messages` — the text message endpoint.
The actual backend file upload endpoint is `POST /api/chat/:id/messages/file`.
The text-message handler expects a JSON body with a `content` string field, not a multipart payload. The file upload either fails or the attachment is silently discarded.
## Current Behavior
User picks a file in the chat input → `sendFileMessage` POSTs multipart to `/chat/:id/messages` → backend text handler rejects or ignores the multipart payload → file is never uploaded or stored.
## Expected Behavior
`sendFileMessage` should POST to `/api/chat/:id/messages/file` with the multipart form data. The response should include a message with an `attachments` array.
## Affected Files
- `frontend/src/actions/chat.ts``sendFileMessage` function uses `endpoints.chat.sendMessage`
- `frontend/src/lib/axios.ts` — no `endpoints.chat.sendFileMessage` entry exists; needs to be added as `/chat/:id/messages/file`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding C19

View File

@@ -0,0 +1,37 @@
---
issue: 008
title: "sendFileMessage posts to wrong endpoint — file uploads silently fail or corrupt text-message handler"
severity: critical
domain: Chat
labels: [bug, frontend, critical, broken-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 sendFileMessage posts to wrong endpoint — file uploads silently fail or corrupt text-message handler
**Severity:** critical
**Domain:** Chat
**Labels:** bug, frontend, critical, broken-feature
## Description
The frontend sendFileMessage action in src/actions/chat.ts (line 386) sends multipart form data to endpoints.chat.sendMessage which resolves to POST /api/chat/:id/messages. The actual file upload endpoint is POST /api/chat/:id/messages/file. The file payload hits the text-message handler which expects JSON with a string content field.
## Current Behavior
File uploads hit the text-message handler, which cannot process multipart payloads. File attachments are silently discarded or the request errors.
## Expected Behavior
sendFileMessage should POST multipart/form-data to /api/chat/:id/messages/file.
## Affected Files
- `frontend/src/actions/chat.ts`
- `frontend/src/lib/axios.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,36 +0,0 @@
---
issue: "009"
title: "archiveConversation uses PUT but backend only accepts PATCH"
severity: major
domain: chat
labels: [frontend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 archiveConversation uses PUT but backend only accepts PATCH
**Severity:** major
**Domain:** chat
**Labels:** frontend, bug
## Description
`frontend/src/actions/chat.ts` (line ~289) calls `axiosInstance.put(endpoints.chat.archive, ...)`. The backend registers this route as `PATCH /api/chat/:id/archive`. Express treats PUT and PATCH as distinct methods; PUT will not match the PATCH handler and returns 404/405.
## Current Behavior
Attempting to archive a conversation from the UI sends `PUT /api/chat/:id/archive` → 404. The chat is not archived.
## Expected Behavior
`archiveConversation` should use `axiosInstance.patch(...)` to match the backend's PATCH registration. The endpoint also has toggle semantics — calling it on an archived chat unarchives it.
## Affected Files
- `frontend/src/actions/chat.ts``archiveConversation` method verb (`put``patch`)
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding C20

View File

@@ -0,0 +1,36 @@
---
issue: 009
title: "archiveConversation sends PUT but backend only accepts PATCH — all archive attempts fail"
severity: critical
domain: Chat
labels: [bug, frontend, critical, broken-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 archiveConversation sends PUT but backend only accepts PATCH — all archive attempts fail
**Severity:** critical
**Domain:** Chat
**Labels:** bug, frontend, critical, broken-feature
## Description
The frontend archiveConversation action (src/actions/chat.ts line 289) calls axiosInstance.put(). The backend registers PATCH /api/chat/:id/archive. HTTP method mismatch causes 404 or 405 on every archive attempt.
## Current Behavior
Every archive attempt returns 404/405. Chat archiving is non-functional.
## Expected Behavior
archiveConversation should call axiosInstance.patch().
## Affected Files
- `frontend/src/actions/chat.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,49 +0,0 @@
---
issue: "010"
title: "Admin user status/role actions broken: wrong HTTP verb (PUT vs PATCH) and wrong status values"
severity: critical
domain: admin
labels: [frontend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 Admin user status/role actions broken: wrong HTTP verb (PUT vs PATCH) and wrong status values
**Severity:** critical
**Domain:** admin
**Labels:** frontend, bug
## Description
Two separate bugs on the admin user management actions:
**Bug 1 — Wrong HTTP verb:**
`frontend/src/actions/user.ts`:
- `updateUserStatus` calls `axiosInstance.put(...)` — backend registers `PATCH`
- `updateUserRole` calls `axiosInstance.put(...)` — backend registers `PATCH`
Both will 404/405 in production since Express doesn't alias PUT to PATCH.
**Bug 2 — Wrong status values:**
`updateUserStatus` accepts and sends `'active' | 'inactive' | 'pending'`. The backend `User.status` enum only accepts `'active' | 'suspended' | 'deleted'`. Sending `'inactive'` or `'pending'` is silently rejected or ignored. `'suspended'` is completely absent from the frontend type.
## Current Behavior
- Clicking "Suspend user" in admin panel sends `PUT /api/users/admin/:userId/status` with `{ status: 'inactive' }` → 404 and wrong value
- Clicking "Update role" sends `PUT /api/users/admin/:userId/role` → 404
## Expected Behavior
- Use `axiosInstance.patch(...)` for both actions
- Status values should be `'active' | 'suspended' | 'deleted'` to match the backend enum
## Affected Files
- `frontend/src/actions/user.ts``updateUserStatus` (line ~162), `updateUserRole` (line ~175)
- `frontend/src/types/user.ts` (line ~159) — status union type needs to include `'suspended'` and remove `'inactive'`/`'pending'`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Findings C26, C27

View File

@@ -0,0 +1,36 @@
---
issue: 010
title: "Frontend admin updateUserStatus and updateUserRole use PUT but backend only accepts PATCH"
severity: critical
domain: User Management
labels: [bug, frontend, critical, admin, broken-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 Frontend admin updateUserStatus and updateUserRole use PUT but backend only accepts PATCH
**Severity:** critical
**Domain:** User Management
**Labels:** bug, frontend, critical, admin, broken-feature
## Description
user.ts line 162 calls axiosInstance.put() for updateUserStatus and line 175 calls axiosInstance.put() for updateUserRole. Backend registers these as PATCH /api/users/admin/:userId/status and PATCH /api/users/admin/:userId/role. PUT is not registered; calls return 404 or 405.
## Current Behavior
Admin status and role update actions fail with 404/405 silently.
## Expected Behavior
Both actions should use axiosInstance.patch().
## Affected Files
- `frontend/src/actions/user.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,37 @@
---
issue: 011
title: "Frontend updateUserStatus sends 'inactive'/'pending' status values that backend does not accept"
severity: critical
domain: User Management
labels: [bug, frontend, critical, admin, type-mismatch]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 Frontend updateUserStatus sends 'inactive'/'pending' status values that backend does not accept
**Severity:** critical
**Domain:** User Management
**Labels:** bug, frontend, critical, admin, type-mismatch
## Description
TypeScript union type in user.ts line 159 is 'active' | 'inactive' | 'pending'. Backend User.status enum is active | suspended | deleted. Values 'inactive' and 'pending' are not valid on the backend and will be rejected or silently ignored. 'suspended' is absent from the frontend type.
## Current Behavior
Attempting to set user status to 'inactive' or 'pending' via the admin UI sends invalid values. The user's status is not actually updated.
## Expected Behavior
Frontend type should be 'active' | 'suspended' | 'deleted' to match the backend enum. Admin UI should offer 'suspended' as an option.
## Affected Files
- `frontend/src/actions/user.ts`
- `frontend/src/types/user.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,36 +0,0 @@
---
issue: "011"
title: "updatePurchaseRequest sends PUT but backend only accepts PATCH"
severity: major
domain: purchase-request
labels: [frontend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 updatePurchaseRequest sends PUT but backend only accepts PATCH
**Severity:** major
**Domain:** purchase-request
**Labels:** frontend, bug
## Description
`frontend/src/actions/marketplace.ts` (line ~71) calls `axiosInstance.put(endpoints.marketplace.requests.update)`. The backend registers `PATCH /marketplace/purchase-requests/:id` (routes.ts). Sending PUT results in 404/405 — edits to purchase requests silently fail.
## Current Behavior
Editing a purchase request from the buyer edit view sends `PUT /marketplace/purchase-requests/:id` → 404. The request is not updated.
## Expected Behavior
The action should use `axiosInstance.patch(...)`.
## Affected Files
- `frontend/src/actions/marketplace.ts``updatePurchaseRequest` function (verb: `put``patch`)
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M18

View File

@@ -0,0 +1,38 @@
---
issue: 012
title: "Trezor Safekeeping frontend — audit 'zero frontend' finding was STALE (feature exists)"
severity: info
domain: Trezor
labels: [invalid, stale-audit, trezor, frontend]
status: invalid
created: 2026-05-29
resolved: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# ⚪ INVALID — Trezor Safekeeping frontend DOES exist (audit finding was stale)
**Severity:** info (was: critical)
**Domain:** Trezor
**Status:** INVALID — the audit's "zero frontend implementation" claim (findings C31/C32) was generated from an older code snapshot. The frontend Trezor implementation exists in current code.
## Why this is not a bug
A direct re-check of the current frontend on 2026-05-29 confirmed a complete Trezor implementation:
- `frontend/src/app/dashboard/admin/trezor/page.tsx` → renders `TrezorSettingsView` (registration + re-register UI)
- `frontend/src/sections/admin/trezor/trezor-settings-view.tsx` → settings/registration view (~14KB)
- `frontend/src/web3/trezor/trezorConnector.ts` → lazy-imports `@trezor/connect-web`; implements `trezorGetXpub`, `trezorGetAddress`, `trezorSignMessage`
- `frontend/src/components/trezor-sign-dialog/TrezorSignDialog.tsx` → full stepper: build instruction → sign on Trezor → enter txHash → confirm
- `frontend/src/actions/trezor.ts` → complete API client: `getTrezorAccount`, `getTrezorRegistrationMessage`, `registerTrezor`, `getTrezorOperationMessage`, `confirmRelease`, `confirmRefund` — and it **builds the `trezor: { message, signature }` object** in the confirmation body
The active admin release/refund path goes through `TrezorSignDialog``actions/trezor.ts`, which **does** satisfy the backend `assertTrezorSignatureForOperation` guard when `TREZOR_SAFEKEEPING_REQUIRED=true`.
## Residual note (not a blocker)
The legacy helpers `confirmReleaseTx` / `confirmRefundTx` in `frontend/src/actions/payment.ts` post only `{ txHash }` with no `trezor` field — but they have **no UI callers** and are dead code. Consider removing them to avoid confusion. Tracked as a minor cleanup, not a release blocker.
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — findings C31, C32 (now superseded)
- Corrected doc: `04 - Flows/Trezor Safekeeping Flow.md`

View File

@@ -1,36 +0,0 @@
---
issue: "012"
title: "updateOffer sends PUT but backend registers PATCH — offer edits fail"
severity: major
domain: seller-offer
labels: [frontend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 updateOffer sends PUT but backend registers PATCH — offer edits fail
**Severity:** major
**Domain:** seller-offer
**Labels:** frontend, bug
## Description
`frontend/src/actions/marketplace.ts` (line ~289) calls `axiosInstance.put(endpoints.marketplace.offers.update)` mapping to `PUT /marketplace/offers/:id`. The backend registers `PATCH /offers/:id` (routes.ts line ~1260). Method mismatch → 404 or matched wrong route. `step-1-send-proposal.tsx` calls `updateOffer()` for proposal edits, so this path is actively exercised.
## Current Behavior
A seller editing an existing proposal sends `PUT /marketplace/offers/:id` which does not match the registered `PATCH` handler.
## Expected Behavior
`updateOffer` should use `axiosInstance.patch(...)`.
## Affected Files
- `frontend/src/actions/marketplace.ts``updateOffer` function
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M28

View File

@@ -0,0 +1,40 @@
---
issue: 013
title: "createProviderPaymentIntent always routes to request-network/intents regardless of provider argument"
severity: critical
domain: Payment
labels: [bug, frontend, critical, payment, routing]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 createProviderPaymentIntent always routes to request-network/intents regardless of provider argument
**Severity:** critical
**Domain:** Payment
**Labels:** bug, frontend, critical, payment, routing
## Description
src/actions/payment.ts getProviderIntentEndpoint() ignores the provider parameter and always returns endpoints.payments.requestNetwork.intents ('/payment/request-network/intents'). Any checkout using provider='shkeeper' silently POSTs to the wrong backend service.
## Current Behavior
SHKeeper checkout silently POSTs to /payment/request-network/intents instead of /payment/shkeeper/intents, causing payment intent creation to fail or create a wrong-provider payment record.
## Expected Behavior
getProviderIntentEndpoint() should return the correct provider-specific endpoint based on the provider argument (e.g., endpoints.payments.shkeeper.intents for 'shkeeper').
## Reproduction Steps
Initiate a SHKeeper checkout and intercept network — observe the POST goes to /payment/request-network/intents not /payment/shkeeper/intents.
## Affected Files
- `frontend/src/actions/payment.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,42 +0,0 @@
---
issue: "013"
title: "select-offer cascade overwrites withdrawn/rejected offers — missing status filter in updateMany"
severity: major
domain: seller-offer
labels: [backend, bug, data-integrity]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 select-offer cascade overwrites withdrawn/rejected offers — missing status filter in updateMany
**Severity:** major
**Domain:** seller-offer
**Labels:** backend, bug, data-integrity
## Description
`POST /api/marketplace/purchase-requests/:id/select-offer` (routes.ts lines ~1386-1395) calls `SellerOffer.updateMany({ purchaseRequestId, _id: { $ne: offerId } }, { status: 'rejected' })` with **no status filter**. This overwrites offers that are already `'withdrawn'` or previously `'rejected'`, corrupting their status history.
By contrast, `SellerOfferService.acceptOffer()` (the service method used by `PUT /offers/:id/accept`) correctly filters with `status: { $in: ['pending', 'active'] }` before bulk-rejecting competitors.
## Current Behavior
1. Seller A submits offer → pending
2. Seller B submits offer → pending
3. Seller B withdraws offer → withdrawn
4. Buyer selects Seller A's offer via `POST .../select-offer`
5. Seller B's withdrawn offer is **overwritten to 'rejected'** — status history corrupted
## Expected Behavior
The `updateMany` in the `select-offer` route handler should add `status: { $in: ['pending'] }` to only reject currently-pending competing offers. Already-withdrawn or rejected offers should be left untouched.
## Affected Files
- `backend/src/routes/routes.ts` (or marketplaceController.ts) — `select-offer` route handler's `updateMany` call
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M23

View File

@@ -0,0 +1,36 @@
---
issue: 014
title: "PaymentProvider TypeScript type excludes 'shkeeper' and 'decentralized' causing UI fallthrough for main payment providers"
severity: critical
domain: Payment
labels: [bug, frontend, critical, payment, type-mismatch]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 PaymentProvider TypeScript type excludes 'shkeeper' and 'decentralized' causing UI fallthrough for main payment providers
**Severity:** critical
**Domain:** Payment
**Labels:** bug, frontend, critical, payment, type-mismatch
## Description
src/types/payment.ts defines PaymentProvider as 'request.network' | 'test' | 'other'. The two primary production payment providers ('shkeeper' and 'decentralized') are absent from this union type. Frontend code that switches on PaymentProvider falls through to unknown/default state for the majority of production payments.
## Current Behavior
Provider-based conditional rendering, labels, and routing logic silently falls through to unknown state for SHKeeper and DePay payments.
## Expected Behavior
PaymentProvider type should include 'shkeeper' and 'decentralized' variants.
## Affected Files
- `frontend/src/types/payment.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,43 +0,0 @@
---
issue: "014"
title: "select-offer sends no per-seller socket events or notifications to winning/losing sellers"
severity: major
domain: seller-offer
labels: [backend, missing-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 select-offer sends no per-seller socket events or notifications to winning/losing sellers
**Severity:** major
**Domain:** seller-offer
**Labels:** backend, missing-feature
## Description
`POST /api/marketplace/purchase-requests/:id/select-offer` (routes.ts lines ~1300-1438) emits only a single `purchase-request-update` event to the request room with `eventType: 'offer-selected'`. It does NOT:
- Call `notifyOfferAccepted` for the winning seller
- Call `notifyOfferRejected` for losing sellers
- Emit `seller-offer-update` events to individual seller rooms
These notifications only fire when using `PUT /offers/:id/accept` or `PUT /offers/:id/status` (via `SellerOfferService.updateOfferStatus`), not via the `select-offer` path used by the frontend.
## Current Behavior
Buyer selects an offer → winning seller gets no real-time notification → losing sellers get no notification.
## Expected Behavior
When a buyer selects an offer:
1. Winning seller receives a `seller-offer-update` event and a push notification
2. Losing sellers receive a `seller-offer-update` event and a notification
## Affected Files
- `backend/src/routes/routes.ts``select-offer` route handler, missing `notifyOfferAccepted` and `notifyOfferRejected` calls
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M25

View File

@@ -1,44 +0,0 @@
---
issue: "015"
title: "Seller offer withdraw has no HTTP route — withdrawOffer() service method is dead code"
severity: major
domain: seller-offer
labels: [backend, missing-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Seller offer withdraw has no HTTP route — withdrawOffer() service method is dead code
**Severity:** major
**Domain:** seller-offer
**Labels:** backend, missing-feature
## Description
`SellerOfferService.withdrawOffer()` (SellerOfferService.ts lines ~427-443) exists and implements withdrawal logic, but no HTTP route calls it. The documented `POST /api/marketplace/offers/:id/withdraw` endpoint does not exist in `routes.ts` or `marketplaceController.ts`.
There is also no frontend `withdrawOffer()` action, no withdraw button in any seller step component, and no seller offers history page at `/dashboard/seller/marketplace/offers`.
The only workaround is `PUT /api/marketplace/offers/:id/status` with `{ status: 'withdrawn' }`, which has no guard ensuring the requester is the offer's seller.
## Current Behavior
Sellers cannot withdraw their pending offers through any UI path. Withdrawing via `PUT /offers/:id/status` is the only API path and has no ownership guard.
## Expected Behavior
1. Wire a `POST /api/marketplace/offers/:id/withdraw` route to `SellerOfferService.withdrawOffer()`
2. Add an ownership guard (only the offer's seller can withdraw)
3. Add a frontend withdraw button and action
## Affected Files
- `backend/src/routes/routes.ts` — missing `POST /offers/:id/withdraw` route
- `frontend/src/actions/marketplace.ts` — missing `withdrawOffer` action
- Frontend seller dashboard — missing offers list page
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Findings C9, M26

View File

@@ -0,0 +1,40 @@
---
issue: 015
title: "Simulated transaction SIM_ bypass has no environment guard — can fire in production on wallet connection failure"
severity: critical
domain: Payment
labels: [security, bug, critical, payment, frontend, bypass]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 Simulated transaction SIM_ bypass has no environment guard — can fire in production on wallet connection failure
**Severity:** critical
**Domain:** Payment
**Labels:** security, bug, critical, payment, frontend, bypass
## Description
src/web3/context/web3-provider.tsx lines 225 and 232 generate SIM_ prefixed transaction hashes when wallet connection fails. The backend skips on-chain verification for any paymentHash starting with 'SIM_' — controlled only by hash prefix, not an environment flag. The frontend generates SIM_ hashes in an error fallback path that can trigger in production.
## Current Behavior
In production, if a wallet connection times out or throws, the fallback generates a SIM_ hash that passes backend verification and creates a completed payment record without any real on-chain transaction.
## Expected Behavior
SIM_ hash generation should be guarded by process.env.NODE_ENV !== 'production' check. Backend SIM_ bypass should also be gated by NODE_ENV.
## Reproduction Steps
Simulate a wallet connection failure in staging — observe that a SIM_ hash is generated and check if a completed payment record is created in the database.
## Affected Files
- `frontend/src/web3/context/web3-provider.tsx`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,39 +0,0 @@
---
issue: "016"
title: "createProviderPaymentIntent always routes to request-network regardless of provider — SHKeeper checkout broken"
severity: critical
domain: payment
labels: [frontend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 createProviderPaymentIntent always routes to request-network regardless of provider — SHKeeper checkout broken
**Severity:** critical
**Domain:** payment
**Labels:** frontend, bug
## Description
`frontend/src/actions/payment.ts``getProviderIntentEndpoint()` ignores its `provider` argument and always returns `endpoints.payments.requestNetwork.intents` (`/payment/request-network/intents`).
If any UI component passes `provider='shkeeper'` to `createProviderPaymentIntent()`, the intent creation silently POSTs to the Request Network endpoint instead of `/payment/shkeeper/intents`. The SHKeeper intents endpoint is defined in `axios.ts` but is never reached by this factory.
## Current Behavior
A SHKeeper checkout call to `createProviderPaymentIntent('shkeeper', ...)` POSTs to `/payment/request-network/intents`. The RN endpoint creates a Request Network intent, not a SHKeeper intent. The payment provider is silently misrouted.
## Expected Behavior
`getProviderIntentEndpoint('shkeeper')` should return `endpoints.payments.shkeeper.intents`. The function should switch on the provider argument.
## Affected Files
- `frontend/src/actions/payment.ts``getProviderIntentEndpoint()` function (~line 444)
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M38
- Related: [[ISSUE-017-payment-provider-type-missing-values]]

View File

@@ -0,0 +1,36 @@
---
issue: 016
title: "updatePurchaseRequest uses PUT but backend only registers PATCH — all purchase request edits fail"
severity: major
domain: Purchase Request
labels: [bug, frontend, major, broken-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 updatePurchaseRequest uses PUT but backend only registers PATCH — all purchase request edits fail
**Severity:** major
**Domain:** Purchase Request
**Labels:** bug, frontend, major, broken-feature
## Description
The frontend updatePurchaseRequest action (marketplace.ts line 71) calls axiosInstance.put against '/marketplace/purchase-requests/:id'. Backend registers PATCH (not PUT) on /purchase-requests/:id. PUT returns 404 from the controller router.
## Current Behavior
Purchase request edits from the buyer edit view fail with 404/405.
## Expected Behavior
updatePurchaseRequest should call axiosInstance.patch().
## Affected Files
- `frontend/src/actions/marketplace.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,46 +0,0 @@
---
issue: "017"
title: "PaymentProvider TypeScript type missing 'shkeeper' and 'decentralized' values"
severity: major
domain: payment
labels: [frontend, bug, typescript]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 PaymentProvider TypeScript type missing 'shkeeper' and 'decentralized' values
**Severity:** major
**Domain:** payment
**Labels:** frontend, bug, typescript
## Description
`frontend/src/types/payment.ts` defines:
```ts
type PaymentProvider = 'request.network' | 'test' | 'other'
```
The backend accepts `'shkeeper'`, `'decentralized'`, and `'other'` as `provider` values on Payment records. The two most-used production providers (`shkeeper`, `decentralized`) are absent from the TypeScript union.
Any frontend code that switches on `payment.provider` will fall through to a default/unknown branch for all SHKeeper and DePay payments, causing incorrect UI rendering (wrong labels, missing payment method icons, etc.).
## Current Behavior
SHKeeper and DePay payments in the payment list and payment detail views may show as "Unknown provider" or trigger TypeScript errors at compile time.
## Expected Behavior
```ts
type PaymentProvider = 'request.network' | 'shkeeper' | 'decentralized' | 'test' | 'other'
```
## Affected Files
- `frontend/src/types/payment.ts``PaymentProvider` type definition (~line 15)
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M37
- Related: [[ISSUE-016-payment-provider-routing-always-request-network]]

View File

@@ -0,0 +1,36 @@
---
issue: 017
title: "updateOffer uses PUT /marketplace/offers/:id but backend registers PATCH /offers/:id — offer edits fail"
severity: major
domain: Seller Offer
labels: [bug, frontend, major, broken-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 updateOffer uses PUT /marketplace/offers/:id but backend registers PATCH /offers/:id — offer edits fail
**Severity:** major
**Domain:** Seller Offer
**Labels:** bug, frontend, major, broken-feature
## Description
Frontend updateOffer action (src/actions/marketplace.ts line 289) uses axiosInstance.put() against /marketplace/offers/:id. Backend registers router.patch('/offers/:id') at routes.ts line 1260. Method mismatch. step-1-send-proposal.tsx actively calls updateOffer() for existing offer edits.
## Current Behavior
Offer price/ETA/notes edits from the seller proposal form fail silently or 404.
## Expected Behavior
updateOffer should use axiosInstance.patch().
## Affected Files
- `frontend/src/actions/marketplace.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,40 @@
---
issue: 018
title: "select-offer updateMany has no status filter — overwrites withdrawn/rejected offers back to 'rejected' corrupting status history"
severity: major
domain: Seller Offer
labels: [bug, backend, major, data-integrity]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 select-offer updateMany has no status filter — overwrites withdrawn/rejected offers back to 'rejected' corrupting status history
**Severity:** major
**Domain:** Seller Offer
**Labels:** bug, backend, major, data-integrity
## Description
The POST /purchase-requests/:id/select-offer route handler (routes.ts lines 1386-1395) uses updateMany with only {purchaseRequestId, _id: {$ne: offerId}} — no status filter. This can overwrite already-withdrawn or previously-rejected offers' status back to 'rejected', corrupting their status history. SellerOfferService.acceptOffer() correctly filters by status: {$in: ['pending', 'active']}.
## Current Behavior
Selecting an offer via the select-offer endpoint corrupts previously-withdrawn offer records by setting their status back to 'rejected'.
## Expected Behavior
The select-offer updateMany call should include a status filter: {$in: ['pending']} to only reject pending offers, matching the service-layer behavior.
## Reproduction Steps
Create a request with one withdrawn offer and one pending offer. Select the pending offer via POST /purchase-requests/:id/select-offer. Verify the withdrawn offer's status is now 'rejected'.
## Affected Files
- `backend/src/routes/routes.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,53 +0,0 @@
---
issue: "018"
title: "Trezor Safekeeping has zero frontend implementation — all backend endpoints unreachable from UI"
severity: critical
domain: trezor
labels: [frontend, missing-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🔴 Trezor Safekeeping has zero frontend implementation — all backend endpoints unreachable from UI
**Severity:** critical
**Domain:** trezor
**Labels:** frontend, missing-feature
## Description
A comprehensive search of all `.ts` and `.tsx` files in `frontend/src/` finds **zero calls** to any Trezor backend endpoint. There is no:
- Trezor registration page
- xpub input UI
- Trezor Connect SDK import
- Admin Trezor signing panel
- Any action calling `/api/trezor/*`
The only Trezor reference in the entire frontend is a brand logo in `wallet-icons.ts`.
The documented 12-step challenge-sign-submit flow exists entirely in the backend but has no frontend surface at any step.
Additionally, `confirmReleaseTx` and `confirmRefundTx` in `frontend/src/actions/payment.ts` post `{ txHash, ...extra }` with **no `trezor` object** (message + signature). With `TREZOR_SAFEKEEPING_REQUIRED=true`, every admin release/refund from the UI will be rejected by the backend's `assertTrezorSignatureForOperation` guard.
## Current Behavior
- No UI exists for Trezor registration
- Admin release/refund with `TREZOR_SAFEKEEPING_REQUIRED=true` always fails (missing signature payload)
- All Trezor API endpoints are only testable via curl/Postman
## Expected Behavior
A complete frontend implementation covering:
1. Trezor registration page (xpub input, challenge-sign-submit flow)
2. Operation signing UI for admin release/refund (call `POST /api/trezor/operation-message`, prompt sign, attach `trezor` object to confirm body)
## Affected Files
- `frontend/src/actions/payment.ts``confirmReleaseTx`, `confirmRefundTx` missing `trezor` field
- Missing: Trezor registration page component
- Missing: Admin Trezor signing integration in dispute/payment admin panels
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Findings C31, C32

View File

@@ -1,46 +0,0 @@
---
issue: "019"
title: "Request Network admin payout/release/refund sub-routes do not exist in backend"
severity: major
domain: payment
labels: [backend, missing-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Request Network admin payout/release/refund sub-routes do not exist in backend
**Severity:** major
**Domain:** payment
**Labels:** backend, missing-feature
## Description
`frontend/src/actions/payment.ts` exports four functions that hit non-existent backend endpoints:
| Function | Calls | Status |
|---|---|---|
| `initiateRequestNetworkPayout()` | `POST /api/payment/request-network/:id/payout/initiate` | 404 |
| `confirmRequestNetworkPayout()` | `POST /api/payment/request-network/:id/payout/confirm` | 404 |
| `confirmRequestNetworkRelease()` | `POST /api/payment/request-network/:id/release/confirm` | 404 |
| `confirmRequestNetworkRefund()` | `POST /api/payment/request-network/:id/refund/confirm` | 404 |
The backend only implements: `POST /api/payment/request-network/intents`, `GET /api/payment/request-network/:paymentId/checkout`, `POST /api/payment/request-network/webhook`.
## Current Behavior
All four admin RN payout/release/refund actions return 404. Admin has no way to complete or refund a Request Network payment through the UI.
## Expected Behavior
Backend should implement the four sub-routes, or the frontend actions should be mapped to the actual release/refund mechanism.
## Affected Files
- `frontend/src/actions/payment.ts``initiateRequestNetworkPayout`, `confirmRequestNetworkPayout`, `confirmRequestNetworkRelease`, `confirmRequestNetworkRefund`
- Backend: missing `request-network/:id/payout/*`, `release/confirm`, `refund/confirm` routes
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M34

View File

@@ -0,0 +1,36 @@
---
issue: 019
title: "SellerOffer.status 'active' does not exist in schema enum but is referenced in docs and code comments"
severity: major
domain: Seller Offer
labels: [bug, backend, major, data-model]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 SellerOffer.status 'active' does not exist in schema enum but is referenced in docs and code comments
**Severity:** major
**Domain:** Seller Offer
**Labels:** bug, backend, major, data-model
## Description
SellerOffer Mongoose schema (SellerOffer.ts line 80) and TypeScript interface (line 17) enumerate only 'pending | accepted | rejected | withdrawn'. Attempting to save status='active' on a SellerOffer will throw a Mongoose ValidationError. Any code path that sets status='active' on a SellerOffer will fail at runtime.
## Current Behavior
Any attempt to set a SellerOffer to 'active' throws Mongoose ValidationError.
## Expected Behavior
Either add 'active' to the SellerOffer status enum if it is a real state, or remove all references to it from code comments and remove the documented state machine entry.
## Affected Files
- `backend/src/models/SellerOffer.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,42 +0,0 @@
---
issue: "020"
title: "POST /api/disputes/:id/assign has no role guard — any user can self-assign as mediator"
severity: major
domain: dispute
labels: [security, backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 POST /api/disputes/:id/assign has no role guard — any user can self-assign as mediator
**Severity:** major
**Domain:** dispute
**Labels:** security, backend, bug
## Description
`POST /api/disputes/:id/assign` is mounted with only `authenticateToken`. Any authenticated buyer or seller can assign themselves as the mediator/admin for any open dispute.
## Current Behavior
```bash
POST /api/disputes/{disputeId}/assign
Authorization: Bearer <buyer-jwt>
{ "adminId": "<buyer-user-id>" }
```
Returns 200 and sets the dispute's assigned mediator to the buyer.
## Expected Behavior
Should require `authorizeRoles('admin')`. Non-admin tokens should receive `403`.
## Affected Files
- `backend/src/routes/disputeRoutes.ts` — missing role guard on the assign route
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)
- Related: [[ISSUE-001-dispute-status-no-role-guard]], [[ISSUE-002-dispute-resolve-no-role-guard]]

View File

@@ -0,0 +1,36 @@
---
issue: 020
title: "select-offer does not send per-seller socket events or notifications to winning or losing sellers"
severity: major
domain: Seller Offer
labels: [bug, backend, major, notifications, socket]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 select-offer does not send per-seller socket events or notifications to winning or losing sellers
**Severity:** major
**Domain:** Seller Offer
**Labels:** bug, backend, major, notifications, socket
## Description
POST /purchase-requests/:id/select-offer route (routes.ts lines 1300-1438) emits only a single purchase-request-update event to the request room. It does NOT call notifyOfferAccepted, does NOT call notifyOfferRejected for losing sellers, and does NOT emit seller-offer-update events. Those notifications only fire via SellerOfferService.updateOfferStatus().
## Current Behavior
After a buyer selects an offer via select-offer, the winning seller receives no notification and losing sellers receive no rejection notification.
## Expected Behavior
The select-offer path should emit per-seller socket events and notifications equivalent to what SellerOfferService.acceptOffer() does — notify the winning seller and each losing seller.
## Affected Files
- `backend/src/routes/routes.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,45 +0,0 @@
---
issue: "021"
title: "Axios interceptor only retriggers token refresh for 401, not 403"
severity: major
domain: auth
labels: [frontend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Axios interceptor only retriggers token refresh for 401, not 403
**Severity:** major
**Domain:** auth
**Labels:** frontend, bug
## Description
`frontend/src/lib/axios.ts` (line ~105) only triggers the token refresh flow for `status === 401`:
```ts
if (status === 401 && !isAuthRoute && !originalRequest?._retry) {
// trigger refresh
}
```
A `403` response (e.g., `EMAIL_NOT_VERIFIED`, a blocked account, or an under-privileged action) is not intercepted — it propagates as an unhandled error. Depending on how calling components handle errors, this may result in a blank screen or silent failure rather than an appropriate user message.
## Current Behavior
Backend returns `403 EMAIL_NOT_VERIFIED` → interceptor does not retry or refresh → error propagates to the component. Some components may not handle this gracefully.
## Expected Behavior
The interceptor (or a separate error handler) should:
- On `403`: **not** attempt a token refresh (a 403 is an authorization failure, not an expired token)
- But should surface the error clearly to the user (e.g., redirect to verify-email page for `EMAIL_NOT_VERIFIED` errors)
## Affected Files
- `frontend/src/lib/axios.ts` — response interceptor
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M1

View File

@@ -0,0 +1,37 @@
---
issue: 021
title: "POST /api/marketplace/offers/:id/withdraw HTTP route does not exist — seller withdraw is dead code"
severity: major
domain: Seller Offer
labels: [missing-feature, backend, frontend, major]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 POST /api/marketplace/offers/:id/withdraw HTTP route does not exist — seller withdraw is dead code
**Severity:** major
**Domain:** Seller Offer
**Labels:** missing-feature, backend, frontend, major
## Description
SellerOfferService.withdrawOffer() method exists (lines 427-443) but no HTTP route calls it. The only way to withdraw is via PUT /offers/:id/status with {status:'withdrawn'} which applies no pending-only guard. No frontend withdraw button or action exists.
## Current Behavior
Sellers have no UI path to withdraw an offer. withdrawOffer() service method is unreachable via HTTP. The route-level withdrawal via PUT /status has no transition guard.
## Expected Behavior
A dedicated withdraw endpoint should be registered, calling withdrawOffer() which enforces the pending-only guard. Or the PUT /offers/:id/status path should enforce status transition guards.
## Affected Files
- `backend/src/routes/routes.ts`
- `frontend/src/actions/marketplace.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 022
title: "GET /api/payment/payments/:id/debug has no authentication — full payment data exposed without credentials"
severity: major
domain: Payment
labels: [security, bug, backend, major, missing-auth]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 GET /api/payment/payments/:id/debug has no authentication — full payment data exposed without credentials
**Severity:** major
**Domain:** Payment
**Labels:** security, bug, backend, major, missing-auth
## Description
GET /api/payment/payments/:id/debug returns payment document plus walletMonitor status without any authentication middleware. Backend code explicitly flags this as a security issue.
## Current Behavior
Any unauthenticated caller can read full payment data including blockchain metadata.
## Expected Behavior
Should require authenticateToken + authorizeRoles('admin').
## Affected Files
- `backend/src/routes/paymentRoutes.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,38 +0,0 @@
---
issue: "022"
title: "Login rate limiter counts all attempts (not just failures) — users can be locked out after correct logins"
severity: major
domain: auth
labels: [backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Login rate limiter counts all attempts (not just failures) — users can be locked out after correct logins
**Severity:** major
**Domain:** auth
**Labels:** backend, bug
## Description
`rateLimitService.checkLoginAttempts()` calls `checkLimit()` which calls `redisService.incr` — incrementing the counter on **every invocation**, before password comparison. The counter is only reset after a full successful login (password verified + session created).
With the limit at 5 attempts/15 min, a user who makes 4 correct logins in quick succession (e.g., testing on multiple devices) followed by 1 wrong password will be locked out immediately, even though they never "failed" 5 times in the intended sense.
## Current Behavior
5 total login attempts within 15 minutes (any combination of correct/incorrect passwords) triggers `429 TOO_MANY_ATTEMPTS`.
## Expected Behavior
The counter should only increment on **failed** password comparison, not on every attempt. Alternatively, the behaviour should be clearly documented so UX can warn users appropriately.
## Affected Files
- `backend/src/services/auth/rateLimitService.ts``checkLoginAttempts` / `checkLimit` — counter increment should move to after password comparison in `authController.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M3

View File

@@ -1,37 +0,0 @@
---
issue: "023"
title: "changePassword action exists but no dashboard UI page exposes it"
severity: major
domain: auth
labels: [frontend, missing-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 changePassword action exists but no dashboard UI page exposes it
**Severity:** major
**Domain:** auth
**Labels:** frontend, missing-feature
## Description
`frontend/src/actions/account.ts` (line ~263) defines `changePassword()` which calls `POST /api/auth/change-password`. The backend endpoint exists and `changePasswordValidation` enforces password complexity (uppercase + lowercase + digit). However, **no dashboard page or component renders a change-password form**. The feature is API-only.
## Current Behavior
Users have no UI path to change their password after login. The only password reset mechanism is the email-based reset flow.
## Expected Behavior
A "Change Password" section in the account settings dashboard (e.g., under `/dashboard/account`) that calls `changePassword()` with `{ currentPassword, newPassword }`.
## Affected Files
- Missing: Change password form component in `/dashboard/account` or `/dashboard/account/security`
- `frontend/src/actions/account.ts``changePassword` function (implemented, no callers)
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M4

View File

@@ -0,0 +1,36 @@
---
issue: 023
title: "GET /api/payment/export has no admin role guard at route level — any authenticated user can export all payment data"
severity: major
domain: Payment
labels: [security, bug, backend, major, privilege-escalation]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 GET /api/payment/export has no admin role guard at route level — any authenticated user can export all payment data
**Severity:** major
**Domain:** Payment
**Labels:** security, bug, backend, major, privilege-escalation
## Description
GET /api/payment/export (controller-pattern route) has only authenticateToken — no admin guard at the router level. The parallel /api/payment/payments/export route has an admin role guard. The frontend hits the non-admin-gated path. Any authenticated buyer can export all payment records.
## Current Behavior
Non-admin buyers can call GET /api/payment/export and receive payment export data for all users.
## Expected Behavior
GET /api/payment/export should apply authorizeRoles('admin') at the route level.
## Affected Files
- `backend/src/routes/paymentRoutes.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 024
title: "GET /api/payment/stats has no admin role guard — any authenticated user can read aggregate payment stats"
severity: major
domain: Payment
labels: [security, bug, backend, major, privilege-escalation]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 GET /api/payment/stats has no admin role guard — any authenticated user can read aggregate payment stats
**Severity:** major
**Domain:** Payment
**Labels:** security, bug, backend, major, privilege-escalation
## Description
GET /api/payment/stats (controller-pattern route) requires only authenticateToken. The /api/payment/payments/stats route requires admin role. Frontend uses the non-admin-gated path.
## Current Behavior
Any authenticated buyer can read aggregate payment platform statistics.
## Expected Behavior
Stats endpoint should be admin-only or return only caller-scoped data for non-admins.
## Affected Files
- `backend/src/routes/paymentRoutes.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,41 +0,0 @@
---
issue: "024"
title: "POST /api/auth/reset-password-with-code accepts weak passwords — no complexity validation"
severity: major
domain: auth
labels: [backend, security, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 POST /api/auth/reset-password-with-code accepts weak passwords — no complexity validation
**Severity:** major
**Domain:** auth
**Labels:** backend, security, bug
## Description
`POST /api/auth/reset-password-with-code` has **no `passwordResetValidation` middleware** (`authRoutes.ts` line ~54-57). The controller only validates that email, code, and password fields are present, and that the code is 6 digits.
Passwords like `'123456'`, `'aaaaaa'`, or `'password'` are accepted.
By contrast, the legacy `POST /api/auth/reset-password` (token-based) is wired with `passwordResetValidation` which enforces `/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/` — at least one uppercase, one lowercase, one digit.
## Current Behavior
`POST /api/auth/reset-password-with-code` with `{ email, code: "123456", password: "aaaaaa" }` → 200, password reset to weak value.
## Expected Behavior
Apply `passwordResetValidation` (or equivalent inline validation) to `reset-password-with-code` as well.
## Affected Files
- `backend/src/routes/authRoutes.ts` — line ~54-57, add `passwordResetValidation` middleware
- `backend/src/shared/middleware/authValidation.ts``passwordResetValidation` definition
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M6

View File

@@ -1,46 +0,0 @@
---
issue: "025"
title: "All dispute socket events are commented-out TODO stubs — no real-time updates in dispute flow"
severity: major
domain: dispute
labels: [backend, missing-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 All dispute socket events are commented-out TODO stubs — no real-time updates in dispute flow
**Severity:** major
**Domain:** dispute
**Labels:** backend, missing-feature
## Description
Every `socket.io` emit block in `DisputeService` is currently commented out as a TODO. No real-time updates fire for any dispute lifecycle event:
- Dispute created
- Admin assigned
- Status changed
- Evidence uploaded
- Resolution posted
The dispute flow is CRUD-only. Any UI component that relies on socket events for real-time dispute state will never receive updates.
## Current Behavior
All dispute state changes are only visible after a manual page refresh.
## Expected Behavior
Implement the socket emit calls for key dispute events:
- `dispute-created` → to buyer, seller, and admin rooms
- `dispute-status-changed` → to involved parties
- `dispute-resolved` → to buyer and seller rooms
## Affected Files
- `backend/src/services/dispute/disputeService.ts` — all commented-out `io.to(...).emit(...)` blocks
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 025
title: "GET /api/disputes/statistics has no admin role guard — any authenticated user can access aggregate dispute KPIs"
severity: major
domain: Dispute
labels: [security, bug, backend, major, privilege-escalation]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 GET /api/disputes/statistics has no admin role guard — any authenticated user can access aggregate dispute KPIs
**Severity:** major
**Domain:** Dispute
**Labels:** security, bug, backend, major, privilege-escalation
## Description
Backend registers GET /api/disputes/statistics with authenticateToken only. No authorizeRoles(admin) guard is applied at the route or controller level. Any authenticated non-admin user can access aggregate dispute platform data.
## Current Behavior
Non-admin authenticated users can call GET /api/disputes/statistics and receive platform-wide KPI data.
## Expected Behavior
Return 403 for non-admin tokens. Apply authorizeRoles('admin') at the route level.
## Affected Files
- `backend/src/routes/disputeRoutes.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 026
title: "GET /notifications/:id only returns user's most-recent notification — all others return 404 erroneously"
severity: major
domain: Notification
labels: [bug, backend, major, broken-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 GET /notifications/:id only returns user's most-recent notification — all others return 404 erroneously
**Severity:** major
**Domain:** Notification
**Labels:** bug, backend, major, broken-feature
## Description
The backend getNotificationById controller calls getUserNotifications(userId, 1, 1) — fetching page 1 with limit 1 — then does an in-memory _id string match. Any notification that is not the single most-recent record for that user always returns 404, regardless of ownership.
## Current Behavior
GET /notifications/:id returns 404 for all notifications except the user's most recently created one.
## Expected Behavior
getNotificationById should perform a direct MongoDB query by _id and userId: Notification.findOne({_id, userId}).
## Affected Files
- `backend/src/controllers/notificationController.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,38 +0,0 @@
---
issue: "026"
title: "'completed' payment status not counted in successfulPayments stats — admin dashboard undercounts"
severity: major
domain: payment
labels: [backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 'completed' payment status not counted in successfulPayments stats — admin dashboard undercounts
**Severity:** major
**Domain:** payment
**Labels:** backend, bug
## Description
`paymentService.getPaymentStats()` aggregate counts only `'confirmed'` as `successfulPayments`. `'completed'` is excluded from this count.
Most SHKeeper payments follow the terminal path: `pending → processing → completed`. `'confirmed'` is a separate RN-specific intermediate state. This means the vast majority of successfully completed payments (SHKeeper + DePay) are **invisible in the `successfulPayments` count** in the admin stats endpoint.
## Current Behavior
Admin dashboard shows a `successfulPayments` count that excludes all `'completed'` status payments. For a platform where SHKeeper is the primary payment provider, this count is close to 0 even when hundreds of payments have succeeded.
## Expected Behavior
`successfulPayments` should count payments in both `'confirmed'` and `'completed'` status, or the aggregate should be documented with a clear note about which statuses are terminal success states.
## Affected Files
- `backend/src/services/payment/paymentService.ts``getPaymentStats()` aggregate pipeline
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M36

View File

@@ -0,0 +1,36 @@
---
issue: 027
title: "confirm-delivery endpoint has no ownership check — any authenticated user can confirm delivery on any request"
severity: major
domain: Delivery
labels: [security, bug, backend, major, authorization]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 confirm-delivery endpoint has no ownership check — any authenticated user can confirm delivery on any request
**Severity:** major
**Domain:** Delivery
**Labels:** security, bug, backend, major, authorization
## Description
marketplaceController.confirmDelivery (line 782) checks dispute gate and status === 'delivery' but does NOT verify the caller is the buyer of the request. Any authenticated user who knows a purchaseRequestId in 'delivery' status can call PATCH /confirm-delivery and advance it to 'delivered'.
## Current Behavior
Sellers, admins, or any authenticated third party can call confirm-delivery and mark a request as delivered without the buyer's involvement.
## Expected Behavior
confirmDelivery should verify req.user.id === purchaseRequest.buyerId before proceeding.
## Affected Files
- `backend/src/controllers/marketplaceController.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,38 +0,0 @@
---
issue: "027"
title: "GET /api/notifications/:id always 404s for non-latest notifications — broken in-memory lookup"
severity: major
domain: notification
labels: [backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 GET /api/notifications/:id always 404s for non-latest notifications — broken in-memory lookup
**Severity:** major
**Domain:** notification
**Labels:** backend, bug
## Description
The `getNotificationById` controller does NOT perform a direct MongoDB `findById` lookup. Instead it calls `getUserNotifications(userId, 1, 1)` — fetching only the user's single most-recent notification — and then does an **in-memory `_id` string comparison**.
Any notification that is not the user's absolute latest record returns `404`, regardless of ownership. This makes the endpoint completely unreliable for any consumer that tries to fetch a specific notification by ID.
## Current Behavior
`GET /api/notifications/abc123` returns the notification only if `abc123` happens to be the user's most recently created notification. For all others: 404.
## Expected Behavior
`getNotificationById` should do a direct `Notification.findOne({ _id: id, userId })` query.
## Affected Files
- `backend/src/services/notification/notificationService.ts` (or controller) — `getNotificationById` / `getUserNotifications` call
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding C22

View File

@@ -0,0 +1,36 @@
---
issue: 028
title: "delivery-code-generated socket event broadcasts raw 6-digit code to entire request room including seller"
severity: major
domain: Delivery
labels: [security, bug, backend, major, delivery]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 delivery-code-generated socket event broadcasts raw 6-digit code to entire request room including seller
**Severity:** major
**Domain:** Delivery
**Labels:** security, bug, backend, major, delivery
## Description
DeliveryService.generateDeliveryCode emits 'delivery-code-generated' with the raw 6-digit code to the room request-{id}. Both buyer and seller are subscribers of this room. A seller with socket access can intercept the code before physical handoff, defeating the security purpose of the code-based handoff verification.
## Current Behavior
DeliveryService.ts line 55 broadcasts {requestId, code, expiresAt, timestamp} to all room subscribers. Seller receives the code via socket before physically receiving the goods.
## Expected Behavior
The code should only be emitted to the buyer's personal room (user-{buyerId}), not the shared request room.
## Affected Files
- `backend/src/services/deliveryService.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,41 +0,0 @@
---
issue: "028"
title: "GET /api/payment/export has no admin role guard — any authenticated user can export payment data"
severity: major
domain: payment
labels: [security, backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 GET /api/payment/export has no admin role guard — any authenticated user can export payment data
**Severity:** major
**Domain:** payment
**Labels:** security, backend, bug
## Description
Two parallel export endpoints exist:
- `GET /api/payment/payments/export` — has `authorizeRoles('admin')` guard (correct)
- `GET /api/payment/export` (controller-pattern route) — only has `authenticateToken`, **no admin guard**
The frontend hits `/payment/export` (the controller-pattern route without the admin guard). Any authenticated buyer can export payment records.
## Current Behavior
`GET /api/payment/export` with any valid user JWT → 200 with payment export data.
## Expected Behavior
`GET /api/payment/export` should require `authorizeRoles('admin')`, or the frontend should be pointed at `/api/payment/payments/export`.
## Affected Files
- Backend: controller-pattern route for `GET /payment/export` — missing `authorizeRoles('admin')`
- `frontend/src/lib/axios.ts``endpoints.payments.export` maps to the wrong route
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M31

View File

@@ -1,46 +0,0 @@
---
issue: "029"
title: "Frontend delivery actions regenerate/attempts/stats call non-existent backend endpoints"
severity: major
domain: delivery
labels: [frontend, missing-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Frontend delivery actions regenerate/attempts/stats call non-existent backend endpoints
**Severity:** major
**Domain:** delivery
**Labels:** frontend, missing-feature
## Description
Three frontend delivery actions hit non-existent backend routes:
| Action | Calls | Status |
|---|---|---|
| `regenerateDeliveryCode` | `POST /delivery-code/regenerate` | 404 (falls back to `/generate`) |
| `getDeliveryAttempts` | `GET /delivery-code/attempts` | 404, throws |
| `getDeliveryStats` | `GET /delivery/stats` | 404, throws |
`regenerateDeliveryCode` silently falls back to the generate endpoint on 404. The other two throw unhandled errors if any component calls them.
## Current Behavior
- Code "regeneration" actually calls generate (new code, ignores regenerate semantic)
- Any UI showing delivery attempt count or stats shows nothing or throws
## Expected Behavior
Either implement the backend routes, or remove the phantom actions and handle their use cases differently.
## Affected Files
- `frontend/src/actions/delivery.ts``regenerateDeliveryCode`, `getDeliveryAttempts`, `getDeliveryStats`
- Backend: missing routes for `/delivery-code/regenerate`, `/delivery-code/attempts`, `/delivery/stats`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M15

View File

@@ -0,0 +1,37 @@
---
issue: 029
title: "No brute-force protection on delivery code verification endpoint — 900,000 combinations are enumerable"
severity: major
domain: Delivery
labels: [security, bug, backend, major, brute-force]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 No brute-force protection on delivery code verification endpoint — 900,000 combinations are enumerable
**Severity:** major
**Domain:** Delivery
**Labels:** security, bug, backend, major, brute-force
## Description
The 6-digit delivery code verify endpoint (routes.ts lines 2790-2847) has no rate limiting, lockout counter, or attempt count maximum. Failed attempts are recorded to deliveryInfo.deliveryAttempts[] but no enforcement exists. A malicious actor could attempt all 900,000 combinations without being blocked.
## Current Behavior
Unlimited guesses are permitted. No rate limiting or lockout is applied to the verify endpoint.
## Expected Behavior
After N failed attempts (e.g., 5), the endpoint should return 429 or lock the code for a period. The deliveryAttempts[] array already tracks attempts — enforcement just needs to be added.
## Affected Files
- `backend/src/routes/routes.ts`
- `backend/src/services/deliveryService.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,36 +0,0 @@
---
issue: "030"
title: "PATCH /confirm-delivery has no ownership check — any authenticated user can confirm delivery"
severity: major
domain: delivery
labels: [backend, security, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 PATCH /confirm-delivery has no ownership check — any authenticated user can confirm delivery
**Severity:** major
**Domain:** delivery
**Labels:** backend, security, bug
## Description
`PATCH /api/marketplace/purchase-requests/:id/confirm-delivery` (the buyer fast-track path to `'delivered'` status) has no ownership or role check. Any authenticated user who knows a purchase request ID can mark it as delivered without possessing the delivery code.
## Current Behavior
`PATCH /purchase-requests/{anyId}/confirm-delivery` with any valid JWT → 200, status set to `'delivered'`.
## Expected Behavior
Should verify `req.user.id === request.buyerId` — only the buyer of that specific request should be able to confirm delivery via this fast-track path.
## Affected Files
- `backend/src/routes/controllerRoutes.ts` or `routes.ts``confirm-delivery` handler missing ownership guard
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 030
title: "POST /api/payment/payments/cleanup-pending admin check is inside handler only — no middleware-level enforcement"
severity: major
domain: Admin
labels: [security, bug, backend, major, missing-auth]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 POST /api/payment/payments/cleanup-pending admin check is inside handler only — no middleware-level enforcement
**Severity:** major
**Domain:** Admin
**Labels:** security, bug, backend, major, missing-auth
## Description
POST /api/payment/payments/cleanup-pending registers only authenticateToken at the route level. Admin check is inside the handler. Any authenticated non-admin who discovers this endpoint can attempt to call it; the in-handler check is the only defense against unauthorized bulk deletion of pending payments.
## Current Behavior
Non-admin authenticated users can call the endpoint; admin gate fires inside handler code rather than at middleware level.
## Expected Behavior
Apply authorizeRoles('admin') middleware at the route level before the handler runs.
## Affected Files
- `backend/src/routes/paymentRoutes.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,47 +0,0 @@
---
issue: "031"
title: "Points/referral system missing 5 frontend pages — redemption, levels, referrals, transactions, admin"
severity: major
domain: points
labels: [frontend, missing-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Points/referral system missing 5 frontend pages — redemption, levels, referrals, transactions, admin
**Severity:** major
**Domain:** points
**Labels:** frontend, missing-feature
## Description
The following routes return 404 because no frontend pages exist:
| Route | Backend Endpoint | Status |
|---|---|---|
| `/dashboard/points/referrals` | `GET /api/points/referrals` | Page missing |
| `/dashboard/points/transactions` | `GET /api/points/transactions` | Page missing |
| `/dashboard/points/levels` | `GET /api/points/levels` | Page missing |
| `/dashboard/points/redeem` (or any UI) | `POST /api/points/redeem` | No redemption UI anywhere |
| Admin points management | `POST /api/points/admin/add` | No admin page |
`redeemPoints()` and `generateReferralCode()` actions are defined but have no call sites in any component.
## Current Behavior
All points features beyond the basic balance display are inaccessible from the UI.
## Expected Behavior
Implement frontend pages for: referral history, transaction history, levels display, points redemption flow, and admin points management.
## Affected Files
- Missing pages in `frontend/src/app/dashboard/points/`
- `frontend/src/actions/points.ts``redeemPoints`, `generateReferralCode` (defined, no callers)
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 031
title: "POST /api/points/admin/add admin check is inside handler only — no middleware-level enforcement"
severity: major
domain: Admin
labels: [security, bug, backend, major, missing-auth]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 POST /api/points/admin/add admin check is inside handler only — no middleware-level enforcement
**Severity:** major
**Domain:** Admin
**Labels:** security, bug, backend, major, missing-auth
## Description
POST /api/points/admin/add registers authenticateToken only at the route level. Admin role check runs inside the handler. This means the handler code runs before the role is verified, creating potential for edge-case bypass.
## Current Behavior
The handler code begins executing for any authenticated user before the role check fires.
## Expected Behavior
Apply authorizeRoles('admin') middleware at the route level.
## Affected Files
- `backend/src/routes/pointsRoutes.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,37 @@
---
issue: 032
title: "Admin delete user via legacy endpoint performs hard delete (findByIdAndDelete) instead of soft delete"
severity: major
domain: User Management
labels: [bug, frontend, backend, major, data-integrity]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Admin delete user via legacy endpoint performs hard delete (findByIdAndDelete) instead of soft delete
**Severity:** major
**Domain:** User Management
**Labels:** bug, frontend, backend, major, data-integrity
## Description
Frontend deleteUser function calls the legacy /users/admin/:id DELETE route which performs findByIdAndDelete (hard delete). The new controller at /api/user/admin/:userId performs a soft delete (status='deleted'). The frontend comment says 'soft delete' but calls the hard-delete route. User records and all associated data are permanently destroyed.
## Current Behavior
Admin 'delete user' action permanently destroys the user record from the database via findByIdAndDelete.
## Expected Behavior
Frontend should call the new controller endpoint /api/user/admin/:userId for soft delete, or the legacy route should be updated to perform a soft delete.
## Affected Files
- `frontend/src/actions/user.ts`
- `frontend/src/lib/axios.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,45 +0,0 @@
---
issue: "032"
title: "SHKeeper release/refund doc paths include erroneous /shkeeper/ segment"
severity: major
domain: payment
labels: [backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 SHKeeper release/refund doc paths include erroneous /shkeeper/ segment
**Severity:** major
**Domain:** payment
**Labels:** backend, bug
## Description
The SHKeeper Payment Flow was documented with `/shkeeper/` in the release/refund paths. The actual backend routes are:
| Documented (wrong) | Actual (correct) |
|---|---|
| `POST /api/payment/shkeeper/:id/release` | `POST /api/payment/:id/release` |
| `POST /api/payment/shkeeper/:id/release/confirm` | `POST /api/payment/:id/release/confirm` |
| `POST /api/payment/shkeeper/:id/refund` | `POST /api/payment/:id/refund` |
| `POST /api/payment/shkeeper/:id/refund/confirm` | `POST /api/payment/:id/refund/confirm` |
The frontend `endpoints.payments.details` maps to `/payment/:id` (correct), so the frontend is unaffected. The issue is in the documentation and any external integration or test harness built from the docs.
## Current Behavior
Calling any `/shkeeper/` path returns 404.
## Expected Behavior
Documentation and any test harnesses should use paths without the `/shkeeper/` segment.
## Affected Files
- Doc file updated: `04 - Flows/Payment Flow - SHKeeper.md`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding C30

View File

@@ -0,0 +1,36 @@
---
issue: 033
title: "Admin can delete other admin accounts via new controller — legacy admin-on-admin protection does not apply"
severity: major
domain: User Management
labels: [security, bug, backend, major, privilege-escalation]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Admin can delete other admin accounts via new controller — legacy admin-on-admin protection does not apply
**Severity:** major
**Domain:** User Management
**Labels:** security, bug, backend, major, privilege-escalation
## Description
The new controller (DELETE /api/user/admin/:userId) only blocks self-deletion. It does not prevent an admin from deleting other admin accounts. The legacy route (DELETE /api/users/admin/:userId) blocks admin-on-admin deletion. The two routes have divergent authorization logic.
## Current Behavior
An admin can delete other admin accounts via the new controller endpoint without a 403 error.
## Expected Behavior
DELETE /api/user/admin/:userId should check if target user has role=admin and return 403 (matching legacy route behavior).
## Affected Files
- `backend/src/controllers/userController.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,42 +0,0 @@
---
issue: "033"
title: "GET seller offer history has no HTTP route — getOffersBySeller() is unreachable dead code"
severity: major
domain: seller-offer
labels: [backend, missing-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 GET seller offer history has no HTTP route — getOffersBySeller() is unreachable dead code
**Severity:** major
**Domain:** seller-offer
**Labels:** backend, missing-feature
## Description
`SellerOfferService.getOffersBySeller()` exists in the service layer but no HTTP route exposes it. The documented endpoint `GET /api/marketplace/offers/seller/:sellerId` does not exist in `routes.ts` or `marketplaceController.ts`.
Notification action URLs that point to `/dashboard/seller/marketplace/offers` are also broken — that frontend page does not exist.
## Current Behavior
- Sellers have no way to view their own offer history via the API
- Notification deep-links to the offers page return 404
## Expected Behavior
1. Register `GET /api/marketplace/offers/seller/:sellerId` (or equivalent scoped route) calling `getOffersBySeller()`
2. Create the frontend page at `/dashboard/seller/marketplace/offers`
3. Fix notification `actionUrl` to point to the real page
## Affected Files
- `backend/src/routes/routes.ts` — missing `GET /offers/seller/:sellerId` route
- Missing: `frontend/src/app/dashboard/shops/` or similar seller offers list page
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M27

View File

@@ -0,0 +1,36 @@
---
issue: 034
title: "All dispute socket.io emit blocks are TODO stubs — no real-time updates fire for any dispute event"
severity: major
domain: Dispute
labels: [missing-feature, backend, major, socket, dispute]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 All dispute socket.io emit blocks are TODO stubs — no real-time updates fire for any dispute event
**Severity:** major
**Domain:** Dispute
**Labels:** missing-feature, backend, major, socket, dispute
## Description
Every socket.io emit block in DisputeService is commented out as TODO. No real-time updates fire for dispute creation, admin assignment, status changes, evidence uploads, or resolution. The flow doc describes real-time presence as a working feature.
## Current Behavior
Zero socket events are emitted from DisputeService. All real-time dispute notifications are silent.
## Expected Behavior
Socket events should be emitted for dispute lifecycle events to keep all parties informed in real time.
## Affected Files
- `backend/src/services/disputeService.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,41 +0,0 @@
---
issue: "034"
title: "SellerOffer 'active' status does not exist in schema — saves with this value throw ValidationError"
severity: major
domain: seller-offer
labels: [backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 SellerOffer 'active' status does not exist in schema — saves with this value throw ValidationError
**Severity:** major
**Domain:** seller-offer
**Labels:** backend, bug
## Description
The Seller Offer Flow doc lists `'active'` as a valid `SellerOffer.status`. The Mongoose schema and TypeScript interface only enumerate:
```
'pending' | 'accepted' | 'rejected' | 'withdrawn'
```
Any code path that attempts to set `SellerOffer.status = 'active'` will throw a Mongoose `ValidationError`. The `createOffer()` service correctly checks `PurchaseRequest.status === 'active'` (a different model's status), but `SellerOffer.status = 'active'` is never valid.
## Current Behavior
`SellerOffer.save()` with `status: 'active'` → Mongoose ValidationError. (Currently no code path actually tries to do this — the bug is latent but would be triggered by misreading the documentation.)
## Expected Behavior
Remove `'active'` from all `SellerOffer` status documentation. The valid states are `pending | accepted | rejected | withdrawn`.
## Affected Files
- Doc file updated: `04 - Flows/Seller Offer Flow.md` and `02 - Data Models/SellerOffer.md`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M22

View File

@@ -0,0 +1,37 @@
---
issue: 035
title: "Frontend getPaymentStatus and confirmPayment call non-existent endpoints GET /payment/:id/status and POST /payment/:id/confirm"
severity: major
domain: Payment
labels: [bug, frontend, major, broken-feature, dispute]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Frontend getPaymentStatus and confirmPayment call non-existent endpoints GET /payment/:id/status and POST /payment/:id/confirm
**Severity:** major
**Domain:** Payment
**Labels:** bug, frontend, major, broken-feature, dispute
## Description
Frontend getPaymentStatus() builds URL as /payment/:id/status and confirmPayment() builds /payment/:id/confirm. Neither endpoint is registered in the backend. getPaymentStatus is actively called from dispute/payment-details-card.tsx line 101 — the 'Verify' button always returns 404.
## Current Behavior
The 'Verify' button in the dispute payment panel always returns 404. confirmPayment() is broken.
## Expected Behavior
Either implement /payment/:id/status and /payment/:id/confirm backend routes, or fix the frontend to use the correct existing payment detail endpoint.
## Affected Files
- `frontend/src/actions/payment.ts`
- `frontend/src/sections/dispute/components/payment-details-card.tsx`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -1,41 +0,0 @@
---
issue: "035"
title: "Dispute payment card 'Verify' button always 404s — getPaymentStatus calls non-existent endpoint"
severity: major
domain: payment
labels: [frontend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Dispute payment card 'Verify' button always 404s — getPaymentStatus calls non-existent endpoint
**Severity:** major
**Domain:** payment
**Labels:** frontend, bug
## Description
`frontend/src/sections/dispute/components/payment-details-card.tsx` (line ~101) calls `getPaymentStatus()` which builds URL as `GET /payment/:id/status`. No `/status` sub-route exists on any payment route in the backend.
The 'Verify' button in the dispute panel is permanently broken in production.
## Current Behavior
Clicking 'Verify' on the dispute payment card → `GET /payment/{id}/status` → 404.
## Expected Behavior
Either:
1. Implement `GET /api/payment/:id/status` on the backend, or
2. Update the component to use the existing `GET /api/payment/:id` endpoint for payment detail fetching
## Affected Files
- `frontend/src/sections/dispute/components/payment-details-card.tsx` — line ~101
- `frontend/src/actions/payment.ts``getPaymentStatus` function
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding C13

View File

@@ -0,0 +1,36 @@
---
issue: 036
title: "cancelPayment action sends DELETE /payment/:id but no DELETE route exists on any payment endpoint"
severity: major
domain: Payment
labels: [bug, frontend, major, broken-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 cancelPayment action sends DELETE /payment/:id but no DELETE route exists on any payment endpoint
**Severity:** major
**Domain:** Payment
**Labels:** bug, frontend, major, broken-feature
## Description
cancelPayment() in src/actions/payment.ts sends DELETE /payment/:id. Backend has no DELETE method on any payment route. The web3 context version is a local state reset, but the action-layer version makes a real HTTP DELETE that will 404.
## Current Behavior
cancelPayment() via the action layer returns 404.
## Expected Behavior
Either implement a DELETE /payment/:id backend route for cancellation, or remove/replace the action-layer cancelPayment with correct API call.
## Affected Files
- `frontend/src/actions/payment.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 037
title: "Frontend initiateRequestNetworkPayout, confirmRequestNetworkPayout, confirmRequestNetworkRelease, confirmRequestNetworkRefund call non-existent backend routes"
severity: major
domain: Payment
labels: [missing-feature, bug, frontend, major, payment, request-network]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Frontend initiateRequestNetworkPayout, confirmRequestNetworkPayout, confirmRequestNetworkRelease, confirmRequestNetworkRefund call non-existent backend routes
**Severity:** major
**Domain:** Payment
**Labels:** missing-feature, bug, frontend, major, payment, request-network
## Description
Four frontend actions in src/actions/payment.ts call /api/payment/request-network/:id/payout/initiate, /payout/confirm, /release/confirm, and /refund/confirm. None of these sub-paths exist in the backend. Admin Request Network payout/release/refund operations are completely broken.
## Current Behavior
All four RN admin payout/release/refund actions return 404.
## Expected Behavior
Backend should implement the four Request Network admin payout/release/refund endpoints, or the frontend actions should be updated to match existing backend routes.
## Affected Files
- `frontend/src/actions/payment.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,37 @@
---
issue: 038
title: "Multiple frontend payment stub actions call non-existent backend endpoints: /payment/history, /payment/methods, /payment/validate, /payment/transactions, /payment/escrow/balance"
severity: major
domain: Payment
labels: [missing-feature, major, frontend, payment]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Multiple frontend payment stub actions call non-existent backend endpoints: /payment/history, /payment/methods, /payment/validate, /payment/transactions, /payment/escrow/balance
**Severity:** major
**Domain:** Payment
**Labels:** missing-feature, major, frontend, payment
## Description
Frontend defines getPaymentHistory, getPaymentMethods, validatePayment, getTransactionHistory, getEscrowBalance — all calling endpoints that have no backend implementation. Any dashboard widget invoking these actions will receive 404 and silently fail or show empty state.
## Current Behavior
All five actions return 404 when called.
## Expected Behavior
Either implement backend routes for these endpoints or remove the stub actions. At minimum, verify no production UI calls them.
## Affected Files
- `frontend/src/actions/payment.ts`
- `frontend/src/lib/axios.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 039
title: "reset-password-with-code endpoint has no password complexity validation — accepts weak passwords rejected by token-based reset"
severity: major
domain: Authentication
labels: [security, bug, backend, major, auth]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 reset-password-with-code endpoint has no password complexity validation — accepts weak passwords rejected by token-based reset
**Severity:** major
**Domain:** Authentication
**Labels:** security, bug, backend, major, auth
## Description
POST /api/auth/reset-password-with-code has no validation middleware (authRoutes.ts:54-56). A new password of '123456' or 'aaaaaa' is accepted. POST /api/auth/reset-password uses passwordResetValidation enforcing uppercase+lowercase+digit. Inconsistent security between the two reset paths.
## Current Behavior
Code-based password reset accepts any non-empty password without complexity requirements.
## Expected Behavior
POST /api/auth/reset-password-with-code should apply the same passwordResetValidation middleware as the token-based reset.
## Affected Files
- `backend/src/routes/authRoutes.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 040
title: "changePassword action has no UI component — change password feature is untestable from the UI"
severity: major
domain: Authentication
labels: [missing-feature, frontend, major]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 changePassword action has no UI component — change password feature is untestable from the UI
**Severity:** major
**Domain:** Authentication
**Labels:** missing-feature, frontend, major
## Description
The changePassword action is implemented in action.ts (line 263) and POST /api/auth/change-password exists on the backend, but no dashboard page or view component calls it. There is no 'Change Password' UI anywhere under /dashboard.
## Current Behavior
Users cannot change their password through the UI. The feature only exists at the API level.
## Expected Behavior
A change-password form should exist in the user dashboard settings.
## Affected Files
- `frontend/src/actions/account.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,37 @@
---
issue: 041
title: "Frontend searchPurchaseRequests calls /marketplace/purchase-requests/search which does not exist in backend"
severity: major
domain: Purchase Request
labels: [bug, frontend, major, broken-feature]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Frontend searchPurchaseRequests calls /marketplace/purchase-requests/search which does not exist in backend
**Severity:** major
**Domain:** Purchase Request
**Labels:** bug, frontend, major, broken-feature
## Description
Frontend defines searchPurchaseRequests pointing to /marketplace/purchase-requests/search. No /search sub-path is registered in backend. Search/filter should be handled via query parameters on the list endpoint GET /purchase-requests.
## Current Behavior
Calling searchPurchaseRequests produces a 404.
## Expected Behavior
searchPurchaseRequests should use GET /marketplace/purchase-requests with filter query parameters instead of a /search sub-path.
## Affected Files
- `frontend/src/actions/marketplace.ts`
- `frontend/src/lib/axios.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,37 @@
---
issue: 042
title: "Frontend getMarketplaceStats calls /marketplace/purchase-requests/stats which has no backend handler"
severity: major
domain: Purchase Request
labels: [missing-feature, frontend, major]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Frontend getMarketplaceStats calls /marketplace/purchase-requests/stats which has no backend handler
**Severity:** major
**Domain:** Purchase Request
**Labels:** missing-feature, frontend, major
## Description
Frontend defines getMarketplaceStats calling /marketplace/purchase-requests/stats. No /stats sub-path under purchase-requests is registered in backend. Any dashboard page calling this will receive a 404.
## Current Behavior
getMarketplaceStats always returns 404.
## Expected Behavior
Backend should implement GET /marketplace/purchase-requests/stats, or the frontend action should be removed and any UI using it should use an alternative.
## Affected Files
- `frontend/src/actions/marketplace.ts`
- `frontend/src/lib/axios.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 043
title: "Frontend getDeliveryAttempts and getDeliveryStats call non-existent backend endpoints"
severity: major
domain: Delivery
labels: [missing-feature, frontend, major]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Frontend getDeliveryAttempts and getDeliveryStats call non-existent backend endpoints
**Severity:** major
**Domain:** Delivery
**Labels:** missing-feature, frontend, major
## Description
getDeliveryAttempts calls /delivery-code/attempts and getDeliveryStats calls /delivery/stats. Neither path is registered in backend. Delivery attempt data exists in deliveryInfo.deliveryAttempts[] but no HTTP route exposes it.
## Current Behavior
Both actions return 404. Any UI calling them silently fails.
## Expected Behavior
Either implement the backend routes or remove the frontend actions and any UI depending on them.
## Affected Files
- `frontend/src/actions/delivery.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 044
title: "POST /api/marketplace/purchase-requests/:id/final-approval creates dummy payment for testing if no real payment exists — testing backdoor in production code"
severity: major
domain: Purchase Request
labels: [security, bug, backend, major, escrow, bypass]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 POST /api/marketplace/purchase-requests/:id/final-approval creates dummy payment for testing if no real payment exists — testing backdoor in production code
**Severity:** major
**Domain:** Purchase Request
**Labels:** security, bug, backend, major, escrow, bypass
## Description
The final-approval endpoint in routes.ts (lines 1561-1592) contains logic that creates a dummy Payment document when no real payment is found and the request is in 'delivered' or 'delivery' status. This testing backdoor is undocumented and bypasses the payment integrity check in production.
## Current Behavior
Any request in delivered/delivery status can be final-approved without a real payment by triggering this code path, effectively releasing escrow for unpaid orders.
## Expected Behavior
The dummy payment creation should be guarded by NODE_ENV !== 'production' or removed entirely from production code.
## Affected Files
- `backend/src/routes/routes.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 045
title: "addParticipants frontend sends { participants: string[] } array but backend expects { userId: string } single user"
severity: major
domain: Chat
labels: [bug, frontend, major, chat]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 addParticipants frontend sends { participants: string[] } array but backend expects { userId: string } single user
**Severity:** major
**Domain:** Chat
**Labels:** bug, frontend, major, chat
## Description
The frontend addParticipants action (chat.ts line 425) sends { participants: string[] } as the body. The API documents POST /api/chat/:id/participants with body { userId: string } — a single user. Backend expects a single userId, not an array. Bulk participant addition will be silently handled incorrectly.
## Current Behavior
addParticipants sends an array payload that the backend does not expect. Participant addition may fail or be ignored.
## Expected Behavior
Frontend should send { userId: string } and call the endpoint once per participant, or backend should be updated to accept an array.
## Affected Files
- `frontend/src/actions/chat.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,37 @@
---
issue: 046
title: "Frontend getSellerOfferHistory / seller offer history page does not exist — notification links to /dashboard/seller/marketplace/offers are broken"
severity: major
domain: Seller Offer
labels: [missing-feature, frontend, backend, major]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Frontend getSellerOfferHistory / seller offer history page does not exist — notification links to /dashboard/seller/marketplace/offers are broken
**Severity:** major
**Domain:** Seller Offer
**Labels:** missing-feature, frontend, backend, major
## Description
No frontend page exists at /dashboard/seller/marketplace/offers. No getSellerOffers() action exists. The backend route GET /api/marketplace/offers/seller/:sellerId also does not exist (getOffersBySeller() service method is dead code via HTTP). Backend notification actionUrls pointing to this path produce broken links.
## Current Behavior
Notification links to the seller offer history are broken. Sellers have no way to view their offer history.
## Expected Behavior
A seller offer history page should exist at /dashboard/seller/marketplace/offers, backed by a proper backend list endpoint for the seller's own offers.
## Affected Files
- `backend/src/routes/routes.ts`
- `backend/src/services/sellerOfferService.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 047
title: "Frontend cron management and per-id token sweep endpoints for derived-destinations are not in backend inventory"
severity: major
domain: Admin
labels: [missing-feature, backend, major, admin]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Frontend cron management and per-id token sweep endpoints for derived-destinations are not in backend inventory
**Severity:** major
**Domain:** Admin
**Labels:** missing-feature, backend, major, admin
## Description
Frontend derived-destinations actions call GET /api/payment/derived-destinations/cron/status, POST /cron/start, POST /cron/stop, and POST /:id/sweep. Backend lists only the bulk sweep and /:id/sweep-native. The cron management and per-id token sweep may be unimplemented. The UI page calls getSweepCronStatus on mount.
## Current Behavior
Opening /dashboard/admin/derived-destinations likely triggers 404 on cron status request on mount.
## Expected Behavior
Backend should implement cron status, start, stop, and per-destination token sweep endpoints, or the frontend should be updated to match what is implemented.
## Affected Files
- `frontend/src/actions/derived-destinations.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 048
title: "Frontend reloadNetworkRegistry and probeChain call backend endpoints that do not exist"
severity: major
domain: Admin
labels: [missing-feature, backend, major, admin]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Frontend reloadNetworkRegistry and probeChain call backend endpoints that do not exist
**Severity:** major
**Domain:** Admin
**Labels:** missing-feature, backend, major, admin
## Description
Frontend network-registry actions call POST /api/admin/rn/networks/reload and POST /api/admin/rn/networks/probe/:chainId. Backend only has GET /api/admin/rn/networks. Reload and probe buttons in the network registry UI silently fail.
## Current Behavior
Reload Registry and Probe Chain UI buttons return 404.
## Expected Behavior
Backend should implement reload and probe endpoints, or the frontend buttons should be removed/disabled.
## Affected Files
- `frontend/src/actions/network-registry.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 049
title: "Frontend getConfirmationThresholdHistory calls GET /api/admin/settings/confirmation-thresholds/history which does not exist in backend"
severity: major
domain: Admin
labels: [missing-feature, backend, major, admin]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Frontend getConfirmationThresholdHistory calls GET /api/admin/settings/confirmation-thresholds/history which does not exist in backend
**Severity:** major
**Domain:** Admin
**Labels:** missing-feature, backend, major, admin
## Description
Frontend confirmation-thresholds action defines getConfirmationThresholdHistory() calling /admin/settings/confirmation-thresholds/history. Backend only lists GET (current values) and PATCH per-chain. No history endpoint is registered.
## Current Behavior
getConfirmationThresholdHistory() returns 404.
## Expected Behavior
Backend should implement a history endpoint for threshold changes, or the frontend action should be removed.
## Affected Files
- `frontend/src/actions/confirmation-thresholds.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 050
title: "Points/Referral: five frontend pages do not exist — redemption, levels, referrals, transactions, admin-add all untestable via UI"
severity: major
domain: Points
labels: [missing-feature, frontend, major, points]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Points/Referral: five frontend pages do not exist — redemption, levels, referrals, transactions, admin-add all untestable via UI
**Severity:** major
**Domain:** Points
**Labels:** missing-feature, frontend, major, points
## Description
The following routes 404: /dashboard/points/referrals, /dashboard/points/transactions, /dashboard/points/levels. redeemPoints is never called from any component. generateReferralCode is never called. adminAddPoints has no admin UI page.
## Current Behavior
All five features are untestable via UI. Backend endpoints exist but are inaccessible through the product.
## Expected Behavior
Frontend pages should be implemented for the above routes and wired to the corresponding backend endpoints.
## Affected Files
- `frontend/src/app/dashboard/points/`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 051
title: "Self-referral prevention is absent — users can refer themselves for points"
severity: major
domain: Points
labels: [security, bug, backend, major, points]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Self-referral prevention is absent — users can refer themselves for points
**Severity:** major
**Domain:** Points
**Labels:** security, bug, backend, major, points
## Description
authController.ts referral attribution logic at lines 704 and 1132 has no self-referral check. Any user who obtains their own referral code and uses it during sign-up will receive a referral reward on their own account.
## Current Behavior
Self-referral is possible. Users can earn referral rewards by using their own code.
## Expected Behavior
Before applying referral attribution, verify that the referrer's userId !== the new user's userId. If they match, skip the reward.
## Affected Files
- `backend/src/controllers/authController.ts`
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)

View File

@@ -0,0 +1,36 @@
---
issue: 052
title: "'completed' payment status not counted in successfulPayments stats — admin dashboard undercounts"
severity: major
domain: Payment
labels: [backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 'completed' payment status not counted in successfulPayments stats — admin dashboard undercounts
**Severity:** major
**Domain:** Payment
**Labels:** backend, bug
## Description
`paymentService.getPaymentStats()` aggregate counts only `'confirmed'` as `successfulPayments`. `'completed'` is excluded. Most SHKeeper/DePay payments follow the terminal path `pending → processing → completed`, so the bulk of successful payments are invisible in the success count.
## Current Behavior
Admin dashboard `successfulPayments` count excludes all `'completed'` payments. For a platform where SHKeeper is the primary provider, this count reads close to zero even after many successful payments.
## Expected Behavior
`successfulPayments` should count both `'confirmed'` and `'completed'` (the terminal success states), or the stat should be clearly documented as confirmed-only.
## Affected Files
- `backend/src/services/payment/paymentService.ts``getPaymentStats()` aggregate pipeline
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M36

View File

@@ -0,0 +1,36 @@
---
issue: 053
title: "Axios interceptor only retriggers token refresh for 401, not 403"
severity: major
domain: Authentication
labels: [frontend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Axios interceptor only retriggers token refresh for 401, not 403
**Severity:** major
**Domain:** Authentication
**Labels:** frontend, bug
## Description
`frontend/src/lib/axios.ts` (line ~105) only triggers the token-refresh flow for `status === 401`. A `403` response (e.g. `EMAIL_NOT_VERIFIED`, blocked account, under-privileged action) is not intercepted — it propagates as an unhandled error and some components may not handle it gracefully.
## Current Behavior
Backend returns `403` → interceptor neither refreshes nor surfaces a meaningful state → error propagates raw to the calling component.
## Expected Behavior
A `403` should NOT trigger a token refresh (it is an authorization failure, not an expired token), but it should be surfaced clearly — e.g. redirect to the verify-email page for `EMAIL_NOT_VERIFIED`. The doc's claim that the interceptor "handles 401/403" should match the code.
## Affected Files
- `frontend/src/lib/axios.ts` — response interceptor (~line 105)
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M1

View File

@@ -0,0 +1,37 @@
---
issue: 054
title: "Login rate limiter counts all attempts (not just failures) — users locked out after correct logins"
severity: major
domain: Authentication
labels: [backend, bug]
status: open
created: 2026-05-29
source: Doc vs Code Audit 2026-05-29
---
# 🟠 Login rate limiter counts all attempts (not just failures) — users locked out after correct logins
**Severity:** major
**Domain:** Authentication
**Labels:** backend, bug
## Description
`rateLimitService.checkLoginAttempts()` calls `checkLimit()``redisService.incr`, incrementing the counter on **every** login invocation, before password comparison. The counter only resets after a fully successful login. So 5 total attempts within 15 min (any mix of correct/incorrect passwords) triggers the lockout — not 5 failures as the docs imply.
## Current Behavior
5 total login attempts within 15 minutes → `429 TOO_MANY_ATTEMPTS`, even if some attempts used the correct password.
## Expected Behavior
The counter should increment only on a **failed** password comparison, not on every attempt. Otherwise document the actual behaviour so UX warns users appropriately.
## Affected Files
- `backend/src/services/auth/rateLimitService.ts``checkLoginAttempts` / `checkLimit`
- `backend/src/controllers/authController.ts` — move the increment to after password comparison
## References
- [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md) — Finding M3

View File

@@ -1,59 +1,70 @@
# Issues Index
> Generated from Doc vs Code Audit — 2026-05-29
> **35 open issues** | 🔴 14 critical · 🟠 19 major · 🟡 2 minor
> Generated from Doc vs Code Audit — 2026-05-29 · last reconciled 2026-05-29
> **53 open issues** | 🔴 14 critical · 🟠 39 major · 🟡 0 minor · ⚪ 1 invalid (stale audit)
## 🔴 Critical
- [[ISSUE-001-dispute-status-no-role-guard|PATCH /api/disputes/:id/status no role guard — privilege escalation]] — `dispute` · security
- [[ISSUE-002-dispute-resolve-no-role-guard|POST /api/disputes/:id/resolve no role guard — any user can resolve + ban sellers]] — `dispute` · security
- [[ISSUE-003-dispute-route-shadowing|Route shadowing: two dispute routers at /api/disputes wrong handler fires]] — `dispute`
- [[ISSUE-004-payment-endpoints-no-auth|fetch-tx, auto-fetch-missing, debug payment endpoints have no authentication]] — `payment` · security
- [[ISSUE-005-scanner-status-no-auth|GET /api/admin/scanner/status has no authentication]] — `admin` · security
- [[ISSUE-006-delete-account-wrong-endpoint|Frontend deleteAccount calls DELETE /user/profile — endpoint doesn't exist]] — `auth`
- [[ISSUE-007-sim-bypass-no-env-guard|SIM_ transaction bypass active in production — no NODE_ENV guard]] — `payment` · security
- [[ISSUE-008-chat-file-upload-wrong-endpoint|sendFileMessage posts to wrong endpoint — chat file uploads always fail]] — `chat`
- [[ISSUE-010-admin-user-status-wrong-values-and-verb|Admin user status/role broken: wrong HTTP verb + wrong status values]] — `admin`
- [[ISSUE-016-payment-provider-routing-always-request-network|createProviderPaymentIntent always routes to request-network — SHKeeper broken]] — `payment`
- [[ISSUE-018-trezor-no-frontend-implementation|Trezor Safekeeping has zero frontend implementation]] — `trezor`
- [[ISSUE-020-dispute-assign-no-role-guard|POST /api/disputes/:id/assign no role guard — any user can self-assign mediator]] — `dispute` · security
- [[ISSUE-030-confirm-delivery-no-auth-guard|PATCH /confirm-delivery no ownership check — any user can confirm delivery]] — `delivery` · security
- [[ISSUE-035-payment-dispute-verify-button-404|Dispute 'Verify' button always 404s — getPaymentStatus hits non-existent endpoint]] — `payment`
- [[ISSUE-001-patch-api-disputes-id-status-and-post-api-disputes-id-resolv|PATCH /api/disputes/:id/status and POST /api/disputes/:id/resolve have no role guard — privilege escalation]] — `Dispute`
- [[ISSUE-002-post-api-disputes-id-assign-has-no-role-guard-any-user-can-s|POST /api/disputes/:id/assign has no role guard — any user can self-assign as admin]] — `Dispute`
- [[ISSUE-003-route-shadowing-post-api-disputes-purchaserequestid-resolve-|Route shadowing: POST /api/disputes/:purchaseRequestId/resolve matches dashboard router first and executes wrong handler]] — `Dispute`
- [[ISSUE-004-post-api-disputes-id-resolve-dashboard-does-not-trigger-escr|POST /api/disputes/:id/resolve (dashboard) does not trigger escrow release — only updates Dispute model]] — `Dispute`
- [[ISSUE-005-post-api-payment-payments-id-fetch-tx-post-api-payment-payme|POST /api/payment/payments/:id/fetch-tx, POST /api/payment/payments/auto-fetch-missing, and GET /api/payment/payments/:id/debug have no authentication middleware]] — `Payment`
- [[ISSUE-006-get-api-admin-scanner-status-has-no-authentication-middlewar|GET /api/admin/scanner/status has no authentication middleware despite /api/admin/ prefix]] — `Admin`
- [[ISSUE-007-frontend-deleteaccount-action-calls-delete-user-profile-whic|Frontend deleteAccount action calls DELETE /user/profile which has no backend route — account deletion is broken]] — `Authentication`
- [[ISSUE-008-sendfilemessage-posts-to-wrong-endpoint-file-uploads-silentl|sendFileMessage posts to wrong endpoint — file uploads silently fail or corrupt text-message handler]] — `Chat`
- [[ISSUE-009-archiveconversation-sends-put-but-backend-only-accepts-patch|archiveConversation sends PUT but backend only accepts PATCH — all archive attempts fail]] — `Chat`
- [[ISSUE-010-frontend-admin-updateuserstatus-and-updateuserrole-use-put-b|Frontend admin updateUserStatus and updateUserRole use PUT but backend only accepts PATCH]] — `User Management`
- [[ISSUE-011-frontend-updateuserstatus-sends-inactive-pending-status-valu|Frontend updateUserStatus sends 'inactive'/'pending' status values that backend does not accept]] — `User Management`
- [[ISSUE-013-createproviderpaymentintent-always-routes-to-request-network|createProviderPaymentIntent always routes to request-network/intents regardless of provider argument]] — `Payment`
- [[ISSUE-014-paymentprovider-typescript-type-excludes-shkeeper-and-decent|PaymentProvider TypeScript type excludes 'shkeeper' and 'decentralized' causing UI fallthrough for main payment providers]] — `Payment`
- [[ISSUE-015-simulated-transaction-sim-bypass-has-no-environment-guard-ca|Simulated transaction SIM_ bypass has no environment guard — can fire in production on wallet connection failure]] — `Payment`
## 🟠 Major
- [[ISSUE-009-archive-chat-wrong-method|archiveConversation uses PUT but backend only accepts PATCH]] — `chat`
- [[ISSUE-011-update-purchase-request-put-vs-patch|updatePurchaseRequest sends PUT but backend only accepts PATCH]] — `purchase-request`
- [[ISSUE-012-update-offer-put-vs-patch|updateOffer sends PUT but backend registers PATCH]] — `seller-offer`
- [[ISSUE-013-select-offer-no-status-filter-corrupts-withdrawn|select-offer cascade overwrites withdrawn offers — missing status filter]] — `seller-offer` · data-integrity
- [[ISSUE-014-select-offer-no-seller-notifications|select-offer sends no per-seller notifications to winning/losing sellers]] — `seller-offer`
- [[ISSUE-015-seller-offer-withdraw-no-http-route|Seller offer withdraw has no HTTP route withdrawOffer() is dead code]] — `seller-offer`
- [[ISSUE-017-payment-provider-type-missing-values|PaymentProvider TypeScript type missing 'shkeeper' and 'decentralized']] — `payment`
- [[ISSUE-019-rn-payout-release-refund-not-implemented|Request Network admin payout/release/refund sub-routes do not exist]] — `payment`
- [[ISSUE-021-axios-interceptor-403-not-handled|Axios interceptor only retriggers token refresh for 401, not 403]] — `auth`
- [[ISSUE-022-rate-limit-counts-all-attempts|Login rate limiter counts all attempts — users locked out after correct logins]] — `auth`
- [[ISSUE-023-change-password-no-ui|changePassword action exists but no dashboard UI page]] — `auth`
- [[ISSUE-024-reset-password-with-code-no-complexity-check|POST /api/auth/reset-password-with-code accepts weak passwords]] — `auth` · security
- [[ISSUE-025-dispute-socket-events-all-stubs|All dispute socket events are TODO stubs — no real-time updates]] — `dispute`
- [[ISSUE-026-payment-completed-not-counted-in-stats|'completed' payment not counted in successfulPaymentsadmin dashboard undercounts]] — `payment`
- [[ISSUE-027-get-notification-by-id-broken|GET /api/notifications/:id always 404s for non-latest notifications]] — `notification`
- [[ISSUE-028-payment-export-no-admin-guard|GET /api/payment/export has no admin guard — any user can export payments]] — `payment` · security
- [[ISSUE-029-delivery-attempts-stats-phantom-endpoints|Frontend delivery actions regenerate/attempts/stats hit non-existent endpoints]] — `delivery`
- [[ISSUE-031-points-missing-frontend-pages|Points/referral missing 5 frontend pages — redemption, levels, referrals, transactions, admin]] — `points`
- [[ISSUE-032-shkeeper-release-refund-wrong-paths|SHKeeper release/refund doc paths include erroneous /shkeeper/ segment]] — `payment`
- [[ISSUE-033-seller-offer-history-route-missing|GET seller offer history has no HTTP route — getOffersBySeller() is dead code]] — `seller-offer`
- [[ISSUE-034-seller-offer-active-status-invalid|SellerOffer 'active' status invalid — saves throw ValidationError]] — `seller-offer`
- [[ISSUE-016-updatepurchaserequest-uses-put-but-backend-only-registers-pa|updatePurchaseRequest uses PUT but backend only registers PATCH — all purchase request edits fail]] — `Purchase Request`
- [[ISSUE-017-updateoffer-uses-put-marketplace-offers-id-but-backend-regis|updateOffer uses PUT /marketplace/offers/:id but backend registers PATCH /offers/:id — offer edits fail]] — `Seller Offer`
- [[ISSUE-018-select-offer-updatemany-has-no-status-filter-overwrites-with|select-offer updateMany has no status filter — overwrites withdrawn/rejected offers back to 'rejected' corrupting status history]] — `Seller Offer`
- [[ISSUE-019-selleroffer-status-active-does-not-exist-in-schema-enum-but-|SellerOffer.status 'active' does not exist in schema enum but is referenced in docs and code comments]] — `Seller Offer`
- [[ISSUE-020-select-offer-does-not-send-per-seller-socket-events-or-notif|select-offer does not send per-seller socket events or notifications to winning or losing sellers]] — `Seller Offer`
- [[ISSUE-021-post-api-marketplace-offers-id-withdraw-http-route-does-not-|POST /api/marketplace/offers/:id/withdraw HTTP route does not exist — seller withdraw is dead code]] — `Seller Offer`
- [[ISSUE-022-get-api-payment-payments-id-debug-has-no-authentication-full|GET /api/payment/payments/:id/debug has no authentication — full payment data exposed without credentials]] — `Payment`
- [[ISSUE-023-get-api-payment-export-has-no-admin-role-guard-at-route-leve|GET /api/payment/export has no admin role guard at route level — any authenticated user can export all payment data]] — `Payment`
- [[ISSUE-024-get-api-payment-stats-has-no-admin-role-guard-any-authentica|GET /api/payment/stats has no admin role guard — any authenticated user can read aggregate payment stats]] — `Payment`
- [[ISSUE-025-get-api-disputes-statistics-has-no-admin-role-guard-any-auth|GET /api/disputes/statistics has no admin role guard — any authenticated user can access aggregate dispute KPIs]] — `Dispute`
- [[ISSUE-026-get-notifications-id-only-returns-user-s-most-recent-notific|GET /notifications/:id only returns user's most-recent notification — all others return 404 erroneously]] — `Notification`
- [[ISSUE-027-confirm-delivery-endpoint-has-no-ownership-check-any-authent|confirm-delivery endpoint has no ownership check — any authenticated user can confirm delivery on any request]] — `Delivery`
- [[ISSUE-028-delivery-code-generated-socket-event-broadcasts-raw-6-digit-|delivery-code-generated socket event broadcasts raw 6-digit code to entire request room including seller]] — `Delivery`
- [[ISSUE-029-no-brute-force-protection-on-delivery-code-verification-endp|No brute-force protection on delivery code verification endpoint — 900,000 combinations are enumerable]] — `Delivery`
- [[ISSUE-030-post-api-payment-payments-cleanup-pending-admin-check-is-ins|POST /api/payment/payments/cleanup-pending admin check is inside handler only — no middleware-level enforcement]] — `Admin`
- [[ISSUE-031-post-api-points-admin-add-admin-check-is-inside-handler-only|POST /api/points/admin/add admin check is inside handler only — no middleware-level enforcement]] — `Admin`
- [[ISSUE-032-admin-delete-user-via-legacy-endpoint-performs-hard-delete-f|Admin delete user via legacy endpoint performs hard delete (findByIdAndDelete) instead of soft delete]] — `User Management`
- [[ISSUE-033-admin-can-delete-other-admin-accounts-via-new-controller-leg|Admin can delete other admin accounts via new controller — legacy admin-on-admin protection does not apply]] — `User Management`
- [[ISSUE-034-all-dispute-socket-io-emit-blocks-are-todo-stubs-no-real-tim|All dispute socket.io emit blocks are TODO stubs — no real-time updates fire for any dispute event]] — `Dispute`
- [[ISSUE-035-frontend-getpaymentstatus-and-confirmpayment-call-non-existe|Frontend getPaymentStatus and confirmPayment call non-existent endpoints GET /payment/:id/status and POST /payment/:id/confirm]] — `Payment`
- [[ISSUE-036-cancelpayment-action-sends-delete-payment-id-but-no-delete-r|cancelPayment action sends DELETE /payment/:id but no DELETE route exists on any payment endpoint]] — `Payment`
- [[ISSUE-037-frontend-initiaterequestnetworkpayout-confirmrequestnetworkp|Frontend initiateRequestNetworkPayout, confirmRequestNetworkPayout, confirmRequestNetworkRelease, confirmRequestNetworkRefund call non-existent backend routes]] — `Payment`
- [[ISSUE-038-multiple-frontend-payment-stub-actions-call-non-existent-bac|Multiple frontend payment stub actions call non-existent backend endpoints: /payment/history, /payment/methods, /payment/validate, /payment/transactions, /payment/escrow/balance]] — `Payment`
- [[ISSUE-039-reset-password-with-code-endpoint-has-no-password-complexity|reset-password-with-code endpoint has no password complexity validation — accepts weak passwords rejected by token-based reset]] — `Authentication`
- [[ISSUE-040-changepassword-action-has-no-ui-component-change-password-fe|changePassword action has no UI component — change password feature is untestable from the UI]] — `Authentication`
- [[ISSUE-041-frontend-searchpurchaserequests-calls-marketplace-purchase-r|Frontend searchPurchaseRequests calls /marketplace/purchase-requests/search which does not exist in backend]] — `Purchase Request`
- [[ISSUE-042-frontend-getmarketplacestats-calls-marketplace-purchase-requ|Frontend getMarketplaceStats calls /marketplace/purchase-requests/stats which has no backend handler]] — `Purchase Request`
- [[ISSUE-043-frontend-getdeliveryattempts-and-getdeliverystats-call-non-e|Frontend getDeliveryAttempts and getDeliveryStats call non-existent backend endpoints]] — `Delivery`
- [[ISSUE-044-post-api-marketplace-purchase-requests-id-final-approval-cre|POST /api/marketplace/purchase-requests/:id/final-approval creates dummy payment for testing if no real payment exists — testing backdoor in production code]] — `Purchase Request`
- [[ISSUE-045-addparticipants-frontend-sends-participants-string-array-but|addParticipants frontend sends { participants: string[] } array but backend expects { userId: string } single user]] — `Chat`
- [[ISSUE-046-frontend-getsellerofferhistory-seller-offer-history-page-doe|Frontend getSellerOfferHistory / seller offer history page does not exist — notification links to /dashboard/seller/marketplace/offers are broken]] — `Seller Offer`
- [[ISSUE-047-frontend-cron-management-and-per-id-token-sweep-endpoints-fo|Frontend cron management and per-id token sweep endpoints for derived-destinations are not in backend inventory]] — `Admin`
- [[ISSUE-048-frontend-reloadnetworkregistry-and-probechain-call-backend-e|Frontend reloadNetworkRegistry and probeChain call backend endpoints that do not exist]] — `Admin`
- [[ISSUE-049-frontend-getconfirmationthresholdhistory-calls-get-api-admin|Frontend getConfirmationThresholdHistory calls GET /api/admin/settings/confirmation-thresholds/history which does not exist in backend]] — `Admin`
- [[ISSUE-050-points-referral-five-frontend-pages-do-not-exist-redemption-|Points/Referral: five frontend pages do not exist — redemption, levels, referrals, transactions, admin-add all untestable via UI]] — `Points`
- [[ISSUE-051-self-referral-prevention-is-absent-users-can-refer-themselve|Self-referral prevention is absent — users can refer themselves for points]] — `Points`
- [[ISSUE-052-payment-completed-status-not-counted-in-successful-payments-stats|'completed' payment status not counted in successfulPayments stats — admin dashboard undercounts]] — `Payment`
- [[ISSUE-053-axios-interceptor-only-handles-401-not-403-for-token-refresh|Axios interceptor only retriggers token refresh for 401, not 403]] — `Authentication`
- [[ISSUE-054-login-rate-limiter-counts-all-attempts-not-only-failures|Login rate limiter counts all attempts (not just failures) — users locked out after correct logins]] — `Authentication`
## Security Issues Summary
## ⚪ Invalid / Superseded (audit was stale vs current code)
- [[ISSUE-012-trezor-safekeeping-zero-frontend-implementation-all-admin-re|Trezor Safekeeping "zero frontend" — INVALID: the frontend Trezor implementation exists in current code (TrezorSettingsView, trezorConnector, TrezorSignDialog, actions/trezor.ts). Audit findings C31/C32 were from an older snapshot.]] — `Trezor`
## 🟡 Minor
| # | Issue | Severity |
|---|---|---|
| 001 | Dispute status PATCH — no role guard (privilege escalation) | 🔴 Critical |
| 002 | Dispute resolve POST — no role guard (ban_seller without auth) | 🔴 Critical |
| 004 | Payment fetch-tx/auto-fetch/debug — no authentication | 🔴 Critical |
| 005 | Admin scanner status — no authentication | 🔴 Critical |
| 007 | SIM_ bypass active in production | 🔴 Critical |
| 020 | Dispute assign — no role guard | 🔴 Critical |
| 030 | confirm-delivery — no ownership check | 🔴 Critical |
| 024 | reset-password-with-code — no complexity validation | 🟠 Major |
| 028 | Payment export — no admin guard | 🟠 Major |