Skip to content

Manual student enrollment: tier bypass + payment bookkeeping - #93

Open
projectamazonph wants to merge 4 commits into
mainfrom
claude/manual-student-enrollment-tier-w9lva5
Open

Manual student enrollment: tier bypass + payment bookkeeping#93
projectamazonph wants to merge 4 commits into
mainfrom
claude/manual-student-enrollment-tier-w9lva5

Conversation

@projectamazonph

@projectamazonph projectamazonph commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • Surfaced the existing manual-enrollment flow (/admin/enroll — grant a pricing tier without a PayMongo payment, for students paying outside the platform) in the admin sidebar nav, where it wasn't previously linked.
  • Added an optional payment-bookkeeping step to that flow: admin can record how the student actually paid (method, amount, free-text reference like a GCash ref # or bank slip note) when granting a tier. This creates a single COMPLETED Payment row for the grant (not tied to a single course enrollment, since a tier can bundle several courses), which now shows up under the student's Payments on /admin/users/[id]. Recording payment is optional — comp/free grants still work with no Payment row created.
  • Fixed a pre-existing bug on the student detail page: the Payments badge checked payment.status === 'PAID', a value the app never sets (the real enum value is 'COMPLETED'), so completed payments always rendered as the default gray badge instead of green/success.

Test plan

  • pnpm typecheck — confirmed the touched files introduce no new errors (63 pre-existing errors both before and after this change, all from the ungenerated Prisma client in the sandbox with no DATABASE_URL)
  • eslint on all changed files — clean
  • Manual smoke test against a real Postgres: /admin/enroll → check "record a payment" → submit → confirm Payment row appears on /admin/users/[id] with correct method/amount/reference and a green "COMPLETED" badge

Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Added an “Enroll student” option to the admin navigation.
    • Admins can optionally record payment details during manual enrollment, including method, amount, and reference.
    • Enrollment results now indicate whether payment was recorded.
    • Payment history displays payment methods and additional metadata when available.
  • Bug Fixes
    • Corrected payment status display for completed payments.
  • UI Improvements
    • Added supporting payment fields, styling, and enrollment icons.

claude added 2 commits July 30, 2026 03:33
The manual enrollment flow at /admin/enroll (grant a pricing tier
without a PayMongo payment) existed but was only reachable via direct
URL or from a student's detail page, not from the main admin nav.
/admin/enroll now lets the admin note how a student paid outside the
platform (method, amount, free-text reference) when granting a tier.
grantManualEnrollment() creates a single COMPLETED Payment row for the
grant (not tied to one course enrollment, since a tier can bundle
several) so it shows up under the student's Payments in the admin
panel. Recording payment is optional — comp/free grants still work
exactly as before with no Payment row.

Also fixed the Payments badge on the student detail page, which
checked payment.status against 'PAID', a value the app never uses
(the real enum value is 'COMPLETED'), so completed payments always
rendered as the default gray badge.
Copilot AI review requested due to automatic review settings July 30, 2026 03:41

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@projectamazonph, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 49 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 82167953-a840-45c6-9559-88511dcbad82

📥 Commits

Reviewing files that changed from the base of the PR and between 9927bce and 7cc4120.

📒 Files selected for processing (3)
  • src/app/actions/admin-enroll.ts
  • src/lib/__tests__/enrollment.test.ts
  • src/lib/enrollment.ts
📝 Walkthrough

Walkthrough

Manual enrollment now optionally records completed payments, validates and audits payment details, exposes payment fields in the admin form, and displays payment status and metadata in admin user records.

Changes

Manual enrollment payment recording

Layer / File(s) Summary
Payment contract and persistence
src/lib/enrollment.ts
Manual enrollment accepts optional payment input, creates a completed payment row within the transaction, and returns paymentRecorded.
Admin action validation and audit
src/app/actions/admin-enroll.ts
Payment method, amount, and reference are validated, forwarded to enrollment, included in audit metadata, and returned in the action result.
Enrollment form payment entry
src/app/admin/enroll/EnrollForm.tsx, src/app/admin/enroll/page.tsx, src/app/admin/enroll/enroll.module.css
The form records optional payment method, amount, and reference values, prefills tier pricing, submits converted amounts, and displays the recording result.
Admin payment navigation and display
src/components/ui/Icon.tsx, src/components/ui/NavSidebar.tsx, src/app/admin/users/[id]/page.tsx
Admin navigation adds the enrollment entry and icon, while user payment entries show completed status, method, and metadata.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  actor Admin
  participant EnrollForm
  participant manualEnrollAction
  participant grantManualEnrollment
  participant PaymentStore

  Admin->>EnrollForm: Enter enrollment and optional payment
  EnrollForm->>manualEnrollAction: Submit validated payment payload
  manualEnrollAction->>grantManualEnrollment: Forward enrollment and payment
  grantManualEnrollment->>PaymentStore: Create completed payment row
  grantManualEnrollment-->>manualEnrollAction: Return paymentRecorded
  manualEnrollAction-->>EnrollForm: Return enrollment result
  EnrollForm-->>Admin: Show payment recorded status
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: manual student enrollment with payment bookkeeping support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/manual-student-enrollment-tier-w9lva5

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/enrollment.ts`:
- Around line 153-177: Make manual tier-grant payment and audit recording
retry-safe and atomic: in src/lib/enrollment.ts lines 153-177, add durable
idempotency for the grant, avoid creating payments when toCreate is empty, and
derive paymentRecorded from the actual insert result; in
src/app/actions/admin-enroll.ts lines 66-78, persist the audit entry within the
same transaction or via a durable outbox so committed mutations cannot return
unaudited errors. Add regression tests covering retries and audit-write
failures, asserting exactly one payment and one audit record.
- Around line 154-155: Update the comment describing the tier payment behavior
near the enrollment grant logic to replace the em dash with an allowed
punctuation mark, preserving the existing meaning and wording.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9dfb8ed7-60a2-4461-818d-bf0f7097d545

📥 Commits

Reviewing files that changed from the base of the PR and between dabee94 and 9927bce.

📒 Files selected for processing (8)
  • src/app/actions/admin-enroll.ts
  • src/app/admin/enroll/EnrollForm.tsx
  • src/app/admin/enroll/enroll.module.css
  • src/app/admin/enroll/page.tsx
  • src/app/admin/users/[id]/page.tsx
  • src/components/ui/Icon.tsx
  • src/components/ui/NavSidebar.tsx
  • src/lib/enrollment.ts

Comment thread src/lib/enrollment.ts
Comment thread src/lib/enrollment.ts Outdated
claude added 2 commits July 30, 2026 03:48
Addresses a CodeRabbit review finding on PR #93: the AuditLog write
happened as a separate db call after the enrollment/payment
transaction committed. If that write failed, the action returned an
error even though the Payment row already existed — and since nothing
gated payment creation on idempotency, retrying the same submission
would create a duplicate COMPLETED payment.

grantManualEnrollment() now accepts an `audit` context and writes the
AuditLog row with the same transaction client as the enrollment and
payment writes, so the whole grant commits or rolls back together.

Also fixed an em dash CodeRabbit flagged in a comment (repo style
guidelines prohibit them).

Not done: a durable idempotency key / outbox pattern for the payment
write itself, which CodeRabbit's suggestion also called for. This is
a low-traffic, solo-admin internal tool where an accidental duplicate
payment is easy to spot and soft-delete in the admin UI; the atomicity
fix above removes the concrete failure mode described (committed
payment reported as failed, prompting a retry). Skipping the added
infra as disproportionate to this feature's scope.
CI's Quality Gates job failed on 3eca663: global branch coverage
dropped to 68.39%, below the 70% threshold, because the new
if (payment) / if (audit) branches in grantManualEnrollment() had no
test coverage. Adds three cases to enrollment.test.ts: no payment/audit
provided, a payment + audit recorded together (asserting the Payment
and AuditLog write shapes, including the JSON metadata), and audit
provided without a payment (null metadata). enrollment.ts branch
coverage goes from 57.14% to 92.85%, bringing the global figure to
71.55%.
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.

3 participants