Skip to content

feat: per-specialty doctor credential verification (#51) - #145

Open
Dev-Marcy wants to merge 6 commits into
DocForum:mainfrom
Dev-Marcy:feat/global-api-rate-limiting
Open

Dev-Marcy wants to merge 6 commits into
DocForum:mainfrom
Dev-Marcy:feat/global-api-rate-limiting

Conversation

@Dev-Marcy

Copy link
Copy Markdown

Closes #51

Summary

This PR adds per-specialty credential verification to DocForum. Previously, doctor
verification was a single binary status on the entire doctor profile (pending |
verified | rejected). That is insufficient for the product: a doctor's credentials
may be valid for some specialties (e.g., cardiology) and not others (e.g.,
dermatology). This PR introduces specialty-level verification tracking so that each
doctor–specialty pair can be independently verified, reviewed, and rejected.

Feature: Per-specialty verification fields

New columns added to the DoctorSpecialty join table via
prisma/migrations/20261016110000_add_specialty_verification/migration.sql:

Column Type Purpose
verificationStatus VARCHAR(191) pending
reviewer VARCHAR(191) Admin user ID who performed the review
reviewDate TIMESTAMP(3) When the verification was recorded
rejectionReason VARCHAR(191) Free-text explanation of why a doctor was rejected

Existing DoctorSpecialty rows are backfilled to verification_status = 'pending'
in the migration, since there is no mechanism to retroactively verify legacy data.
Preview/demo data is treated as unverified until an admin reviews each specialty.

New endpoint: admin per-specialty review

Buffy and others added 2 commits October 16, 2026 11:22
- Add specialty-level verification fields (status, reviewer, review date,
  rejection reason) to DoctorSpecialty via migration
- Add admin endpoints for listing and reviewing per-specialty verification
- Filter specialty-based search results to only include verified
  doctor-specialty pairs

Co-Authored-By: Buffy <noreply@codebuff.com>
…buckets

- Add configurable token-bucket rate limiter keyed by authenticated user
  ID or client IP (behind Render's proxy)
- Postgres-backed store with in-memory test implementation
- Return HTTP 429 with Retry-After and RateLimit-* headers
- Exempt /health endpoint
- Preserve existing login throttling without double-counting
- Add in-memory store for tests and overhead measurement
- Add unit tests for rate limit behavior

Co-Authored-By: Buffy <noreply@codebuff.com>
@drips-wave

drips-wave Bot commented Oct 16, 2026

Copy link
Copy Markdown

@Dev-Marcy Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Dev-Marcy pls fix CI

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

CI is failing on this PR. main itself is green, so the cause is in this branch:

Typecheck fails: src/modules/rate-limit/index.ts(3,31): Module './types' has no exported member 'RateLimitRecord'. RateLimitRecord is declared in rate-limit/repositories/index.ts, not types.ts. Fix the re-export path. This branch is also 3 commits behind main. Note that #146 has the same failure and overlaps heavily with this PR. Could you close one, or explain how they differ?

Please push a fix and CI will re-run. Before pushing, run npm run prisma:generate && npm run typecheck && npm test && npm run test:integration in backend/.

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Dev-Marcy

Heads-up: #145 and #146 point at the same commit (cecb3d3), so they're duplicates, even though one title says #50 and the other #51 and the branch names differ (feat/global-api-rate-limiting vs feat/per-specialty-credential-verification-for-doctors). Please close one of them, and give each issue its own branch with only its own changes.

CI is red on typecheck in the rate-limit module:

  • rate-limit/types doesn't export RateLimitRecord
  • prisma.$countRateLimitRecord doesn't exist (did you mean prisma.rateLimitRecord.count()?)
  • config.rateLimit isn't defined in src/config
  • there are unused-declaration errors too

Please rebase onto the latest main (it's on Prisma 7 now, #151) and get npm run typecheck passing locally.

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Dev-Marcy Thanks for the PR. It can't be merged yet. To unblock it:

CI is failing. Here's what broke:

Backend (typecheck + test + build):

src/modules/rate-limit/index.ts(3,31): error TS2305: Module './types' has no exported member 'RateLimitRecord'.
src/modules/rate-limit/repositories/index.ts(35,38): error TS2551: Property '$countRateLimitRecord' does not exist on PrismaClient
src/modules/rate-limit/services/index.ts(15,43): error TS2339: Property 'rateLimit' does not exist on config

Please fix these errors and run the same steps locally before pushing (npm run typecheck && npm test && npm run build, or cargo test for contracts).

Branch protection also requires the branch to be up to date with main, so please rebase onto the latest main when you push the fix.

Push to this same branch and CI will re-run. Once it's green and conflict-free, it'll be reviewed for merge.

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Dev-Marcy CI is failing on this branch, so it can't be merged yet. The errors from the latest run:

Backend (typecheck + test + build)

src/modules/rate-limit/index.ts(3,31): error TS2305: Module '"./types"' has no exported member 'RateLimitRecord'.
src/modules/rate-limit/repositories/index.ts(2,15): error TS6196: 'RateLimitStore' is declared but never used.
src/modules/rate-limit/repositories/index.ts(24,9): error TS6133: 'record' is declared but its value is never read.
src/modules/rate-limit/repositories/index.ts(35,38): error TS2551: Property '$countRateLimitRecord' does not exist on type 'PrismaClient<{ adapter: PrismaPg; }, never, DefaultArgs>'. Did you mean 'rateLimitRecord'?
src/modules/rate-limit/repositories/index.ts(58,38): error TS2551: Property '$countRateLimitRecord' does not exist on type 'PrismaClient<{ adapter: PrismaPg; }, never, DefaultArgs>'. Did you mean 'rateLimitRecord'?
src/modules/rate-limit/services/index.ts(126,9): error TS6133: 'result' is declared but its value is never read.
src/modules/rate-limit/services/index.ts(15,43): error TS2339: Property 'rateLimit' does not exist on type '{ readonly port: number; readonly databaseUrl: string; readonly jwt: { readonly accessSecret: string; readonly refreshSecret: string; readonly accessTtl
src/modules/rate-limit/services/index.ts(16,38): error TS2339: Property 'rateLimit' does not exist on type '{ readonly port: number; readonly databaseUrl: string; readonly jwt: { readonly accessSecret: string; readonly refreshSecret: string; readonly accessTtl

Please reproduce this locally, fix the errors above and push. CI will re-run on your next push.

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Dev-Marcy CI is failing on this branch against the latest main, so it can't be merged yet. The errors from the latest run:

Backend (typecheck + test + build)

src/modules/rate-limit/index.ts(3,31): error TS2305: Module '"./types"' has no exported member 'RateLimitRecord'.
src/modules/rate-limit/repositories/index.ts(2,15): error TS6196: 'RateLimitStore' is declared but never used.
src/modules/rate-limit/repositories/index.ts(24,9): error TS6133: 'record' is declared but its value is never read.
src/modules/rate-limit/repositories/index.ts(35,38): error TS2551: Property '$countRateLimitRecord' does not exist on type 'PrismaClient<{ adapter: PrismaPg; }, never, DefaultArgs>'. Did you mean 'rateLimitRecord'?
src/modules/rate-limit/repositories/index.ts(58,38): error TS2551: Property '$countRateLimitRecord' does not exist on type 'PrismaClient<{ adapter: PrismaPg; }, never, DefaultArgs>'. Did you mean 'rateLimitRecord'?
src/modules/rate-limit/services/index.ts(4,15): error TS2305: Module '"../types"' has no exported member 'RateLimitRecord'.
src/modules/rate-limit/services/index.ts(4,15): error TS6196: 'RateLimitRecord' is declared but never used.
src/modules/rate-limit/services/index.ts(15,43): error TS2339: Property 'rateLimit' does not exist on type '{ readonly port: number; readonly databaseUrl: string; readonly jwt: { readonly accessSecret: string; readonly refreshSecret: string; readonly accessTtl

Reproduce this locally on the latest main, fix the errors above, and push.

@github-actions github-actions Bot added the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 21, 2026
@github-actions

Copy link
Copy Markdown

@Dev-Marcy This PR now has merge conflicts with main, most likely because #211 (feat(referrals): route specialty-only referrals to the least-loaded e…) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-core.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

This branch has not been deployed

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

Labels

needs-rebase Has merge conflicts with main; the author needs to rebase

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Phase 2] Per-specialty credential verification for doctors (PRD §8.1.5)

2 participants