fix: resolve #807, #808, #809, #810 — ID retry, dashboard pagination, E2E webhook/SSE, report index - #1
Open
topsonDev wants to merge 1 commit into
Open
fix: resolve #807, #808, #809, #810 — ID retry, dashboard pagination, E2E webhook/SSE, report index#1topsonDev wants to merge 1 commit into
topsonDev wants to merge 1 commit into
Conversation
…tellarEdu#810 StellarEdu#807 — generateStudentId collision retry - Track whether a studentId was auto-generated in registerStudent. - Hoist assignedFee/assignedDeadline to function scope so the catch block can access them during a retry. - On a MongoDB 11000 duplicate-key error with an auto-generated ID, call generateStudentId() again (up to MAX_ID_RETRIES attempts) and retry Student.create() with the new candidate, instead of surfacing an opaque 409 to the client. - Only propagate DUPLICATE_STUDENT (409) when the caller supplied the ID explicitly, or when all retry attempts are exhausted. StellarEdu#808 — Frontend dashboard pagination - Server-side pagination, search, status/class filters, and stat counts from server aggregates were already present in dashboard.jsx and the /students + /payments/summary API routes. No additional changes required; confirmed the implementation satisfies acceptance criteria. StellarEdu#809 — E2E payment pipeline webhook + SSE assertions - Added Scenario 7 to tests/e2e/paymentPipeline.e2e.test.js: sets a webhookUrl on the school, spies on webhookService.notifyPaymentConfirmed, calls verifyPayment, and asserts the webhook was fired with the correct URL, payment payload, and HMAC secret. - Added Scenario 8: spies on sseService.emit, triggers syncAllPayments with a matched transaction, and asserts the SSE 'payment' event was emitted on the correct school channel. - Both tests run against mongodb-memory-server with no real network calls. StellarEdu#810 — Compound index alignment for report queries - reportService.aggregateByDate: added deletedAt: null to the $match stage. Without it the query did not satisfy the partial index filter expression ({ studentDeleted: {$ne: true}, deletedAt: null }) and MongoDB fell back to a COLLSCAN on large collections. - Added hint({ schoolId: 1, status: 1, confirmedAt: -1 }) to the aggregate call so the planner always picks the partial compound index and never performs an in-memory sort on confirmedAt. - getDashboardMetrics already included deletedAt: null in all its $match stages; no further changes were needed there. Closes StellarEdu#807 Closes StellarEdu#808 Closes StellarEdu#809 Closes StellarEdu#810
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR resolves four open issues in a single batch.
StellarEdu#807 — generateStudentId collision retry
Problem: Under concurrency, two registrations could pass the
Student.exists()check simultaneously, then both callStudent.create(). The second write hit the unique index and surfaced as an opaque 409.Fix (
backend/src/controllers/studentController.js):autoGeneratedflag when nostudentIdis supplied in the request body.assignedFee/assignedDeadlineto function scope so thecatchblock can access them during a retry.generateStudentId()again (up toMAX_ID_RETRIESattempts) and retryStudent.create()with the new candidate.DUPLICATE_STUDENT(409) when the caller supplied the ID explicitly, or after all retry attempts are exhausted.StellarEdu#808 — Frontend dashboard pagination
Finding:
frontend/src/pages/dashboard.jsxalready implements full server-side pagination, debounced search, status/class filters, and skeleton loading. Stat counts are sourced from the/payments/summaryaggregate endpoint. The acceptance criteria are satisfied by the existing implementation; no code changes were required.StellarEdu#809 — E2E test: webhook + SSE side effects
Problem: The pipeline E2E test suite had no assertions covering the webhook and SSE side effects that fire after a successful payment.
Fix (
tests/e2e/paymentPipeline.e2e.test.js):webhookUrlon the school, spies onwebhookService.notifyPaymentConfirmed, callsverifyPayment, and asserts the webhook was fired with the correct URL, payment payload (txHash,status: 'SUCCESS'), and HMAC secret.sseService.emit, triggerssyncAllPaymentswith a matched transaction, and asserts the'payment'event was emitted on the correct school channel with the expectedtxHash.mongodb-memory-serverwith no real network calls; CI-safe.StellarEdu#810 — Compound index alignment for report queries
Problem:
reportService.aggregateByDatematched{ schoolId, status: 'SUCCESS', studentDeleted: { $ne: true } }but omitteddeletedAt: null. The partial compound index onpaymentshaspartialFilterExpression: { studentDeleted: { $ne: true }, deletedAt: null }. Without both conditions the planner could not use the index and fell back to a COLLSCAN.Fix (
backend/src/services/reportService.js):deletedAt: nullto the$matchstage inaggregateByDateso the query fully satisfies the partial filter expression.hint({ schoolId: 1, status: 1, confirmedAt: -1 })to the aggregate call to pin the planner to the partial compound index and prevent in-memory sorts onconfirmedAt.getDashboardMetricsalready includesdeletedAt: nullin all its$matchstages; no further changes needed.Files changed
backend/src/controllers/studentController.jsbackend/src/services/reportService.jstests/e2e/paymentPipeline.e2e.test.jsTesting
mongodb-memory-serverand the existingfakeHorizonfixture.Closes StellarEdu#807
Closes StellarEdu#808
Closes StellarEdu#809
Closes StellarEdu#810