Skip to content

feat: normalize payout milestones (#110) - #130

Open
kimanicode wants to merge 1 commit into
Eduvault-stellar:mainfrom
kimanicode:fix/milestone-normalization-110
Open

feat: normalize payout milestones (#110)#130
kimanicode wants to merge 1 commit into
Eduvault-stellar:mainfrom
kimanicode:fix/milestone-normalization-110

Conversation

@kimanicode

Copy link
Copy Markdown

Summary

closes #110: normalizes payout milestones out of a JSON blob on Payout.milestones into proper milestones, milestone_evidence, and milestone_history collections, with a zero-downtime expand/backfill/verify migration.

Note: the issue text references prisma/schema.prisma, useMilestoneActions.ts, and ManageMilestonesDialog.tsx - none of these exist in this repo (it's MongoDB-based, no Prisma). This PR implements the real equivalents under their actual names/extensions (schemaContracts.js, useMilestoneActions.js, ManageMilestonesDialog.jsx).

What changed

Schema / migration

  • schemaContracts.js - added milestones, milestone_evidence, milestone_history to COLLECTIONS, added indexes and validators for all three, and kept the legacy milestones array on payouts for backward compatibility during rollout
  • migrations/005-normalize-payout-milestones.js - expand/backfill/verify migration with a down() to drop the new collections/indexes if needed. Handles null, empty, legacy-shaped, and malformed milestone payloads explicitly, with an exception report rather than silent skipping
  • Registered as migration v5 in migrations/registry.js

Service layer

  • milestoneService.js - dual-read (normalized model, falls back to legacy JSON), dual-write (writes the new model and keeps payout.milestones in sync during rollout), optimistic concurrency via a version field, and evidence/history CRUD

API routes (none of these existed before this PR - useEscrow.js already referenced /api/escrows/:id/milestones, but the route itself was missing)

  • GET/POST /api/escrows/[escrowId]/milestones
  • GET/PUT/DELETE /api/milestones/[milestoneId] (PUT uses optimistic concurrency)
  • POST /api/milestones/[milestoneId]/submit
  • POST /api/milestones/[milestoneId]/approve
  • POST /api/milestones/[milestoneId]/reject
  • GET/POST /api/milestones/[milestoneId]/evidence

Frontend

  • hooks/useMilestoneActions.js - mutation hooks for create/update/submit/approve/reject/addEvidence
  • components/milestones/ManageMilestonesDialog.jsx - milestone management modal

Docs

  • docs/payout-milestone-migration-runbook.md - expand/backfill/verify runbook, including rollback procedure and the contract-phase plan

Unrelated fix included

Found and fixed a pre-existing syntax bug in schemaContracts.js: the upload_quarantine entry in REQUIRED_INDEXES was missing a closing ],. Small, low-risk, but genuinely unrelated to milestones - flagging so it's not confused with in-scope work during review.

Concurrency safety

Milestone updates now go through targeted, per-document operations with an optimistic-concurrency version check, instead of whole-blob read-modify-write on Payout.milestones - concurrent updates to different milestones on the same payout can no longer clobber each other.

Tests

  • tests/backend/payout-milestone-migration.test.mjs - 19 tests: payload handling (empty/null/legacy/malformed), idempotency, and verification-mismatch detection
  • tests/backend/milestone-api-routes.test.mjs - 12 integration tests covering milestoneService reads, transitions, and evidence
  • Extended tests/backend/helpers/fakeMongo.mjs with .sort(), $push, and .aggregate() support, needed by the new service/tests
  • 31/31 passing

Acceptance criteria

  • Migration handles empty, null, legacy, and malformed milestone payloads with an exception report
  • Backfill is idempotent and safe to resume
  • No milestone data lost - verification checks source/target counts and amount totals
  • Concurrent milestone updates cannot overwrite unrelated milestones (per-document ops + optimistic concurrency)
  • API and UI behavior covered by migration and integration tests
  • Rollback and production runbooks documented

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[DATA]: Normalize payout milestones and deliver a zero-downtime JSON migration

1 participant