diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..d413811 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,94 @@ + + +## Summary + +Provide a concise description of the change and the motivation. + +## Related Issue + +Closes #129 + +## What I changed + +- Added Escrow, Dispute and AuditLog Mongoose models +- Implemented a `DisputeService` with lock and resolution logic +- Added `DisputeController` and versioned routes under `/api/v1/disputes` +- Added audit logging for admin actions + +## Files of interest + +- src/models/Escrow.ts +- src/models/Dispute.ts +- src/models/AuditLog.ts +- src/services/disputeService.ts +- src/controllers/disputeController.ts +- src/routes/disputeRoutes.ts +- src/routes/index.ts + +## How to test locally + +1. Ensure `.env` contains a working `MONGODB_URI` (or run MongoDB locally). +2. Install dependencies: + +```bash +pnpm install +``` + +3. Run tests: + +```bash +pnpm test +``` + +4. Start the dev server: + +```bash +pnpm run dev +``` + +5. Example API calls (adjust host/port if needed): + +Lock an escrow (admin): + +```bash +curl -X POST http://localhost:3000/api/v1/disputes//lock \ + -H "Content-Type: application/json" \ + -d '{"adminId":"", "reason":"Buyer reports damaged goods"}' +``` + +Resolve a dispute (refund or release): + +```bash +curl -X POST http://localhost:3000/api/v1/disputes//resolve \ + -H "Content-Type: application/json" \ + -d '{"adminId":"", "action":"refund", "notes":"Refund approved"}' +``` + +Fetch dispute details: + +```bash +curl http://localhost:3000/api/v1/disputes/ +``` + +## Acceptance Criteria Mapping + +- Controller -> Service -> Model architecture: implemented +- Persistence: data saved to MongoDB; no hardcoded mocks +- API Versioning: endpoints registered under `/api/v1` +- Robust error handling: service and controller validate inputs and return errors + +## Checklist + +- [ ] Code follows repo conventions and lints +- [ ] Unit/integration tests added for critical logic (could be added in follow-up) +- [x] All existing tests pass +- [x] PR references related issue: Closes #129 + +## Proof of Work + +Attach a screenshot of successful API response or test output. Example: terminal output of `pnpm test` or a Postman request showing success. + +## Notes for reviewers + +- This PR adds new models and routes; ensure DB indices and migration steps are acceptable. +- Admin authorization is not enforced in this change — recommend adding RBAC middleware in a follow-up. diff --git a/PR_DOCS/129-escrow-dispute-resolution.md b/PR_DOCS/129-escrow-dispute-resolution.md new file mode 100644 index 0000000..2406684 --- /dev/null +++ b/PR_DOCS/129-escrow-dispute-resolution.md @@ -0,0 +1,47 @@ +# PR: Escrow Dispute Resolution (Closes #129) + +Summary +------- + +This PR adds an Escrow Dispute Resolution flow that allows admins to lock escrows, create dispute records, and resolve disputes by refunding the buyer or releasing funds to the driver. It implements a Controller -> Service -> Model layered architecture and records every admin action in an Audit Log. + +Key changes +----------- + +- `src/models/Escrow.ts` — Escrow schema and status fields +- `src/models/Dispute.ts` — Dispute schema with history entries +- `src/models/AuditLog.ts` — AuditLog schema to capture actions +- `src/services/disputeService.ts` — Business logic for locking and resolving escrows +- `src/controllers/disputeController.ts` — API handlers for disputes +- `src/routes/disputeRoutes.ts` — Routes registered under `/api/v1/disputes` +- `src/routes/index.ts` — Registered the disputes routes + +Why this change +--------------- + +To provide a manual arbitration mechanism enabling admins to temporarily lock funds in escrow and resolve disputes off-chain, while keeping a complete audit trail in the database. + +How to run & verify +------------------- + +1. Install deps: `pnpm install` +2. Run tests: `pnpm test` (existing test suite passed locally) +3. Start server: `pnpm run dev` +4. Use the example `curl` commands in the PR template to lock and resolve a dispute. Replace ``, ``, and `` where required. + +Security & Follow-ups +--------------------- + +- This PR does not add RBAC enforcement — please ensure admin-only access is applied by adding existing auth middleware to the dispute routes. +- Consider adding integration tests around the dispute lifecycle. + +Proof of Work +------------- + +Attach here a screenshot of `pnpm test` output or a Postman screenshot showing a successful API response. The test run used in CI locally returned: `PASS tests/health.test.ts`. + +Reviewer Notes +-------------- + +- Review schema choices and field names for consistency with existing models. +- Confirm whether `sorobanTxId` or additional blockchain fields should be set when resolving disputes. diff --git a/src/models/AuditLog.ts b/src/models/AuditLog.ts new file mode 100644 index 0000000..5bbefae --- /dev/null +++ b/src/models/AuditLog.ts @@ -0,0 +1,25 @@ +import mongoose, { Document, Schema } from 'mongoose'; + +export interface IAuditLog extends Document { + action: string; + actor?: mongoose.Types.ObjectId | null; + targetType?: string; + targetId?: mongoose.Types.ObjectId | null; + description?: string; + meta?: Record | null; + createdAt: Date; +} + +const AuditLogSchema: Schema = new Schema( + { + action: { type: String, required: true }, + actor: { type: Schema.Types.ObjectId, ref: 'User', default: null }, + targetType: { type: String, default: null }, + targetId: { type: Schema.Types.ObjectId, default: null }, + description: { type: String, default: null }, + meta: { type: Schema.Types.Mixed, default: null }, + }, + { timestamps: { createdAt: true, updatedAt: false } }, +); + +export default mongoose.model('AuditLog', AuditLogSchema);