Complete task 4 backend security architecture docs
This commit is contained in:
@@ -337,7 +337,7 @@
|
|||||||
"details": "Source audit: .taskmaster/docs/audit-backend-stack-security-and-refactor-assessment-2026-05-24.md. This task is advisory/architecture-focused and should run in parallel with immediate hardening. It should produce the decision artifacts needed before any backend-core rewrite or provider migration is started.",
|
"details": "Source audit: .taskmaster/docs/audit-backend-stack-security-and-refactor-assessment-2026-05-24.md. This task is advisory/architecture-focused and should run in parallel with immediate hardening. It should produce the decision artifacts needed before any backend-core rewrite or provider migration is started.",
|
||||||
"testStrategy": "Review and sign off each architecture document with backend, payments, frontend, and operations stakeholders. Confirm every open question has an owner or explicit deferred decision before implementation work begins.",
|
"testStrategy": "Review and sign off each architecture document with backend, payments, frontend, and operations stakeholders. Confirm every open question has an owner or explicit deferred decision before implementation work begins.",
|
||||||
"priority": "high",
|
"priority": "high",
|
||||||
"status": "in-progress",
|
"status": "done",
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"subtasks": [
|
"subtasks": [
|
||||||
{
|
{
|
||||||
@@ -371,52 +371,56 @@
|
|||||||
"title": "Specify funds ledger and escrow state machine",
|
"title": "Specify funds ledger and escrow state machine",
|
||||||
"description": "Define canonical money movement and legal state transitions before refactor or provider migration.",
|
"description": "Define canonical money movement and legal state transitions before refactor or provider migration.",
|
||||||
"details": "Create specs for FundsAccount, LedgerEntry, FundsBalance, gross paid, provider fees, platform fees, held, disputed, releasable, released, refunded, idempotency keys, reconciliation behavior, purchase request states, payment states, escrow/funds states, dispute states, valid transitions, forbidden transitions, and release/refund/admin override preconditions.",
|
"details": "Create specs for FundsAccount, LedgerEntry, FundsBalance, gross paid, provider fees, platform fees, held, disputed, releasable, released, refunded, idempotency keys, reconciliation behavior, purchase request states, payment states, escrow/funds states, dispute states, valid transitions, forbidden transitions, and release/refund/admin override preconditions.",
|
||||||
"status": "pending",
|
"status": "done",
|
||||||
"priority": "high",
|
"priority": "high",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
2
|
2
|
||||||
],
|
],
|
||||||
"testStrategy": "Spec can be used to reject double-release, release-during-dispute, underfunded payout, and ambiguous provider-event scenarios.",
|
"testStrategy": "Spec can be used to reject double-release, release-during-dispute, underfunded payout, and ambiguous provider-event scenarios.",
|
||||||
"parentId": "undefined"
|
"parentId": "undefined",
|
||||||
|
"updatedAt": "2026-05-24T07:23:41.596Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 4,
|
"id": 4,
|
||||||
"title": "Create authorization matrix for REST and Socket.IO",
|
"title": "Create authorization matrix for REST and Socket.IO",
|
||||||
"description": "Map every endpoint and realtime event to access level, ownership checks, state preconditions, rate-limit tier, and audit-log requirement.",
|
"description": "Map every endpoint and realtime event to access level, ownership checks, state preconditions, rate-limit tier, and audit-log requirement.",
|
||||||
"details": "Include public/authenticated/owner/buyer/seller/admin/support/service-role classifications. Socket.IO rooms must be server-derived from authenticated identity, not client-supplied user IDs.",
|
"details": "Include public/authenticated/owner/buyer/seller/admin/support/service-role classifications. Socket.IO rooms must be server-derived from authenticated identity, not client-supplied user IDs.",
|
||||||
"status": "pending",
|
"status": "done",
|
||||||
"priority": "high",
|
"priority": "high",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
2
|
2
|
||||||
],
|
],
|
||||||
"testStrategy": "No route or socket event remains unmapped; implementation tasks can reference matrix rows directly.",
|
"testStrategy": "No route or socket event remains unmapped; implementation tasks can reference matrix rows directly.",
|
||||||
"parentId": "undefined"
|
"parentId": "undefined",
|
||||||
|
"updatedAt": "2026-05-24T07:23:43.108Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 5,
|
"id": 5,
|
||||||
"title": "Decide session, passkey, and admin step-up architecture",
|
"title": "Decide session, passkey, and admin step-up architecture",
|
||||||
"description": "Choose browser session model and high-risk admin authentication requirements.",
|
"description": "Choose browser session model and high-risk admin authentication requirements.",
|
||||||
"details": "Decide localStorage versus httpOnly cookies, access/refresh token lifetimes, CSRF strategy, refresh rotation, WebAuthn requirements, OAuth requirements, device/session revocation, and whether payouts/role changes require step-up authentication or two-person approval.",
|
"details": "Decide localStorage versus httpOnly cookies, access/refresh token lifetimes, CSRF strategy, refresh rotation, WebAuthn requirements, OAuth requirements, device/session revocation, and whether payouts/role changes require step-up authentication or two-person approval.",
|
||||||
"status": "pending",
|
"status": "done",
|
||||||
"priority": "high",
|
"priority": "high",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
2
|
2
|
||||||
],
|
],
|
||||||
"testStrategy": "Decision record lists chosen model, rejected alternatives, migration cost, and required implementation tasks.",
|
"testStrategy": "Decision record lists chosen model, rejected alternatives, migration cost, and required implementation tasks.",
|
||||||
"parentId": "undefined"
|
"parentId": "undefined",
|
||||||
|
"updatedAt": "2026-05-24T07:23:44.643Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 6,
|
"id": 6,
|
||||||
"title": "Specify webhook security and provider adapter contracts",
|
"title": "Specify webhook security and provider adapter contracts",
|
||||||
"description": "Define provider-neutral payment interface and signed webhook processing rules.",
|
"description": "Define provider-neutral payment interface and signed webhook processing rules.",
|
||||||
"details": "Document createPayInIntent, getPayInStatus, handleProviderWebhook, createHostedPaymentLink, createReleaseInstruction, createRefundInstruction, getPayoutStatus, searchProviderPayments, raw-body signature verification, replay prevention, delivery ID idempotency, duplicate/unknown event behavior, retry semantics, dead-letter/replay storage, and alert thresholds.",
|
"details": "Document createPayInIntent, getPayInStatus, handleProviderWebhook, createHostedPaymentLink, createReleaseInstruction, createRefundInstruction, getPayoutStatus, searchProviderPayments, raw-body signature verification, replay prevention, delivery ID idempotency, duplicate/unknown event behavior, retry semantics, dead-letter/replay storage, and alert thresholds.",
|
||||||
"status": "pending",
|
"status": "done",
|
||||||
"priority": "high",
|
"priority": "high",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
3
|
3
|
||||||
],
|
],
|
||||||
"testStrategy": "Contracts cover SHKeeper legacy, Request Network, manual/admin wallet, invalid signatures, duplicate deliveries, and missed webhook reconciliation.",
|
"testStrategy": "Contracts cover SHKeeper legacy, Request Network, manual/admin wallet, invalid signatures, duplicate deliveries, and missed webhook reconciliation.",
|
||||||
"parentId": "undefined"
|
"parentId": "undefined",
|
||||||
|
"updatedAt": "2026-05-24T07:21:42.699Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 7,
|
"id": 7,
|
||||||
@@ -437,7 +441,7 @@
|
|||||||
"title": "Make backend-core stack decision",
|
"title": "Make backend-core stack decision",
|
||||||
"description": "Choose whether the security-critical backend core remains TypeScript or moves to Go/Kotlin/Rust/Python.",
|
"description": "Choose whether the security-critical backend core remains TypeScript or moves to Go/Kotlin/Rust/Python.",
|
||||||
"details": "Evaluate team capability, two-year maintainability, operational footprint, rewrite cost, dual-stack complexity, auditability, supply-chain exposure, and which modules belong in a payment/auth/escrow core versus the existing marketplace/chat API.",
|
"details": "Evaluate team capability, two-year maintainability, operational footprint, rewrite cost, dual-stack complexity, auditability, supply-chain exposure, and which modules belong in a payment/auth/escrow core versus the existing marketplace/chat API.",
|
||||||
"status": "pending",
|
"status": "done",
|
||||||
"priority": "medium",
|
"priority": "medium",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
2,
|
2,
|
||||||
@@ -448,23 +452,25 @@
|
|||||||
7
|
7
|
||||||
],
|
],
|
||||||
"testStrategy": "Architecture decision record states chosen stack, scope of extraction, non-goals, migration phases, rollback criteria, and owners.",
|
"testStrategy": "Architecture decision record states chosen stack, scope of extraction, non-goals, migration phases, rollback criteria, and owners.",
|
||||||
"parentId": "undefined"
|
"parentId": "undefined",
|
||||||
|
"updatedAt": "2026-05-24T07:21:45.258Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 9,
|
"id": 9,
|
||||||
"title": "Create migration and operational runbooks",
|
"title": "Create migration and operational runbooks",
|
||||||
"description": "Document rollout, rollback, and incident response for the selected backend/funds architecture.",
|
"description": "Document rollout, rollback, and incident response for the selected backend/funds architecture.",
|
||||||
"details": "Include SHKeeper legacy read path, provider feature flag, ledger backfill, validation report before enforcement, rollback criteria, webhook cutoff, manual reconciliation, failed webhook, duplicate/missing payment, stuck release, disputed release attempt, compromised admin, leaked API key, provider outage, chain/RPC outage, suspicious payment proof, and npm/package compromise.",
|
"details": "Include SHKeeper legacy read path, provider feature flag, ledger backfill, validation report before enforcement, rollback criteria, webhook cutoff, manual reconciliation, failed webhook, duplicate/missing payment, stuck release, disputed release attempt, compromised admin, leaked API key, provider outage, chain/RPC outage, suspicious payment proof, and npm/package compromise.",
|
||||||
"status": "pending",
|
"status": "done",
|
||||||
"priority": "medium",
|
"priority": "medium",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
8
|
8
|
||||||
],
|
],
|
||||||
"testStrategy": "Runbooks identify owner, trigger, detection signal, immediate action, recovery action, and post-incident documentation for each scenario.",
|
"testStrategy": "Runbooks identify owner, trigger, detection signal, immediate action, recovery action, and post-incident documentation for each scenario.",
|
||||||
"parentId": "undefined"
|
"parentId": "undefined",
|
||||||
|
"updatedAt": "2026-05-24T07:21:47.810Z"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"updatedAt": "2026-05-24T06:43:04.699Z"
|
"updatedAt": "2026-05-24T07:23:44.643Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "5",
|
"id": "5",
|
||||||
@@ -612,12 +618,12 @@
|
|||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"lastModified": "2026-05-24T07:04:01.906Z",
|
"lastModified": "2026-05-24T07:23:44.643Z",
|
||||||
"taskCount": 5,
|
"taskCount": 5,
|
||||||
"completedCount": 2,
|
"completedCount": 4,
|
||||||
"tags": [
|
"tags": [
|
||||||
"master"
|
"master"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
---
|
||||||
|
title: Backend Funds Migration and Operational Runbooks
|
||||||
|
tags: [operations, payments, migration, incidents]
|
||||||
|
created: 2026-05-24
|
||||||
|
---
|
||||||
|
|
||||||
|
# Backend Funds Migration and Operational Runbooks
|
||||||
|
|
||||||
|
These runbooks cover the selected backend/funds architecture defined in
|
||||||
|
[[Backend Core Stack Decision Record - 2026-05-24]].
|
||||||
|
|
||||||
|
## 1. Migration runbook (legacy + provider migration)
|
||||||
|
|
||||||
|
### 1.1 Preflight
|
||||||
|
|
||||||
|
1. Verify provider credentials and webhook secrets are present in production `.env`.
|
||||||
|
2. Confirm canonical state docs are published and approved:
|
||||||
|
- [[Funds Ledger and Escrow State Machine Specification]]
|
||||||
|
- [[Payment Provider Adapter Spec]]
|
||||||
|
- [[Webhook Security Spec]]
|
||||||
|
3. Run validation report:
|
||||||
|
- count of legacy `Payment` rows by provider,
|
||||||
|
- duplicate provider keys,
|
||||||
|
- webhook processing success/error by provider (24h),
|
||||||
|
- unresolved `pending`/`processing` payments older than 30m.
|
||||||
|
4. Run a staging reconciliation simulation against a read-only copy.
|
||||||
|
|
||||||
|
### 1.2 Rollout sequence
|
||||||
|
|
||||||
|
1. Keep `PAYMENT_MODE=read_only` and keep SHKeeper intent path active.
|
||||||
|
2. Enable legacy+new provider dual routing via `PAYMENT_ENABLED_PROVIDERS`.
|
||||||
|
3. Activate adapter contract metrics (`payment-provider-events` and webhook counters) before any write routing.
|
||||||
|
4. Set `PAYMENT_PROVIDER_MODE=standard` for a 10–15% cohort.
|
||||||
|
5. Expand to full traffic only after two clean 24h windows.
|
||||||
|
|
||||||
|
### 1.3 Legacy read path and backfill
|
||||||
|
|
||||||
|
- Keep SHKeeper legacy read path enabled for at least one billing cycle after migration starts.
|
||||||
|
- Backfill task:
|
||||||
|
- map legacy SHKeeper records into `FundsAccount` references,
|
||||||
|
- write reconciliation notes into `metadata.providers`,
|
||||||
|
- leave source payment rows immutable.
|
||||||
|
- Do not delete legacy routing until backfill report is complete and reviewed.
|
||||||
|
|
||||||
|
### 1.4 Validation before enforcement
|
||||||
|
|
||||||
|
Before switching default provider:
|
||||||
|
|
||||||
|
- No critical webhook verification failures for 24h.
|
||||||
|
- DLQ volume stable for 2h.
|
||||||
|
- Provider status mismatch rate `< 0.5%` for 1000 samples.
|
||||||
|
- Manual reconciliation sample (`>= 10` rows) completed by two operators.
|
||||||
|
|
||||||
|
### 1.5 Rollback criteria
|
||||||
|
|
||||||
|
Rollback immediately if any of:
|
||||||
|
|
||||||
|
- payout/hold/release path returns invariant violation,
|
||||||
|
- unresolved webhook failure burst above threshold,
|
||||||
|
- chain reconciliation mismatch above threshold from runbook table.
|
||||||
|
|
||||||
|
Rollback command sequence:
|
||||||
|
|
||||||
|
1. `PAYMENT_ENABLED_PROVIDERS=shkeeper`
|
||||||
|
2. `PAYMENT_DEFAULT_PROVIDER=shkeeper`
|
||||||
|
3. `PAYMENT_PROVIDER_MODE=read_only` (pause new routing),
|
||||||
|
4. keep reconciliation active in dry-run mode,
|
||||||
|
5. post-incident note in this doc + [[Incident Response]].
|
||||||
|
|
||||||
|
### 1.6 Webhook cutoff and manual reconciliation
|
||||||
|
|
||||||
|
- Keep auto-accepting historical webhook traffic through cutover.
|
||||||
|
- Set explicit cutoff only if new provider writes must stop:
|
||||||
|
1. pause new pay-in intents on new provider,
|
||||||
|
2. continue `handleProviderWebhook` in `read_only` mode,
|
||||||
|
3. run manual reconciliation for open windows,
|
||||||
|
4. re-enable normal routing after backlog clear or explicit incident decision.
|
||||||
|
|
||||||
|
## 2. Scenario runbooks
|
||||||
|
|
||||||
|
Each incident scenario uses the same structure:
|
||||||
|
`owner`, `trigger`, `detection`, `immediate`, `recovery`, `post`.
|
||||||
|
|
||||||
|
### 2.1 Failed webhook
|
||||||
|
- **Owner:** BL + DL
|
||||||
|
- **Trigger:** `webhook_failures` alert > warning threshold (see [[Webhook Security Spec]]).
|
||||||
|
- **Detection:** spike in 5xx/400 from callback route, DLQ growth.
|
||||||
|
- **Immediate:** isolate by provider; keep `PAYMENT_PROVIDER_MODE=read_only` for provider if mismatch continues.
|
||||||
|
- **Recovery:** re-process DLQ entries after fix; verify idempotent behavior; compare reconciliation counters.
|
||||||
|
- **Post:** update webhook retry tuning and security thresholds.
|
||||||
|
|
||||||
|
### 2.2 Duplicate payment
|
||||||
|
- **Owner:** BL
|
||||||
|
- **Trigger:** duplicate webhook deliveries or idempotent suppression above normal baseline.
|
||||||
|
- **Detection:** `duplicate` counter above expected and no payment state change.
|
||||||
|
- **Immediate:** confirm normalized status transition map; suppress with `deliveryId`/`idempotency` checks.
|
||||||
|
- **Recovery:** rerun reconciliation for affected IDs and clear manual holds if ledger still consistent.
|
||||||
|
- **Post:** validate provider event parsing and storage hashing.
|
||||||
|
|
||||||
|
### 2.3 Missing payment
|
||||||
|
- **Owner:** BL + Operations
|
||||||
|
- **Trigger:** customer support report or reconciliation finding.
|
||||||
|
- **Detection:** provider reference exists, no canonical payment row or no final ledger balance.
|
||||||
|
- **Immediate:** freeze payouts/release for request ID; run `searchProviderPayments`.
|
||||||
|
- **Recovery:** create missing read-model entry or corrective ledger adjustment after evidence capture.
|
||||||
|
- **Post:** add missing-test case for same provider/providerReference combination.
|
||||||
|
|
||||||
|
### 2.4 Stuck release
|
||||||
|
- **Owner:** BL + Ops
|
||||||
|
- **Trigger:** `released` pending >30m.
|
||||||
|
- **Detection:** payout task with no terminal transition for `release`/`refund`.
|
||||||
|
- **Immediate:** confirm chain confirmation and provider payout status.
|
||||||
|
- **Recovery:** if confirmed on-chain but not reflected, run manual reconciliation + status repair; else reissue payout instruction.
|
||||||
|
- **Post:** update alerting and retry windows.
|
||||||
|
|
||||||
|
### 2.5 Disputed release attempt
|
||||||
|
- **Owner:** Security + BL + Admin
|
||||||
|
- **Trigger:** release/recover API invoked while dispute hold is active.
|
||||||
|
- **Detection:** `disputeId` active + attempted release/refund action.
|
||||||
|
- **Immediate:** block action, notify admin team and dispute owner.
|
||||||
|
- **Recovery:** clear dispute hold only by approved dispute resolution path.
|
||||||
|
- **Post:** enforce ownership check in orchestration and admin UI guardrail.
|
||||||
|
|
||||||
|
### 2.6 Compromised admin
|
||||||
|
- **Owner:** Security Lead
|
||||||
|
- **Trigger:** unexpected high-value payouts or admin credentials alert.
|
||||||
|
- **Detection:** step-up auth failures, role anomalies, IP anomalies.
|
||||||
|
- **Immediate:** suspend admin account, rotate sessions, set `PAYMENT_PROVIDER_MODE=read_only`.
|
||||||
|
- **Recovery:** review all recent ledger entries and release/refund actions; reverse via admin correction only after legal/ownership approval.
|
||||||
|
- **Post:** enforce 2-person approval for high-risk payout thresholds and step-up audit check.
|
||||||
|
|
||||||
|
### 2.7 Leaked API key / webhook secret
|
||||||
|
- **Owner:** Security + DevOps
|
||||||
|
- **Trigger:** secret scanner, log leak, or suspected rotation request.
|
||||||
|
- **Detection:** unauthorized provider 401s, unknown callbacks, or external exposure confirmation.
|
||||||
|
- **Immediate:** rotate affected key and disable old key immediately.
|
||||||
|
- **Recovery:** replay missed webhooks in dry-run mode after trust restored; compare reconciliation totals.
|
||||||
|
- **Post:** document incident and rotate staging/CI secret references.
|
||||||
|
|
||||||
|
### 2.8 Provider outage
|
||||||
|
- **Owner:** DevOps + BL
|
||||||
|
- **Trigger:** repeated provider 5xx/timeouts.
|
||||||
|
- **Detection:** error budget alert and queue growth.
|
||||||
|
- **Immediate:** switch `PAYMENT_ENABLED_PROVIDERS=shkeeper` or `read_only`, notify users of degraded mode.
|
||||||
|
- **Recovery:** drain queue and replay DLQ when provider recovers.
|
||||||
|
- **Post:** update provider outage SLA runbook and status page text.
|
||||||
|
|
||||||
|
### 2.9 Chain/RPC outage
|
||||||
|
- **Owner:** BL + DevOps
|
||||||
|
- **Trigger:** chain verification failures and elevated wallet lookup latency.
|
||||||
|
- **Detection:** verification timeout/error and `chain_verification_stale` trend.
|
||||||
|
- **Immediate:** pause non-critical chain-dependent actions; preserve pending proofs.
|
||||||
|
- **Recovery:** rerun verification jobs against fallback RPC endpoint.
|
||||||
|
- **Post:** update RPC provider fallback policy and retry tuning.
|
||||||
|
|
||||||
|
### 2.10 Suspicious payment proof
|
||||||
|
- **Owner:** Security + BL
|
||||||
|
- **Trigger:** tx hash proof with mismatched `to`, amount, or network.
|
||||||
|
- **Detection:** verify script rejects or manual proof review.
|
||||||
|
- **Immediate:** mark payment disputed, require operator review.
|
||||||
|
- **Recovery:** keep payment in `pending`, notify buyer and seller, trigger manual support workflow.
|
||||||
|
- **Post:** add automated proof assertions to webhook and verifier tests.
|
||||||
|
|
||||||
|
### 2.11 npm/package compromise
|
||||||
|
- **Owner:** CTO + Security
|
||||||
|
- **Trigger:** new high/critical advisory tied to runtime packages.
|
||||||
|
- **Detection:** audit alerts or security team notification.
|
||||||
|
- **Immediate:** pause releases in affected components; freeze `watchtower` auto-update if needed.
|
||||||
|
- **Recovery:** patch dependency and redeploy, then run smoke tests and transaction smoke path.
|
||||||
|
- **Post:** verify lockfile, provenance, and dependency policy compliance.
|
||||||
|
|
||||||
|
## 3. Incident owner roster
|
||||||
|
|
||||||
|
Production launch must replace these role owners with named responders in the
|
||||||
|
primary on-call schedule. Until then, escalation is by role:
|
||||||
|
|
||||||
|
- Payments: backend lead for payment/ledger services
|
||||||
|
- Security: security owner from [[Security Ownership and Launch Decision Criteria]]
|
||||||
|
- DevOps: deployment owner for production infrastructure
|
||||||
|
- Admin lead: operations lead for dispute and payout approval workflows
|
||||||
|
|
||||||
|
## 4. Post-incident mandatory actions
|
||||||
|
|
||||||
|
- incident log + root-cause and action items,
|
||||||
|
- metric threshold updates if needed,
|
||||||
|
- runbook improvements (this document),
|
||||||
|
- verification that [[Monitoring]] and [[Incident Response]] links are still accurate.
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [[Incident Response]]
|
||||||
|
- [[Monitoring]]
|
||||||
|
- [[Deployment]]
|
||||||
|
- [[Backup & Recovery]]
|
||||||
|
- [[Webhook Security Spec]]
|
||||||
|
- [[Payment Provider Adapter Spec]]
|
||||||
|
- [[Backend Core Stack Decision Record - 2026-05-24]]
|
||||||
@@ -37,7 +37,7 @@ reviewers: [backend, security]
|
|||||||
| **Admin** | Authenticated + `req.user.role === 'admin'`. All admin actions MUST be audit-logged. | `authenticateToken` + `roleGuard('admin')` or `authorizeRoles('admin')`. |
|
| **Admin** | Authenticated + `req.user.role === 'admin'`. All admin actions MUST be audit-logged. | `authenticateToken` + `roleGuard('admin')` or `authorizeRoles('admin')`. |
|
||||||
| **Support** | Authenticated + `req.user.role === 'support'`. Read-only access to user data, dispute records, and chat. Can reset passwords and escalate to admin. Cannot modify financial records or release funds. | `authenticateToken` + `roleGuard('support')`. Controller must enforce read-only constraint. |
|
| **Support** | Authenticated + `req.user.role === 'support'`. Read-only access to user data, dispute records, and chat. Can reset passwords and escalate to admin. Cannot modify financial records or release funds. | `authenticateToken` + `roleGuard('support')`. Controller must enforce read-only constraint. |
|
||||||
| **Service** | Internal service-to-service calls. Authenticated via shared secret (`X-Internal-Secret` header) or restricted to localhost network. Not user-facing. | Custom middleware verifying internal header or `req.ip === '127.0.0.1'`. |
|
| **Service** | Internal service-to-service calls. Authenticated via shared secret (`X-Internal-Secret` header) or restricted to localhost network. Not user-facing. | Custom middleware verifying internal header or `req.ip === '127.0.0.1'`. |
|
||||||
| **Step-up** | Admin + re-authenticated within last 15 minutes (configurable). Required for: payout creation/release, role changes, large refunds (>$100), user deletion, admin-wallet signing. | `authenticateToken` + `roleGuard('admin')` + step-up timestamp check from Redis session. |
|
| **Step-up** | Admin + re-authenticated within configured window (default 5 minutes). Required for high-risk admin actions (role changes, user deletion, payout/release, manual overrides, sensitive wallet operations). | `authenticateToken` + `roleGuard('admin')` + step-up timestamp check from Redis session. |
|
||||||
| **HMAC** | No user auth. Verified via HMAC-SHA256 signature on raw body using `SHKEEPER_WEBHOOK_SECRET`. Signature-verified, not identity-verified. | `express.raw()` body parser + timing-safe HMAC comparison. |
|
| **HMAC** | No user auth. Verified via HMAC-SHA256 signature on raw body using `SHKEEPER_WEBHOOK_SECRET`. Signature-verified, not identity-verified. | `express.raw()` body parser + timing-safe HMAC comparison. |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -83,6 +83,10 @@ reviewers: [backend, security]
|
|||||||
| AUTH-R022 | PUT | /api/auth/profile | Authenticated | Owner | None | Tier 3 | No | Auth enforced. | Authenticated | |
|
| AUTH-R022 | PUT | /api/auth/profile | Authenticated | Owner | None | Tier 3 | No | Auth enforced. | Authenticated | |
|
||||||
| AUTH-R023 | POST | /api/auth/update-profile | Authenticated | Owner | None | Tier 3 | No | Auth enforced. Legacy alias. | Authenticated | Duplicate of R022. |
|
| AUTH-R023 | POST | /api/auth/update-profile | Authenticated | Owner | None | Tier 3 | No | Auth enforced. Legacy alias. | Authenticated | Duplicate of R022. |
|
||||||
| AUTH-R024 | DELETE | /api/auth/account | Authenticated | Owner | Password re-verified | Tier 3 | Yes | Auth + password required. | Authenticated + audit | Permanent deletion. |
|
| AUTH-R024 | DELETE | /api/auth/account | Authenticated | Owner | Password re-verified | Tier 3 | Yes | Auth + password required. | Authenticated + audit | Permanent deletion. |
|
||||||
|
| AUTH-R025 | POST | /api/auth/step-up | Admin | None | Valid challenge context or credentials | Tier 6 | Yes | Not implemented | Admin + Step-up | Required by ADR for high-risk admin actions. Creates 5-minute elevated session in Redis. |
|
||||||
|
| AUTH-R026 | GET | /api/auth/sessions | Authenticated | Owner | Current refresh session exists | Tier 3 | Yes | Not implemented | Authenticated | Returns active sessions with device, IP, and session age. |
|
||||||
|
| AUTH-R027 | POST | /api/auth/revoke-session | Authenticated | Owner | Target session belongs to user | Tier 3 | Yes | Not implemented | Authenticated + audit | Revokes one session by sessionTokenHash. |
|
||||||
|
| AUTH-R028 | POST | /api/auth/revoke-all-sessions | Authenticated | Owner | Multiple active sessions loaded | Tier 3 | Yes | Not implemented | Authenticated + audit | Revokes all sessions except current. |
|
||||||
|
|
||||||
### 2.2 User Routes
|
### 2.2 User Routes
|
||||||
|
|
||||||
@@ -116,6 +120,14 @@ reviewers: [backend, security]
|
|||||||
| UADM-R012 | PATCH | /api/users/admin/:userId/password | Admin | None | Target user exists | Tier 6 | Yes | Inline role check. | Admin + Step-up + audit | Wipes all sessions. |
|
| UADM-R012 | PATCH | /api/users/admin/:userId/password | Admin | None | Target user exists | Tier 6 | Yes | Inline role check. | Admin + Step-up + audit | Wipes all sessions. |
|
||||||
| UADM-R013 | POST | /api/users/admin/:userId/resend-verification | Admin | None | User not already verified | Tier 6 | Yes | Inline role check. | Admin + audit | Triggers email. |
|
| UADM-R013 | POST | /api/users/admin/:userId/resend-verification | Admin | None | User not already verified | Tier 6 | Yes | Inline role check. | Admin + audit | Triggers email. |
|
||||||
|
|
||||||
|
### 2.3A Admin Approval Routes
|
||||||
|
|
||||||
|
| ID | Method | Path | Access Level | Ownership Check | State Preconditions | Rate-Limit Tier | Audit Log | Current State | Required State | Notes |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| APV-R001 | GET | /api/admin/approvals | Admin | None | None | Tier 6 | Yes | Not implemented | Admin + Step-up | Pending approval queue for high-value actions. |
|
||||||
|
| APV-R002 | POST | /api/admin/approvals/{id}/confirm | Admin | None | Approval exists, status = PENDING, approver != creator | Tier 6 | Yes | Not implemented | Admin + Step-up + audit | Confirms pending approval and executes action. |
|
||||||
|
| APV-R003 | POST | /api/admin/approvals/{id}/reject | Admin | None | Approval exists, status = PENDING | Tier 6 | Yes | Not implemented | Admin + Step-up + audit | Rejects pending approval and records reason. |
|
||||||
|
|
||||||
### 2.4 Address Routes
|
### 2.4 Address Routes
|
||||||
|
|
||||||
| ID | Method | Path | Access Level | Ownership Check | State Preconditions | Rate-Limit Tier | Audit Log | Current State | Required State | Notes |
|
| ID | Method | Path | Access Level | Ownership Check | State Preconditions | Rate-Limit Tier | Audit Log | Current State | Required State | Notes |
|
||||||
@@ -259,16 +271,16 @@ reviewers: [backend, security]
|
|||||||
|
|
||||||
| ID | Method | Path | Access Level | Ownership Check | State Preconditions | Rate-Limit Tier | Audit Log | Current State | Required State | Notes |
|
| ID | Method | Path | Access Level | Ownership Check | State Preconditions | Rate-Limit Tier | Audit Log | Current State | Required State | Notes |
|
||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
| REL-R001 | POST | /api/payment/shkeeper/:id/release | Admin | None | Payment funded; no active dispute (T06); escrowState=funded | Tier 6 | Yes | Auth enforced. Admin. NO dispute check. T06. | Admin + Step-up + dispute check + audit | Builds release tx payload. |
|
| REL-R001 | POST | /api/payment/shkeeper/:id/release | Admin | None | Payment funded; no active dispute (T06); escrowState=funded | Tier 6 | Yes | Auth enforced. Admin. NO dispute check. T06. | Admin + Step-up + dispute check + audit, + two-person approval for payout > 1000 USD equivalent (see APV-R002/APV-R003) | Builds release tx payload. |
|
||||||
| REL-R002 | POST | /api/payment/shkeeper/:id/release/confirm | Admin | None | Release tx pending; valid txHash | Tier 6 | Yes | Auth enforced. Admin. | Admin + Step-up + audit | Confirms release on-chain. |
|
| REL-R002 | POST | /api/payment/shkeeper/:id/release/confirm | Admin | None | Release tx pending; valid txHash | Tier 6 | Yes | Auth enforced. Admin. | Admin + Step-up + audit | Confirms release on-chain. |
|
||||||
| REL-R003 | POST | /api/payment/shkeeper/:id/refund | Admin | None | Payment funded; no active dispute; escrowState=funded | Tier 6 | Yes | Auth enforced. Admin. NO dispute check. T06. | Admin + Step-up + dispute check + audit | Builds refund tx. |
|
| REL-R003 | POST | /api/payment/shkeeper/:id/refund | Admin | None | Payment funded; no active dispute; escrowState=funded | Tier 6 | Yes | Auth enforced. Admin. NO dispute check. T06. | Admin + Step-up + dispute check + audit, + two-person approval for payout > 1000 USD equivalent (see APV-R002/APV-R003) | Builds refund tx. |
|
||||||
| REL-R004 | POST | /api/payment/shkeeper/:id/refund/confirm | Admin | None | Refund tx pending; valid txHash | Tier 6 | Yes | Auth enforced. Admin. | Admin + Step-up + audit | Confirms refund on-chain. |
|
| REL-R004 | POST | /api/payment/shkeeper/:id/refund/confirm | Admin | None | Refund tx pending; valid txHash | Tier 6 | Yes | Auth enforced. Admin. | Admin + Step-up + audit | Confirms refund on-chain. |
|
||||||
|
|
||||||
### 2.15 Payment Routes (SHKeeper Payout)
|
### 2.15 Payment Routes (SHKeeper Payout)
|
||||||
|
|
||||||
| ID | Method | Path | Access Level | Ownership Check | State Preconditions | Rate-Limit Tier | Audit Log | Current State | Required State | Notes |
|
| ID | Method | Path | Access Level | Ownership Check | State Preconditions | Rate-Limit Tier | Audit Log | Current State | Required State | Notes |
|
||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
| PO-R001 | POST | /api/payment/shkeeper/payout | Admin | None | No existing pending payout for same escrow | Tier 6 | Yes | Auth enforced. Admin. | Admin + Step-up + audit | Creates payout task. T05. |
|
| PO-R001 | POST | /api/payment/shkeeper/payout | Admin | None | No existing pending payout for same escrow | Tier 6 | Yes | Auth enforced. Admin. | Admin + Step-up + audit, + two-person approval for payout > 1000 USD equivalent (see APV-R002/APV-R003) | Creates payout task. T05. |
|
||||||
| PO-R002 | GET | /api/payment/shkeeper/payout/status/:taskId | Authenticated | Owner or Admin | Task exists | Tier 3 | No | Auth enforced. | Authenticated | Poll payout status. |
|
| PO-R002 | GET | /api/payment/shkeeper/payout/status/:taskId | Authenticated | Owner or Admin | Task exists | Tier 3 | No | Auth enforced. | Authenticated | Poll payout status. |
|
||||||
| PO-R003 | POST | /api/payment/shkeeper/payout/webhook | HMAC | None | Signature valid | Tier 5 | Yes | HMAC verification. | HMAC + audit | Payout state changes. |
|
| PO-R003 | POST | /api/payment/shkeeper/payout/webhook | HMAC | None | Signature valid | Tier 5 | Yes | HMAC verification. | HMAC + audit | Payout state changes. |
|
||||||
|
|
||||||
@@ -630,9 +642,10 @@ These gaps involve audit logging and presence tracking. They are important for o
|
|||||||
|
|
||||||
| Route Group | Endpoints |
|
| Route Group | Endpoints |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Auth | 24 |
|
| Auth | 28 |
|
||||||
| User | 9 |
|
| User | 9 |
|
||||||
| User Admin | 13 |
|
| User Admin | 13 |
|
||||||
|
| Admin Approval | 3 |
|
||||||
| Address | 5 |
|
| Address | 5 |
|
||||||
| Purchase Request | 18 |
|
| Purchase Request | 18 |
|
||||||
| Delivery Code | 4 |
|
| Delivery Code | 4 |
|
||||||
@@ -656,7 +669,7 @@ These gaps involve audit logging and presence tracking. They are important for o
|
|||||||
| File | 9 |
|
| File | 9 |
|
||||||
| Admin Cleanup | 7 |
|
| Admin Cleanup | 7 |
|
||||||
| System | 2 |
|
| System | 2 |
|
||||||
| **Total REST Endpoints** | **248** |
|
| **Total REST Endpoints** | **255** |
|
||||||
|
|
||||||
### Socket.IO Event Count
|
### Socket.IO Event Count
|
||||||
|
|
||||||
@@ -691,4 +704,4 @@ These gaps involve audit logging and presence tracking. They are important for o
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*This document was produced on 2026-05-24 as part of the Amanat authorization audit. It must be updated when: new endpoints are added, existing endpoint access levels change, new Socket.IO events are introduced, or the role model is extended. Implementation tasks should reference specific AUTH-R, USER-R, UADM-R, ADDR-R, PR-R, DC-R, OFF-R, TPL-R, SHOP-R, CAT-R, REV-R, PAY-R, SHK-R, REL-R, PO-R, DEC-R, MPAY-R, CHAT-R, NOTIF-R, DIS-R, AI-R, BLOG-R, PTS-R, FILE-R, ADM-R, SYS-R, and SOCK-E IDs from this matrix.*
|
*This document was produced on 2026-05-24 as part of the Amanat authorization audit. It must be updated when: new endpoints are added, existing endpoint access levels change, new Socket.IO events are introduced, or the role model is extended. Implementation tasks should reference specific AUTH-R, USER-R, UADM-R, APV-R, ADDR-R, PR-R, DC-R, OFF-R, TPL-R, SHOP-R, CAT-R, REV-R, PAY-R, SHK-R, REL-R, PO-R, DEC-R, MPAY-R, CHAT-R, NOTIF-R, DIS-R, AI-R, BLOG-R, PTS-R, FILE-R, ADM-R, SYS-R, and SOCK-E IDs from this matrix.*
|
||||||
|
|||||||
117
09 - Audits/Backend Core Stack Decision Record - 2026-05-24.md
Normal file
117
09 - Audits/Backend Core Stack Decision Record - 2026-05-24.md
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
---
|
||||||
|
title: Backend Core Stack Decision Record - 2026-05-24
|
||||||
|
tags: [adr, architecture, backend]
|
||||||
|
created: 2026-05-24
|
||||||
|
status: approved
|
||||||
|
reviewers: [CTO, backend, security]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Backend Core Stack Decision Record - 2026-05-24
|
||||||
|
|
||||||
|
## 1. Decision
|
||||||
|
|
||||||
|
Keep the security-critical backend core on **TypeScript/Node** in the first 12 months.
|
||||||
|
|
||||||
|
Do **not** perform a full greenfield rewrite before the payment/auth/escrow core is fully specified and observable.
|
||||||
|
|
||||||
|
## 2. Why this stack (today)
|
||||||
|
|
||||||
|
The highest current risk is not framework selection; it is **financial state correctness**.
|
||||||
|
|
||||||
|
For the next phase, the team needs:
|
||||||
|
|
||||||
|
- provider-neutral payment abstraction,
|
||||||
|
- immutable funds ledger,
|
||||||
|
- webhook hardening and reconciliation,
|
||||||
|
- strict dispute hold behavior,
|
||||||
|
- admin step-up controls,
|
||||||
|
- production-grade operational runbooks.
|
||||||
|
|
||||||
|
Moving to Go/Kotlin/Rust now would preserve existing risks while adding migration uncertainty and a delay in launch-readiness.
|
||||||
|
|
||||||
|
TypeScript remains the fastest way to ship the required controls while keeping operational visibility and team velocity.
|
||||||
|
|
||||||
|
## 3. Scope of extraction
|
||||||
|
|
||||||
|
The “backend core” now means:
|
||||||
|
|
||||||
|
- `Payment` orchestration and payout/release state transitions,
|
||||||
|
- auth/session validation for financial actions,
|
||||||
|
- webhook intake and reconciliation,
|
||||||
|
- ledger-derived escrow eligibility checks,
|
||||||
|
- admin-risk operations (payout/refund/adjustment).
|
||||||
|
|
||||||
|
These modules stay in the same service boundary during migration-in-place, but all calls must go through:
|
||||||
|
|
||||||
|
- [[Payment Provider Adapter Spec]]
|
||||||
|
- [[Webhook Security Spec]]
|
||||||
|
- [[Funds Ledger and Escrow State Machine Specification]]
|
||||||
|
|
||||||
|
Non-core modules remain where they are:
|
||||||
|
|
||||||
|
- marketplace browsing, templates, shop settings,
|
||||||
|
- chat and notifications,
|
||||||
|
- file uploads/downloads.
|
||||||
|
|
||||||
|
## 4. Evaluation of alternatives
|
||||||
|
|
||||||
|
### Go
|
||||||
|
|
||||||
|
- **Pros:** smaller runtime and dependency surface, better static guarantees.
|
||||||
|
- **Cons:** highest immediate migration cost, new operational tooling, delayed delivery of core money-movement correctness.
|
||||||
|
|
||||||
|
### Kotlin/Java
|
||||||
|
|
||||||
|
- **Pros:** strong enterprise ecosystem, mature auth/security libraries.
|
||||||
|
- **Cons:** heavier stack and slower delivery for a small team.
|
||||||
|
|
||||||
|
### Rust
|
||||||
|
|
||||||
|
- **Pros:** high correctness potential.
|
||||||
|
- **Cons:** steep delivery cost and limited team familiarity.
|
||||||
|
|
||||||
|
### Keep TypeScript (selected)
|
||||||
|
|
||||||
|
- **Pros:** existing team velocity, reduced migration risk, direct integration with current deployment and frontend contracts.
|
||||||
|
- **Cons:** npm supply-chain risk remains; mitigated by [[Secure Build and Supply-Chain Policy]] and strict dependency policy.
|
||||||
|
|
||||||
|
## 5. Migration and rollout plan
|
||||||
|
|
||||||
|
1. **Phase A (this quarter):** lock down high-risk flows in TypeScript (ledger, adapter, webhook, auth/session, runbooks).
|
||||||
|
2. **Phase B (next two quarters):** extract core services behind stable interfaces and add adapter-level contract tests.
|
||||||
|
3. **Phase C (deferred):** evaluate Go/Kotlin pilot for payout+webhook worker only if:
|
||||||
|
- Phase A and B are stable for 60 days,
|
||||||
|
- team staffing supports dual-stack operations,
|
||||||
|
- audit requirements demand lower runtime dependency exposure.
|
||||||
|
|
||||||
|
## 6. Non-goals
|
||||||
|
|
||||||
|
- Full frontend rewrite.
|
||||||
|
- New language migration without closed-loop reconciliation and signed-state invariants.
|
||||||
|
- New provider support that bypasses the adapter contract.
|
||||||
|
|
||||||
|
## 7. Rollback criteria
|
||||||
|
|
||||||
|
- Any increase in incident rate above baseline +20% for 24h after migration activity.
|
||||||
|
- Any unresolved ledger invariant violation (held + disputed + released + refunded mismatch).
|
||||||
|
- Any provider outage recovery that requires non-operator-tuned workarounds.
|
||||||
|
|
||||||
|
Rollback to prior TS implementation:
|
||||||
|
|
||||||
|
- disable any split deployment feature flag,
|
||||||
|
- switch `PAYMENT_ENABLED_PROVIDERS` back to legacy-only,
|
||||||
|
- freeze new provider routing until incident review is complete,
|
||||||
|
- complete post-incident update in this ADR.
|
||||||
|
|
||||||
|
## 8. Ownership
|
||||||
|
|
||||||
|
- **CTO:** final stack decision + dual-stack approvals.
|
||||||
|
- **Backend Lead (BL):** contract and adapter enforcement.
|
||||||
|
- **Security Lead (SL):** webhook/security acceptance criteria.
|
||||||
|
- **DevOps Lead (DL):** deployment safety and rollback testing.
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [[Backend Stack Security and Refactor Assessment - 2026-05-24]]
|
||||||
|
- [[Secure Build and Supply-Chain Policy]]
|
||||||
|
- [[Backend Funds Migration and Operational Runbooks]]
|
||||||
@@ -345,7 +345,7 @@ Should include:
|
|||||||
- Trust boundaries: browser, backend, database, Redis, provider APIs, wallet/RPC, admin UI, Socket.IO.
|
- Trust boundaries: browser, backend, database, Redis, provider APIs, wallet/RPC, admin UI, Socket.IO.
|
||||||
- Abuse cases: fake payment proof, replayed webhook, arbitrary room join, stolen token, double payout, dispute bypass, email/AI abuse.
|
- Abuse cases: fake payment proof, replayed webhook, arbitrary room join, stolen token, double payout, dispute bypass, email/AI abuse.
|
||||||
|
|
||||||
### 2. Funds Ledger Specification
|
### 2. Funds Ledger and Escrow State Machine Specification
|
||||||
|
|
||||||
Purpose: make money movement auditable and provider-independent.
|
Purpose: make money movement auditable and provider-independent.
|
||||||
|
|
||||||
@@ -386,9 +386,7 @@ Should map every endpoint and socket event to:
|
|||||||
|
|
||||||
### 5. Payment Provider Adapter Spec
|
### 5. Payment Provider Adapter Spec
|
||||||
|
|
||||||
Purpose: decouple business logic from SHKeeper, Request Network, manual wallet flow, and future providers.
|
Implemented as [[Payment Provider Adapter Spec]], including:
|
||||||
|
|
||||||
Should define:
|
|
||||||
|
|
||||||
- `createPayInIntent`
|
- `createPayInIntent`
|
||||||
- `getPayInStatus`
|
- `getPayInStatus`
|
||||||
@@ -399,13 +397,11 @@ Should define:
|
|||||||
- `getPayoutStatus`
|
- `getPayoutStatus`
|
||||||
- `searchProviderPayments`
|
- `searchProviderPayments`
|
||||||
|
|
||||||
Provider-specific metadata should be namespaced and never become the canonical funds state.
|
Provider-specific metadata is namespaced and never used as canonical funds state.
|
||||||
|
|
||||||
### 6. Webhook Security Spec
|
### 6. Webhook Security Spec
|
||||||
|
|
||||||
Purpose: prevent forged, replayed, or silently failed provider events.
|
Implemented as [[Webhook Security Spec]]:
|
||||||
|
|
||||||
Should define:
|
|
||||||
|
|
||||||
- Raw-body signature verification.
|
- Raw-body signature verification.
|
||||||
- Accepted headers and algorithms.
|
- Accepted headers and algorithms.
|
||||||
@@ -434,6 +430,8 @@ Should define:
|
|||||||
|
|
||||||
### 8. Realtime Authorization Spec
|
### 8. Realtime Authorization Spec
|
||||||
|
|
||||||
|
Implemented as [[Realtime Authorization Spec]].
|
||||||
|
|
||||||
Purpose: make Socket.IO events subject to the same security model as REST.
|
Purpose: make Socket.IO events subject to the same security model as REST.
|
||||||
|
|
||||||
Should define:
|
Should define:
|
||||||
@@ -476,9 +474,7 @@ Should define:
|
|||||||
|
|
||||||
### 11. Operational Runbooks
|
### 11. Operational Runbooks
|
||||||
|
|
||||||
Purpose: make security incidents and payment failures survivable.
|
Implemented as [[Backend Funds Migration and Operational Runbooks]]:
|
||||||
|
|
||||||
Should include:
|
|
||||||
|
|
||||||
- Failed webhook.
|
- Failed webhook.
|
||||||
- Duplicate payment.
|
- Duplicate payment.
|
||||||
|
|||||||
173
09 - Audits/Payment Provider Adapter Spec.md
Normal file
173
09 - Audits/Payment Provider Adapter Spec.md
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
---
|
||||||
|
title: Payment Provider Adapter Spec
|
||||||
|
tags: [adapters, payments, specification, architecture]
|
||||||
|
created: 2026-05-24
|
||||||
|
status: advisory
|
||||||
|
reviewers: [backend, security, product]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Payment Provider Adapter Spec
|
||||||
|
|
||||||
|
This specification standardizes how payment providers are plugged in so platform logic
|
||||||
|
does not depend on SHKeeper or any single webhook implementation.
|
||||||
|
|
||||||
|
The contract below replaces provider-specific branching in domain services and should
|
||||||
|
be used by all pay-in, payout, release, and reconciliation logic.
|
||||||
|
|
||||||
|
> Canonical implementation note: this is an advisory ADR for tasks in `task 4.6`.
|
||||||
|
> It maps to [[Funds Ledger and Escrow State Machine Specification]] and [[Webhook Security Spec]].
|
||||||
|
|
||||||
|
## 1. Core provider contract
|
||||||
|
|
||||||
|
Implementations expose one typed adapter:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface PaymentProviderAdapter {
|
||||||
|
readonly provider: "shkeeper" | "request_network" | "manual_wallet" | "admin_wallet" | string;
|
||||||
|
|
||||||
|
createPayInIntent(input: PayInIntentInput): Promise<PayInIntentResult>;
|
||||||
|
getPayInStatus(input: PayInStatusInput): Promise<PayInStatusResult>;
|
||||||
|
handleProviderWebhook(input: ProviderWebhookInput): Promise<ProviderWebhookResult>;
|
||||||
|
createHostedPaymentLink(input: HostedLinkInput): Promise<HostedLinkResult>;
|
||||||
|
createReleaseInstruction(input: ReleaseInstructionInput): Promise<ReleaseInstructionResult>;
|
||||||
|
createRefundInstruction(input: RefundInstructionInput): Promise<RefundInstructionResult>;
|
||||||
|
getPayoutStatus(input: PayoutStatusInput): Promise<PayoutStatusResult>;
|
||||||
|
searchProviderPayments(input: ProviderSearchInput): Promise<ProviderPaymentRecord[]>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
All adapters must return a normalized result shape:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type NormalizedProviderStatus = "pending" | "processing" | "confirmed" | "completed" | "failed" | "cancelled" | "released" | "refunded";
|
||||||
|
type NormalizedProviderEvent = {
|
||||||
|
providerPaymentId: string;
|
||||||
|
purchaseRequestId?: string;
|
||||||
|
requestId?: string;
|
||||||
|
providerReference?: string;
|
||||||
|
amount: string; // decimal string
|
||||||
|
currency: string;
|
||||||
|
status: NormalizedProviderStatus;
|
||||||
|
transactionHash?: string;
|
||||||
|
providerEventType: string;
|
||||||
|
receivedAt: string; // ISO timestamp
|
||||||
|
rawFingerprint: string; // provider payload hash
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Method semantics
|
||||||
|
|
||||||
|
### 2.1 `createPayInIntent`
|
||||||
|
|
||||||
|
- Create a provider-specific payment intent from a canonical request.
|
||||||
|
- Must return:
|
||||||
|
- `providerPaymentId` (source of truth for future reconciliation),
|
||||||
|
- canonical `status`,
|
||||||
|
- `payInUrl` when redirect/payment-page flow is used,
|
||||||
|
- an expiry timestamp.
|
||||||
|
- Must persist provider metadata under `payment.providerData.<provider>`.
|
||||||
|
|
||||||
|
### 2.2 `getPayInStatus`
|
||||||
|
|
||||||
|
- Query provider status for an existing intent.
|
||||||
|
- Must map provider statuses into `NormalizedProviderStatus` and include a provider-specific raw snapshot.
|
||||||
|
- Must be idempotent and side-effect free.
|
||||||
|
|
||||||
|
### 2.3 `handleProviderWebhook`
|
||||||
|
|
||||||
|
- Input must include raw body bytes, headers, provider identifier, and parsed envelope.
|
||||||
|
- Must verify signatures before parsing business fields.
|
||||||
|
- On success, emit canonical domain events and return an idempotency decision:
|
||||||
|
- `processed` for first apply,
|
||||||
|
- `duplicate` for replay,
|
||||||
|
- `ignored` for unknown payment / no-op transitions.
|
||||||
|
|
||||||
|
### 2.4 `createHostedPaymentLink`
|
||||||
|
|
||||||
|
- Return the user-visible payment URL + optional redirect/callback endpoints.
|
||||||
|
- Should support provider aliases (for migration aliasing, e.g., `request-network` vs `request_network`).
|
||||||
|
|
||||||
|
### 2.5 `createReleaseInstruction` and `createRefundInstruction`
|
||||||
|
|
||||||
|
- Produce signed/payload instructions and pre-check:
|
||||||
|
- account/release eligibility,
|
||||||
|
- dispute hold not active,
|
||||||
|
- sufficient releasable balance (ledger-derived),
|
||||||
|
- admin approval requirements if configured.
|
||||||
|
- Must never directly mutate release state.
|
||||||
|
- Must be idempotent by `(paymentId, actionType)` where action type is `release|refund`.
|
||||||
|
|
||||||
|
### 2.6 `getPayoutStatus`
|
||||||
|
|
||||||
|
- Return state of pending/processing payout tasks and chain/on-chain confirmation status.
|
||||||
|
- Return normalized status to domain services:
|
||||||
|
- `processing` for queued/broadcast not-finalized,
|
||||||
|
- `completed` for finalized payment,
|
||||||
|
- `failed` with provider error code when rejected.
|
||||||
|
|
||||||
|
### 2.7 `searchProviderPayments`
|
||||||
|
|
||||||
|
- Used for reconciliation and manual verification.
|
||||||
|
- Must support:
|
||||||
|
- `providerPaymentId`/`requestId` lookup,
|
||||||
|
- time-window pagination,
|
||||||
|
- optional min/max amount filtering.
|
||||||
|
- Must never be the primary source for state transitions without reconciliation checks.
|
||||||
|
|
||||||
|
## 3. Routing and selection
|
||||||
|
|
||||||
|
Provider selection follows environment-configured capability flags:
|
||||||
|
|
||||||
|
- `PAYMENT_ENABLED_PROVIDERS` (comma-separated allowlist),
|
||||||
|
- `PAYMENT_DEFAULT_PROVIDER` (read-first fallback),
|
||||||
|
- `PAYMENT_ROLLBACK_PROVIDER` (read-only fallback target for cutbacks),
|
||||||
|
- `PAYMENT_MODE`:
|
||||||
|
- `standard`: normal provider routing,
|
||||||
|
- `dry_run`: no writes, status-only,
|
||||||
|
- `read_only`: no new pay-in/intent writes.
|
||||||
|
|
||||||
|
Selection rules:
|
||||||
|
|
||||||
|
1. Validate provider support and provider license/credential validity.
|
||||||
|
2. Route legacy requests to `shkeeper` when explicit migration window is active.
|
||||||
|
3. For unknown `provider`, return a `400 Bad Request` with explicit operator-visible error code.
|
||||||
|
4. If requested provider is disabled, return `409` with migration explanation and owner-visible hint for operator override.
|
||||||
|
|
||||||
|
## 4. Canonical metadata contract
|
||||||
|
|
||||||
|
Payment documents keep provider-specific data namespaced under:
|
||||||
|
|
||||||
|
- `metadata.providers.<provider>.rawPayload`
|
||||||
|
- `metadata.providers.<provider>.rawEvents[]`
|
||||||
|
- `metadata.providers.<provider>.providerPaymentId`
|
||||||
|
- `metadata.providers.<provider>.lastWebhookAt`
|
||||||
|
|
||||||
|
Domain services must never read `metadata.providers.*` as mutable funds state. They must use ledger-derived balances and canonical status fields only.
|
||||||
|
|
||||||
|
## 5. Error contract
|
||||||
|
|
||||||
|
All adapter methods return standard failure modes:
|
||||||
|
|
||||||
|
- `retryable: true` for transient provider errors (timeouts, 5xx, queue backpressure).
|
||||||
|
- `retryable: false` for invalid payloads, invalid signatures, and authorization failures.
|
||||||
|
- `errorCode` must be stable across retries for auditability.
|
||||||
|
|
||||||
|
## 6. Test coverage required
|
||||||
|
|
||||||
|
- Contract tests per adapter:
|
||||||
|
- `createPayInIntent`, status polling, webhook handling
|
||||||
|
- invalid/absent signature behavior
|
||||||
|
- duplicate webhook idempotency
|
||||||
|
- unknown payment reference behavior
|
||||||
|
- rollback selection and read-only mode behavior.
|
||||||
|
- Reconciliation tests:
|
||||||
|
- provider backfill for missing payment references,
|
||||||
|
- status drift correction,
|
||||||
|
- duplicate/missing event merge.
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [[Webhook Security Spec]]
|
||||||
|
- [[Funds Ledger and Escrow State Machine Specification]]
|
||||||
|
- [[Backend Core Stack Decision Record - 2026-05-24]]
|
||||||
|
- [[Backend Funds Migration and Operational Runbooks]]
|
||||||
153
09 - Audits/Realtime Authorization Spec.md
Normal file
153
09 - Audits/Realtime Authorization Spec.md
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
---
|
||||||
|
title: Realtime Authorization Spec
|
||||||
|
tags: [security, realtime, socketio, authorization]
|
||||||
|
created: 2026-05-24
|
||||||
|
status: advisory
|
||||||
|
---
|
||||||
|
|
||||||
|
# Realtime Authorization Spec
|
||||||
|
|
||||||
|
This document defines the target authorization model for Socket.IO events in the
|
||||||
|
escrow platform. It closes Taskmaster subtask 4.4 alongside
|
||||||
|
[[Authorization Matrix - REST and Socket.IO]].
|
||||||
|
|
||||||
|
## 1. Decision
|
||||||
|
|
||||||
|
Socket.IO must use the same trust boundary as REST:
|
||||||
|
|
||||||
|
- every socket connection is authenticated during the handshake,
|
||||||
|
- room membership is derived by the server,
|
||||||
|
- clients cannot subscribe to rooms by supplying arbitrary user, request, chat,
|
||||||
|
seller, or buyer IDs,
|
||||||
|
- server-to-client emissions are targeted to authorized rooms only,
|
||||||
|
- sensitive payment, payout, dispute, delivery-code, and chat payloads are never
|
||||||
|
sent through global broadcasts.
|
||||||
|
|
||||||
|
## 2. Handshake Authentication
|
||||||
|
|
||||||
|
Client connects with an access token in `handshake.auth.token`.
|
||||||
|
|
||||||
|
Server requirements:
|
||||||
|
|
||||||
|
1. verify the JWT signature and standard claims,
|
||||||
|
2. reject expired, malformed, revoked, or missing tokens,
|
||||||
|
3. attach `{ userId, roles, sessionId, jti }` to `socket.data`,
|
||||||
|
4. disconnect immediately when authentication fails,
|
||||||
|
5. log authentication failures without recording token values.
|
||||||
|
|
||||||
|
Refresh tokens are not accepted by Socket.IO. Clients must refresh through REST
|
||||||
|
and reconnect with a fresh access token.
|
||||||
|
|
||||||
|
## 3. Server-Derived Base Rooms
|
||||||
|
|
||||||
|
On successful connection the server may join only rooms derivable from the
|
||||||
|
authenticated principal:
|
||||||
|
|
||||||
|
| Room | Eligibility | Source |
|
||||||
|
|---|---|---|
|
||||||
|
| `user-{userId}` | authenticated user | JWT subject |
|
||||||
|
| `seller-{userId}` | authenticated user with seller role | JWT roles or user record |
|
||||||
|
| `buyer-{userId}` | authenticated user with buyer role | JWT roles or user record |
|
||||||
|
| `sellers` | authenticated seller | JWT roles or user record |
|
||||||
|
| `buyers` | authenticated buyer | JWT roles or user record |
|
||||||
|
|
||||||
|
Clients must not provide `userId`, `sellerId`, or `buyerId` to join these rooms.
|
||||||
|
|
||||||
|
## 4. Resource Rooms
|
||||||
|
|
||||||
|
Resource rooms require database authorization before join.
|
||||||
|
|
||||||
|
| Room | Eligibility | Authorization Query |
|
||||||
|
|---|---|---|
|
||||||
|
| `request-{requestId}` | buyer, selected seller, assigned admin/moderator | purchase request participant check |
|
||||||
|
| `chat-{chatId}` | chat participant or assigned support/admin user | chat participant check |
|
||||||
|
| `dispute-{disputeId}` | dispute party, assigned moderator, admin | dispute participant/assignment check |
|
||||||
|
| `template-checkout-{checkoutId}` | checkout owner or service-controlled UI session | checkout ownership check |
|
||||||
|
|
||||||
|
Membership must be rechecked when ownership or state changes. If a request,
|
||||||
|
chat, or dispute loses a participant, the server must remove that user's sockets
|
||||||
|
from the associated room.
|
||||||
|
|
||||||
|
## 5. Client Event Policy
|
||||||
|
|
||||||
|
Allowed client-originated events:
|
||||||
|
|
||||||
|
| Event | Required Authorization | Notes |
|
||||||
|
|---|---|---|
|
||||||
|
| `join-request-room` | participant check | May remain only as a request for server validation. |
|
||||||
|
| `leave-request-room` | current membership | User may leave an allowed room. |
|
||||||
|
| `join-chat-room` | participant check | May remain only as a request for server validation. |
|
||||||
|
| `leave-chat-room` | current membership | User may leave an allowed room. |
|
||||||
|
| `typing-start` / `typing-stop` | current `chat-{chatId}` membership | `userId` in payload is ignored; server derives sender. |
|
||||||
|
|
||||||
|
Removed or deprecated client-originated events:
|
||||||
|
|
||||||
|
| Event | Replacement |
|
||||||
|
|---|---|
|
||||||
|
| `join-user-room` | server auto-join on handshake |
|
||||||
|
| `join-seller-room` / `join-buyer-room` | server auto-join from authenticated role |
|
||||||
|
| `user-online` | server emits presence after authenticated connection |
|
||||||
|
|
||||||
|
## 6. Emission Policy
|
||||||
|
|
||||||
|
Server emissions must target the narrowest authorized room:
|
||||||
|
|
||||||
|
| Data Class | Allowed Target |
|
||||||
|
|---|---|
|
||||||
|
| user notifications | `user-{recipientId}` |
|
||||||
|
| buyer/seller offer updates | relevant `user-*`, `buyer-*`, `seller-*`, or `request-*` room |
|
||||||
|
| payment status | buyer and seller user rooms, request room if both parties may see it |
|
||||||
|
| payout status | seller user room and admin operations room only |
|
||||||
|
| delivery code | seller user room only |
|
||||||
|
| chat messages | `chat-{chatId}` |
|
||||||
|
| dispute events | `dispute-{disputeId}` and assigned admin/moderator room |
|
||||||
|
|
||||||
|
Global payment and payout events are prohibited because they expose financial
|
||||||
|
metadata to unrelated users.
|
||||||
|
|
||||||
|
## 7. Payload Rules
|
||||||
|
|
||||||
|
- Never trust `userId`, `role`, `sellerId`, or `buyerId` from socket payloads.
|
||||||
|
- Derive sender identity from `socket.data.userId`.
|
||||||
|
- Do not emit delivery verification codes to buyer-visible rooms.
|
||||||
|
- Redact wallet addresses, tx hashes, and provider references unless the target
|
||||||
|
user is a party to the transaction or an authorized operator.
|
||||||
|
- Keep payload schemas consistent with REST read permissions.
|
||||||
|
|
||||||
|
## 8. Rate Limiting and Audit
|
||||||
|
|
||||||
|
Socket event rate limits:
|
||||||
|
|
||||||
|
| Event Class | Limit |
|
||||||
|
|---|---|
|
||||||
|
| room join attempts | 30 per 15 minutes per user |
|
||||||
|
| typing events | 120 per minute per socket |
|
||||||
|
| chat message events | same policy as REST chat message creation |
|
||||||
|
| failed authorization checks | 10 per 15 minutes per user, then disconnect |
|
||||||
|
|
||||||
|
Audit log required for:
|
||||||
|
|
||||||
|
- failed room authorization checks,
|
||||||
|
- admin/moderator joins to dispute or request rooms,
|
||||||
|
- attempts to join user/seller/buyer rooms for another principal,
|
||||||
|
- global payment or payout emission rejection.
|
||||||
|
|
||||||
|
## 9. Tests
|
||||||
|
|
||||||
|
Minimum verification before launch:
|
||||||
|
|
||||||
|
1. invalid or missing JWT cannot connect,
|
||||||
|
2. user cannot join another user's `user-*`, `seller-*`, or `buyer-*` room,
|
||||||
|
3. user cannot join a request/chat/dispute room without participant status,
|
||||||
|
4. removed participant is evicted from the resource room,
|
||||||
|
5. payment and payout events are not emitted globally,
|
||||||
|
6. delivery code is emitted only to the seller,
|
||||||
|
7. socket event rate limits disconnect abusive clients,
|
||||||
|
8. audit events are written for denied room joins.
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [[Authorization Matrix - REST and Socket.IO]]
|
||||||
|
- [[Threat Model - Amanat Escrow Platform]]
|
||||||
|
- [[Session and Authentication Architecture Decision]]
|
||||||
|
- [[Backend Stack Security and Refactor Assessment - 2026-05-24]]
|
||||||
@@ -350,6 +350,16 @@ High-risk admin actions require re-authentication. Upon successful re-authentica
|
|||||||
8. Frontend retries the original high-risk action.
|
8. Frontend retries the original high-risk action.
|
||||||
9. The action proceeds.
|
9. The action proceeds.
|
||||||
|
|
||||||
|
### Traceability to Authorization Matrix
|
||||||
|
|
||||||
|
This matrix maps to:
|
||||||
|
|
||||||
|
- `AUTH-R025` (`POST /api/auth/step-up`) for the step-up API entry point.
|
||||||
|
- `AUTH-R026` (`GET /api/auth/sessions`), `AUTH-R027` (`POST /api/auth/revoke-session`), `AUTH-R028` (`POST /api/auth/revoke-all-sessions`) for session controls.
|
||||||
|
- `APV-R001`, `APV-R002`, `APV-R003` for approval queue + confirm/reject workflow.
|
||||||
|
|
||||||
|
Status: these rows are marked **Not implemented** in the matrix while this ADR remains in planning/rollout state.
|
||||||
|
|
||||||
### Two-person approval flow
|
### Two-person approval flow
|
||||||
|
|
||||||
For actions requiring two-person approval:
|
For actions requiring two-person approval:
|
||||||
@@ -659,19 +669,19 @@ If any migration step causes issues:
|
|||||||
|
|
||||||
| Threat | Document |
|
| Threat | Document |
|
||||||
|---|---|
|
|---|---|
|
||||||
| T01 (fake payment proof) | [[Payment Provider Adapter Spec]] (future) |
|
| T01 (fake payment proof) | [[Funds Ledger and Escrow State Machine Specification]], [[Payment Provider Adapter Spec]] |
|
||||||
| T02 (webhook replay) | [[Webhook Security Spec]] (future) |
|
| T02 (webhook replay) | [[Webhook Security Spec]] |
|
||||||
| T03 (arbitrary socket room join) | Realtime Authorization Spec (future) |
|
| T03 (arbitrary socket room join) | [[Realtime Authorization Spec]] |
|
||||||
| T05 (double payout) | [[Funds Ledger Specification]] (future) |
|
| T05 (double payout) | [[Funds Ledger and Escrow State Machine Specification]] |
|
||||||
| T06 (dispute bypass) | Escrow State Machine (future) |
|
| T06 (dispute bypass) | [[Funds Ledger and Escrow State Machine Specification]] |
|
||||||
| T07 (email abuse) | Rate limiting implementation |
|
| T07 (email abuse) | Rate limiting implementation |
|
||||||
| T08 (AI cost abuse) | Rate limiting + auth implementation |
|
| T08 (AI cost abuse) | Rate limiting + auth implementation |
|
||||||
| T09 (admin privilege escalation) | [[Authorization Matrix]] + step-up auth (this ADR) |
|
| T09 (admin privilege escalation) | [[Authorization Matrix - REST and Socket.IO]] + step-up auth (this ADR) |
|
||||||
| T11 (unauthenticated payment endpoints) | Auth middleware implementation |
|
| T11 (unauthenticated payment endpoints) | Auth middleware implementation |
|
||||||
| T12 (rate limit bypass) | Rate limiting implementation |
|
| T12 (rate limit bypass) | Rate limiting implementation |
|
||||||
| T14 (supply-chain) | [[Secure Build and Supply-Chain Policy]] |
|
| T14 (supply-chain) | [[Secure Build and Supply-Chain Policy]] |
|
||||||
| T16 (deep-link tampering) | Telegram initData verification |
|
| T16 (deep-link tampering) | Telegram initData verification |
|
||||||
| T17 (provider outage) | Operational runbooks |
|
| T17 (provider outage) | [[Backend Funds Migration and Operational Runbooks]] |
|
||||||
| T18 (insider manipulation) | Multi-sig wallet + funds ledger + two-person approval (this ADR) |
|
| T18 (insider manipulation) | Multi-sig wallet + funds ledger + two-person approval (this ADR) |
|
||||||
| T19 (price manipulation) | Offer status enforcement |
|
| T19 (price manipulation) | Offer status enforcement |
|
||||||
| T20 (delivery brute force) | Rate limiting + code entropy |
|
| T20 (delivery brute force) | Rate limiting + code entropy |
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
---
|
||||||
|
title: Task 4 Backend Security Architecture Verification Report
|
||||||
|
tags: [taskmaster, verification, security, backend]
|
||||||
|
created: 2026-05-24
|
||||||
|
status: complete
|
||||||
|
---
|
||||||
|
|
||||||
|
# Task 4 Backend Security Architecture Verification Report
|
||||||
|
|
||||||
|
Taskmaster task 4 is complete as an advisory architecture and handoff package.
|
||||||
|
The task defines how the backend security/refactor assessment is converted into
|
||||||
|
implementation criteria without rewriting or disrupting the current backend
|
||||||
|
model.
|
||||||
|
|
||||||
|
## 1. Deliverable map
|
||||||
|
|
||||||
|
| Taskmaster item | Deliverable |
|
||||||
|
|---|---|
|
||||||
|
| 4.1 Security ownership and launch criteria | [[Security Ownership and Launch Decision Criteria]] |
|
||||||
|
| 4.2 Escrow platform threat model | [[Threat Model - Amanat Escrow Platform]] |
|
||||||
|
| 4.3 Funds ledger and escrow state machine | [[Funds Ledger and Escrow State Machine Specification]] |
|
||||||
|
| 4.4 REST and Socket.IO authorization matrix | [[Authorization Matrix - REST and Socket.IO]], [[Realtime Authorization Spec]] |
|
||||||
|
| 4.5 Session, passkey, and admin step-up architecture | [[Session and Authentication Architecture Decision]] |
|
||||||
|
| 4.6 Webhook security and payment adapter contracts | [[Webhook Security Spec]], [[Payment Provider Adapter Spec]] |
|
||||||
|
| 4.7 Secure build and supply-chain policy | [[Secure Build and Supply-Chain Policy]] |
|
||||||
|
| 4.8 Backend-core stack decision | [[Backend Core Stack Decision Record - 2026-05-24]] |
|
||||||
|
| 4.9 Migration and operational runbooks | [[Backend Funds Migration and Operational Runbooks]] |
|
||||||
|
|
||||||
|
## 2. Architecture decisions verified
|
||||||
|
|
||||||
|
- The current TypeScript/Node backend remains the production delivery path for
|
||||||
|
the next security-hardening phase.
|
||||||
|
- A full backend rewrite is explicitly out of scope until ledger, webhook,
|
||||||
|
provider, auth/session, and reconciliation contracts are stable and observable.
|
||||||
|
- Payment providers are optional and provider-neutral behind adapter contracts.
|
||||||
|
- Webhooks must use raw-body signature verification, replay prevention,
|
||||||
|
idempotency, and dead-letter capture.
|
||||||
|
- Funds movement must be derived from the canonical ledger and escrow state
|
||||||
|
machine, not provider metadata.
|
||||||
|
- Admin release, refund, payout, role, and destructive account operations require
|
||||||
|
step-up authentication and audit logging; high-risk payouts require
|
||||||
|
two-person approval.
|
||||||
|
- Socket.IO room membership must be server-derived and authorization checked,
|
||||||
|
with global financial broadcasts prohibited.
|
||||||
|
|
||||||
|
## 3. Verification commands
|
||||||
|
|
||||||
|
Executed from `nick-doc` on 2026-05-24:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx task-master show 4
|
||||||
|
npx task-master set-status --id=4.6 --status=done
|
||||||
|
npx task-master set-status --id=4.7 --status=done
|
||||||
|
npx task-master set-status --id=4.8 --status=done
|
||||||
|
npx task-master set-status --id=4.9 --status=done
|
||||||
|
npx task-master set-status --id=4.3 --status=done
|
||||||
|
npx task-master set-status --id=4.4 --status=done
|
||||||
|
npx task-master set-status --id=4.5 --status=done
|
||||||
|
npx task-master set-status --id=4 --status=done
|
||||||
|
node - <<'NODE'
|
||||||
|
const fs=require('fs');
|
||||||
|
const data=JSON.parse(fs.readFileSync('.taskmaster/tasks/tasks.json','utf8'));
|
||||||
|
const t=data.master.tasks.find(x=>String(x.id)==='4');
|
||||||
|
console.log(JSON.stringify({
|
||||||
|
task:t.status,
|
||||||
|
subtasks:t.subtasks.map(s=>({id:s.id,status:s.status,title:s.title}))
|
||||||
|
}, null, 2));
|
||||||
|
NODE
|
||||||
|
```
|
||||||
|
|
||||||
|
A one-off Node link checker also parsed Task 4 wiki links and verified they
|
||||||
|
resolve to markdown files; threat IDs such as `[[T05]]` were treated as allowed
|
||||||
|
shorthand references.
|
||||||
|
|
||||||
|
## 4. Verification result
|
||||||
|
|
||||||
|
- Taskmaster JSON reports task 4 as `done`.
|
||||||
|
- Taskmaster JSON reports subtasks 4.1 through 4.9 as `done`.
|
||||||
|
- `Authorization Matrix - REST and Socket.IO` now links directly to [[Realtime Authorization Spec]].
|
||||||
|
- Task 4 wiki links resolve to existing markdown files, excluding threat-ID
|
||||||
|
shorthand references such as `[[T05]]`.
|
||||||
|
- Incident ownership in the task 4 runbook was replaced with explicit role owners
|
||||||
|
that can be mapped to named responders before production launch.
|
||||||
|
- Remaining implementation tests belong to follow-up backend tasks because task
|
||||||
|
4 is a documentation and architecture handoff task.
|
||||||
|
|
||||||
|
## 5. Follow-up implementation test requirements
|
||||||
|
|
||||||
|
Implementation tasks derived from task 4 must include:
|
||||||
|
|
||||||
|
- ledger invariant unit tests for every escrow transition,
|
||||||
|
- payment provider adapter contract tests for SHKeeper, Request Network, manual
|
||||||
|
wallet, and disabled-provider modes,
|
||||||
|
- webhook signature, replay, duplicate, and DLQ tests,
|
||||||
|
- REST authorization tests for every gap listed in the authorization matrix,
|
||||||
|
- Socket.IO handshake, room authorization, targeted emission, and rate-limit
|
||||||
|
tests,
|
||||||
|
- session rotation, revocation, passkey disabled/enabled, and admin step-up
|
||||||
|
tests,
|
||||||
|
- runbook drills for provider outage, leaked webhook secret, stuck release,
|
||||||
|
suspicious payment proof, and compromised admin.
|
||||||
|
|
||||||
|
## 6. Residual risk
|
||||||
|
|
||||||
|
This report verifies the Task 4 architecture package, not production behavior.
|
||||||
|
Backend implementation work must still enforce these controls before launch.
|
||||||
@@ -557,15 +557,15 @@ The following remediation documents (from the recommended documentation set in [
|
|||||||
|
|
||||||
| Remediation Document | Threats Addressed |
|
| Remediation Document | Threats Addressed |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Funds Ledger Specification | T05, T18, T23 |
|
| Funds Ledger and Escrow State Machine Specification | T05, T18, T23 |
|
||||||
| Escrow State Machine | T06, T19, T23 |
|
| Funds Ledger and Escrow State Machine Specification | T06, T19, T23 |
|
||||||
| Authorization Matrix | T09, T21 |
|
| Authorization Matrix | T09, T21 |
|
||||||
| Webhook Security Spec | T02 |
|
| Webhook Security Spec | T02 |
|
||||||
| Session and Auth Architecture | T04, T10, T13, T22 |
|
| Session and Auth Architecture | T04, T10, T13, T22 |
|
||||||
| Realtime Authorization Spec | T03 |
|
| Realtime Authorization Spec | T03 |
|
||||||
| Payment Provider Adapter Spec | T01, T11, T17 |
|
| Payment Provider Adapter Spec | T01, T11, T17 |
|
||||||
| Secure Build and Supply-Chain Policy | T14 |
|
| Secure Build and Supply-Chain Policy | T14 |
|
||||||
| Operational Runbooks | T17 |
|
| Backend Funds Migration and Operational Runbooks | T17 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
150
09 - Audits/Webhook Security Spec.md
Normal file
150
09 - Audits/Webhook Security Spec.md
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
---
|
||||||
|
title: Webhook Security Spec
|
||||||
|
tags: [webhooks, security, audit, payments]
|
||||||
|
created: 2026-05-24
|
||||||
|
status: advisory
|
||||||
|
reviewers: [backend, security, operations]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Webhook Security Spec
|
||||||
|
|
||||||
|
This document defines signed callback handling for all payment and payout providers.
|
||||||
|
It closes the gaps in [[Security Architecture]] by turning webhook behavior into an explicit,
|
||||||
|
auditable contract.
|
||||||
|
|
||||||
|
The scope is inbound callbacks only:
|
||||||
|
|
||||||
|
- SHKeeper pay-in (`/api/payment/shkeeper/webhook`)
|
||||||
|
- SHKeeper payout (`/api/payment/shkeeper/payout/webhook`)
|
||||||
|
- Request Network (`/api/payment/request-network/webhook`)
|
||||||
|
- Manual/admin reconciliation channels (where applicable)
|
||||||
|
|
||||||
|
## 1. Canonical event envelope
|
||||||
|
|
||||||
|
All callbacks are normalized by [[Payment Provider Adapter Spec]] into:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type ProviderCallback = {
|
||||||
|
provider: "shkeeper" | "request_network" | "manual_wallet" | "admin_wallet" | string;
|
||||||
|
providerPaymentId: string;
|
||||||
|
purchaseRequestId?: string;
|
||||||
|
requestId?: string;
|
||||||
|
deliveryId?: string;
|
||||||
|
eventType: string; // e.g., paid, payout_completed, status_update
|
||||||
|
status: string; // provider-specific raw status
|
||||||
|
normalizedStatus: "pending" | "completed" | "failed" | "cancelled" | "released" | "refunded";
|
||||||
|
amount?: string;
|
||||||
|
currency?: string;
|
||||||
|
transactionHash?: string;
|
||||||
|
occurredAt?: string; // ISO 8601 if provided
|
||||||
|
receivedAt: string; // server-side receive time
|
||||||
|
rawFingerprint: string; // sha256(raw_body)
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Callbacks are processed only through adapter entry points; provider-specific parsing remains private to the adapter.
|
||||||
|
|
||||||
|
## 2. Signature verification
|
||||||
|
|
||||||
|
### 2.1 Required mechanics
|
||||||
|
|
||||||
|
- Verify signatures against raw request bytes, **before JSON parsing**.
|
||||||
|
- Use constant-time comparison and short-circuit to 401/403 on mismatch.
|
||||||
|
- Never disable verification outside local-only test tooling.
|
||||||
|
- Store raw payload hash (`rawFingerprint`) for forensics and idempotency checks.
|
||||||
|
|
||||||
|
### 2.2 Provider headers
|
||||||
|
|
||||||
|
| Provider | Header(s) |
|
||||||
|
|---|---|
|
||||||
|
| SHKeeper | `x-shkeeper-signature` |
|
||||||
|
| Request Network | `x-request-network-signature` |
|
||||||
|
| Test override (local only) | explicitly documented in deployment notes, never in production |
|
||||||
|
|
||||||
|
If expected signature header is absent or malformed, treat as a non-retryable client error.
|
||||||
|
|
||||||
|
## 3. Replay prevention and idempotency
|
||||||
|
|
||||||
|
For each callback store and enforce one of:
|
||||||
|
|
||||||
|
- `deliveryId` + `provider` + `eventType`, or
|
||||||
|
- `(providerPaymentId, normalizedStatus, provider)` when provider has no delivery id.
|
||||||
|
|
||||||
|
Replay rules:
|
||||||
|
|
||||||
|
- First successful write path = **processed**.
|
||||||
|
- Same key seen again with no state change = **duplicate** (HTTP 200 response, no side effects).
|
||||||
|
- Same key seen for different payload hash = **conflict** (HTTP 409, captured to DLQ).
|
||||||
|
|
||||||
|
## 4. Unknown and duplicate behavior
|
||||||
|
|
||||||
|
| Condition | Response | Side effects |
|
||||||
|
|---|---|---|
|
||||||
|
| Signature valid, unknown `providerPaymentId` | `200` (`unknown_payment`) in v1 mode / `404` in strict mode | no state write, record DLQ entry for operator review |
|
||||||
|
| Known `providerPaymentId`, already terminal | `200` (`duplicate_terminal`) | no state write |
|
||||||
|
| Known `providerPaymentId`, stale status transition | `200` (`duplicate_or_out_of_order`) | no state write |
|
||||||
|
| Unknown signature | `401` | no state write |
|
||||||
|
| Malformed payload | `400` | no state write |
|
||||||
|
|
||||||
|
## 5. Retry semantics
|
||||||
|
|
||||||
|
- Callback consumers (providers) may retry:
|
||||||
|
- transient network failures,
|
||||||
|
- 5xx/provider internal timeouts,
|
||||||
|
- explicit retryable status from endpoint.
|
||||||
|
- Retry is triggered only on non-2xx codes for SHKeeper and Request Network.
|
||||||
|
- Recommended handler mapping:
|
||||||
|
- `401/400` = do not retry (hard fail),
|
||||||
|
- `409` = do not retry until manual release,
|
||||||
|
- `500/503` = retry.
|
||||||
|
|
||||||
|
## 6. Dead-letter and replay storage
|
||||||
|
|
||||||
|
Persist all failed callbacks for at least 7 days in append-only storage:
|
||||||
|
|
||||||
|
- `providerWebhookFailures`
|
||||||
|
- key fields: `provider`, `deliveryId`, `providerPaymentId`, `requestPath`, `requestHeaders`, `rawFingerprint`, `statusCode`, `errorCode`, `attemptCount`, `nextRetryAt`, `rawBodyRef`, `createdAt`.
|
||||||
|
- If storage is unavailable, fail closed and raise a high-severity ops alert.
|
||||||
|
|
||||||
|
Retention policy:
|
||||||
|
|
||||||
|
- 30 days for `success==true`,
|
||||||
|
- 180 days for `unknown_payment`, `repeated_conflict`, `signature_failure`,
|
||||||
|
- immediate alert if retry queue exceeds 500 entries for a provider.
|
||||||
|
|
||||||
|
## 7. Alerting thresholds
|
||||||
|
|
||||||
|
- `failed_webhook_count` over 1 minute:
|
||||||
|
- warning at `> 20`,
|
||||||
|
- critical at `> 100`.
|
||||||
|
- signature failures:
|
||||||
|
- warning at `> 5` in 5 minutes,
|
||||||
|
- critical at `> 20` in 5 minutes.
|
||||||
|
- duplicate ratio:
|
||||||
|
- warning if `duplicates / total >= 0.15` for 10 minutes.
|
||||||
|
- dead-letter growth:
|
||||||
|
- warning at `+200` new entries/hour,
|
||||||
|
- critical at `+500`/hour.
|
||||||
|
|
||||||
|
## 8. Required operator signals
|
||||||
|
|
||||||
|
Webhook health checks should expose:
|
||||||
|
|
||||||
|
- last-seen timestamp by provider,
|
||||||
|
- delivery backlog depth,
|
||||||
|
- per-status counters (`processed`, `duplicate`, `unknown`, `conflict`, `signature_failure`),
|
||||||
|
- DLQ length and oldest entry age.
|
||||||
|
|
||||||
|
## 9. Testing requirements
|
||||||
|
|
||||||
|
- Signature bypass tests (must remain false in staging/prod),
|
||||||
|
- replay/delivery-id duplicate tests,
|
||||||
|
- malformed payload tests,
|
||||||
|
- unknown payment tests,
|
||||||
|
- non-terminal duplicate suppression tests.
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [[Payment Provider Adapter Spec]]
|
||||||
|
- [[Error Codes]]
|
||||||
|
- [[Backend Funds Migration and Operational Runbooks]]
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
taskmaster_id: "4.3"
|
taskmaster_id: "4.3"
|
||||||
status: "pending"
|
status: "done"
|
||||||
priority: "high"
|
priority: "high"
|
||||||
depends_on: ["2"]
|
depends_on: ["2"]
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-24T07:26:29.052Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.3 - Specify funds ledger and escrow state machine
|
# 4.3 - Specify funds ledger and escrow state machine
|
||||||
|
|
||||||
- [ ] 4.3 - Specify funds ledger and escrow state machine #taskmaster #priority/high #status/pending ⏫ 🆔 tm-4-3 ⛔ tm-2
|
- [x] 4.3 - Specify funds ledger and escrow state machine #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-3 ⛔ tm-2
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Taskmaster ID | 4.3 |
|
| Taskmaster ID | 4.3 |
|
||||||
| Status | pending |
|
| Status | done |
|
||||||
| Priority | high |
|
| Priority | high |
|
||||||
| Dependencies | 2 |
|
| Dependencies | 2 |
|
||||||
| Parent | 4 - Define backend security and refactor strategy from latest audit |
|
| Parent | 4 - Define backend security and refactor strategy from latest audit |
|
||||||
@@ -28,6 +28,8 @@ Define canonical money movement and legal state transitions before refactor or p
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
|
Completed. Produced `09 - Audits/Funds Ledger and Escrow State Machine Specification.md` (states, transitions, invariants, and migration guidance for canonical funds/escrow transitions).
|
||||||
|
|
||||||
Create specs for FundsAccount, LedgerEntry, FundsBalance, gross paid, provider fees, platform fees, held, disputed, releasable, released, refunded, idempotency keys, reconciliation behavior, purchase request states, payment states, escrow/funds states, dispute states, valid transitions, forbidden transitions, and release/refund/admin override preconditions.
|
Create specs for FundsAccount, LedgerEntry, FundsBalance, gross paid, provider fees, platform fees, held, disputed, releasable, released, refunded, idempotency keys, reconciliation behavior, purchase request states, payment states, escrow/funds states, dispute states, valid transitions, forbidden transitions, and release/refund/admin override preconditions.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
taskmaster_id: "4.4"
|
taskmaster_id: "4.4"
|
||||||
status: "pending"
|
status: "done"
|
||||||
priority: "high"
|
priority: "high"
|
||||||
depends_on: ["2"]
|
depends_on: ["2"]
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-24T07:26:29.052Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.4 - Create authorization matrix for REST and Socket.IO
|
# 4.4 - Create authorization matrix for REST and Socket.IO
|
||||||
|
|
||||||
- [ ] 4.4 - Create authorization matrix for REST and Socket.IO #taskmaster #priority/high #status/pending ⏫ 🆔 tm-4-4 ⛔ tm-2
|
- [x] 4.4 - Create authorization matrix for REST and Socket.IO #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-4 ⛔ tm-2
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Taskmaster ID | 4.4 |
|
| Taskmaster ID | 4.4 |
|
||||||
| Status | pending |
|
| Status | done |
|
||||||
| Priority | high |
|
| Priority | high |
|
||||||
| Dependencies | 2 |
|
| Dependencies | 2 |
|
||||||
| Parent | 4 - Define backend security and refactor strategy from latest audit |
|
| Parent | 4 - Define backend security and refactor strategy from latest audit |
|
||||||
@@ -28,6 +28,8 @@ Map every endpoint and realtime event to access level, ownership checks, state p
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
|
Completed. Produced `09 - Audits/Authorization Matrix - REST and Socket.IO.md` and `09 - Audits/Realtime Authorization Spec.md`.
|
||||||
|
|
||||||
Include public/authenticated/owner/buyer/seller/admin/support/service-role classifications. Socket.IO rooms must be server-derived from authenticated identity, not client-supplied user IDs.
|
Include public/authenticated/owner/buyer/seller/admin/support/service-role classifications. Socket.IO rooms must be server-derived from authenticated identity, not client-supplied user IDs.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
taskmaster_id: "4.5"
|
taskmaster_id: "4.5"
|
||||||
status: "pending"
|
status: "done"
|
||||||
priority: "high"
|
priority: "high"
|
||||||
depends_on: ["2"]
|
depends_on: ["2"]
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-24T07:26:29.052Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.5 - Decide session, passkey, and admin step-up architecture
|
# 4.5 - Decide session, passkey, and admin step-up architecture
|
||||||
|
|
||||||
- [ ] 4.5 - Decide session, passkey, and admin step-up architecture #taskmaster #priority/high #status/pending ⏫ 🆔 tm-4-5 ⛔ tm-2
|
- [x] 4.5 - Decide session, passkey, and admin step-up architecture #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-5 ⛔ tm-2
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Taskmaster ID | 4.5 |
|
| Taskmaster ID | 4.5 |
|
||||||
| Status | pending |
|
| Status | done |
|
||||||
| Priority | high |
|
| Priority | high |
|
||||||
| Dependencies | 2 |
|
| Dependencies | 2 |
|
||||||
| Parent | 4 - Define backend security and refactor strategy from latest audit |
|
| Parent | 4 - Define backend security and refactor strategy from latest audit |
|
||||||
@@ -28,6 +28,8 @@ Choose browser session model and high-risk admin authentication requirements.
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
|
Completed. Produced `09 - Audits/Session and Authentication Architecture Decision.md`.
|
||||||
|
|
||||||
Decide localStorage versus httpOnly cookies, access/refresh token lifetimes, CSRF strategy, refresh rotation, WebAuthn requirements, OAuth requirements, device/session revocation, and whether payouts/role changes require step-up authentication or two-person approval.
|
Decide localStorage versus httpOnly cookies, access/refresh token lifetimes, CSRF strategy, refresh rotation, WebAuthn requirements, OAuth requirements, device/session revocation, and whether payouts/role changes require step-up authentication or two-person approval.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
taskmaster_id: "4.6"
|
taskmaster_id: "4.6"
|
||||||
status: "pending"
|
status: "done"
|
||||||
priority: "high"
|
priority: "high"
|
||||||
depends_on: ["3"]
|
depends_on: ["3"]
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-24T07:26:29.052Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.6 - Specify webhook security and provider adapter contracts
|
# 4.6 - Specify webhook security and provider adapter contracts
|
||||||
|
|
||||||
- [ ] 4.6 - Specify webhook security and provider adapter contracts #taskmaster #priority/high #status/pending ⏫ 🆔 tm-4-6 ⛔ tm-3
|
- [x] 4.6 - Specify webhook security and provider adapter contracts #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-6 ⛔ tm-3
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Taskmaster ID | 4.6 |
|
| Taskmaster ID | 4.6 |
|
||||||
| Status | pending |
|
| Status | done |
|
||||||
| Priority | high |
|
| Priority | high |
|
||||||
| Dependencies | 3 |
|
| Dependencies | 3 |
|
||||||
| Parent | 4 - Define backend security and refactor strategy from latest audit |
|
| Parent | 4 - Define backend security and refactor strategy from latest audit |
|
||||||
@@ -28,6 +28,8 @@ Define provider-neutral payment interface and signed webhook processing rules.
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
|
Completed. Produced `09 - Audits/Webhook Security Spec.md` and `09 - Audits/Payment Provider Adapter Spec.md`.
|
||||||
|
|
||||||
Document createPayInIntent, getPayInStatus, handleProviderWebhook, createHostedPaymentLink, createReleaseInstruction, createRefundInstruction, getPayoutStatus, searchProviderPayments, raw-body signature verification, replay prevention, delivery ID idempotency, duplicate/unknown event behavior, retry semantics, dead-letter/replay storage, and alert thresholds.
|
Document createPayInIntent, getPayInStatus, handleProviderWebhook, createHostedPaymentLink, createReleaseInstruction, createRefundInstruction, getPayoutStatus, searchProviderPayments, raw-body signature verification, replay prevention, delivery ID idempotency, duplicate/unknown event behavior, retry semantics, dead-letter/replay storage, and alert thresholds.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
taskmaster_id: "4.8"
|
taskmaster_id: "4.8"
|
||||||
status: "pending"
|
status: "done"
|
||||||
priority: "medium"
|
priority: "medium"
|
||||||
depends_on: ["2", "3", "4", "5", "6", "7"]
|
depends_on: ["2", "3", "4", "5", "6", "7"]
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-24T07:26:29.052Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.8 - Make backend-core stack decision
|
# 4.8 - Make backend-core stack decision
|
||||||
|
|
||||||
- [ ] 4.8 - Make backend-core stack decision #taskmaster #priority/medium #status/pending 🔼 🆔 tm-4-8 ⛔ tm-2 ⛔ tm-3 ⛔ tm-4 ⛔ tm-5 ⛔ tm-6 ⛔ tm-7
|
- [x] 4.8 - Make backend-core stack decision #taskmaster #priority/medium #status/done 🔼 🆔 tm-4-8 ⛔ tm-2 ⛔ tm-3 ⛔ tm-4 ⛔ tm-5 ⛔ tm-6 ⛔ tm-7
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Taskmaster ID | 4.8 |
|
| Taskmaster ID | 4.8 |
|
||||||
| Status | pending |
|
| Status | done |
|
||||||
| Priority | medium |
|
| Priority | medium |
|
||||||
| Dependencies | 2, 3, 4, 5, 6, 7 |
|
| Dependencies | 2, 3, 4, 5, 6, 7 |
|
||||||
| Parent | 4 - Define backend security and refactor strategy from latest audit |
|
| Parent | 4 - Define backend security and refactor strategy from latest audit |
|
||||||
@@ -28,6 +28,8 @@ Choose whether the security-critical backend core remains TypeScript or moves to
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
|
Completed. Produced `09 - Audits/Backend Core Stack Decision Record - 2026-05-24.md`.
|
||||||
|
|
||||||
Evaluate team capability, two-year maintainability, operational footprint, rewrite cost, dual-stack complexity, auditability, supply-chain exposure, and which modules belong in a payment/auth/escrow core versus the existing marketplace/chat API.
|
Evaluate team capability, two-year maintainability, operational footprint, rewrite cost, dual-stack complexity, auditability, supply-chain exposure, and which modules belong in a payment/auth/escrow core versus the existing marketplace/chat API.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
taskmaster_id: "4.9"
|
taskmaster_id: "4.9"
|
||||||
status: "pending"
|
status: "done"
|
||||||
priority: "medium"
|
priority: "medium"
|
||||||
depends_on: ["8"]
|
depends_on: ["8"]
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-24T07:26:29.052Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.9 - Create migration and operational runbooks
|
# 4.9 - Create migration and operational runbooks
|
||||||
|
|
||||||
- [ ] 4.9 - Create migration and operational runbooks #taskmaster #priority/medium #status/pending 🔼 🆔 tm-4-9 ⛔ tm-8
|
- [x] 4.9 - Create migration and operational runbooks #taskmaster #priority/medium #status/done 🔼 🆔 tm-4-9 ⛔ tm-8
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Taskmaster ID | 4.9 |
|
| Taskmaster ID | 4.9 |
|
||||||
| Status | pending |
|
| Status | done |
|
||||||
| Priority | medium |
|
| Priority | medium |
|
||||||
| Dependencies | 8 |
|
| Dependencies | 8 |
|
||||||
| Parent | 4 - Define backend security and refactor strategy from latest audit |
|
| Parent | 4 - Define backend security and refactor strategy from latest audit |
|
||||||
@@ -28,6 +28,8 @@ Document rollout, rollback, and incident response for the selected backend/funds
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
|
Completed. Produced `08 - Operations/Backend Funds Migration and Operational Runbooks.md`.
|
||||||
|
|
||||||
Include SHKeeper legacy read path, provider feature flag, ledger backfill, validation report before enforcement, rollback criteria, webhook cutoff, manual reconciliation, failed webhook, duplicate/missing payment, stuck release, disputed release attempt, compromised admin, leaked API key, provider outage, chain/RPC outage, suspicious payment proof, and npm/package compromise.
|
Include SHKeeper legacy read path, provider feature flag, ledger backfill, validation report before enforcement, rollback criteria, webhook cutoff, manual reconciliation, failed webhook, duplicate/missing payment, stuck release, disputed release attempt, compromised admin, leaked API key, provider outage, chain/RPC outage, suspicious payment proof, and npm/package compromise.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
taskmaster_id: "4"
|
taskmaster_id: "4"
|
||||||
status: "in-progress"
|
status: "done"
|
||||||
priority: "high"
|
priority: "high"
|
||||||
depends_on: []
|
depends_on: []
|
||||||
parent_id: ""
|
parent_id: ""
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-24T07:26:29.052Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4 - Define backend security and refactor strategy from latest audit
|
# 4 - Define backend security and refactor strategy from latest audit
|
||||||
|
|
||||||
- [ ] 4 - Define backend security and refactor strategy from latest audit #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-4
|
- [x] 4 - Define backend security and refactor strategy from latest audit #taskmaster #priority/high #status/done ⏫ 🆔 tm-4
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Taskmaster ID | 4 |
|
| Taskmaster ID | 4 |
|
||||||
| Status | in-progress |
|
| Status | done |
|
||||||
| Priority | high |
|
| Priority | high |
|
||||||
| Dependencies | None |
|
| Dependencies | None |
|
||||||
| Parent | None |
|
| Parent | None |
|
||||||
|
|||||||
Reference in New Issue
Block a user