Skip to content

feat: implement automated refresh token cleanup and schema optimization#583

Open
udaycodespace wants to merge 4 commits into
Dev-Card:mainfrom
udaycodespace:feat/543-refresh-token-cleanup
Open

feat: implement automated refresh token cleanup and schema optimization#583
udaycodespace wants to merge 4 commits into
Dev-Card:mainfrom
udaycodespace:feat/543-refresh-token-cleanup

Conversation

@udaycodespace

@udaycodespace udaycodespace commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements automated refresh token cleanup for expired and revoked refresh tokens.

This PR adds automated cleanup of stale refresh tokens, database indexes to support cleanup queries, scheduler integration, and test coverage to verify cleanup behavior while ensuring active tokens remain untouched.

Closes #543


Type of Change

  • Bug fix
  • New feature
  • Refactor (no functional change)
  • UI / Design change
  • Tests only
  • Documentation
  • Infrastructure / DevOps
  • Security

What Changed

Area Change
Database Added indexes on RefreshToken.expiresAt and RefreshToken.revokedAt
Service Added refreshTokenCleanupService.ts for expired/revoked token cleanup
Plugin Added refreshTokenCleanup.ts scheduled cleanup plugin
Startup Cleanup runs automatically on application startup
Scheduling Supports configurable cleanup intervals via environment variable
Logging Added structured success/failure logging
Shutdown Scheduler is cleaned up using onClose
Config Added REFRESH_TOKEN_CLEANUP_INTERVAL_MS to .env.example
Testing Added service and plugin test coverage

How to Test

Type Check

npm --prefix apps/backend run typecheck

Run Cleanup Tests

npx vitest run apps/backend/src/__tests__/refreshTokenCleanup.test.ts

Verify

  • Active refresh tokens are not matched by the cleanup query
  • Revoked refresh tokens are eligible for deletion
  • Expired refresh tokens are eligible for deletion
  • Invalid interval values fall back to the default interval

Checklist

  • TypeScript compiles successfully
  • Added automated tests
  • Tests pass locally
  • No debug statements left in code
  • Configuration updated where required

Validation

Check Result
TypeScript Typecheck [x] Passed
Cleanup Test Suite [x] 16/16 Passed
Startup Cleanup [x] Verified
Scheduled Cleanup [x] Verified
Invalid Interval Fallback [x] Verified
Error Handling [x] Verified
Scheduler Shutdown [x] Verified
Working Tree [x] Clean

Screenshots / Recordings

Files changed

1

Test execution (16/16 passing)

2

TypeScript validation

3

Commit and repository status

4

Additional Context

Active Token Safety

The cleanup query only targets:

revokedAt != null

OR

expiresAt < now

Active refresh tokens satisfy:

revokedAt == null

AND

expiresAt > now

Therefore active refresh tokens cannot match the cleanup query and are not deleted.

Demo Video

The issue requests a demo video showing cleanup behavior.

For now, I have attached validation screenshots showing the implementation, test execution, type checking, and repository status.

If review feedback results in additional changes, I will address those first and then record a final demo video covering the complete cleanup workflow to avoid re-recording multiple times.

@vercel

vercel Bot commented Jun 16, 2026

Copy link
Copy Markdown

@udaycodespace is attempting to deploy a commit to the Prashantkumar Khatri's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added backend gssoc:approved Required label for every approved PR. Gives the base +50 points and enables contribution tracking. labels Jun 16, 2026
@github-actions

Copy link
Copy Markdown

Hi @udaycodespace,

Thanks for opening this pull request.

This PR has been automatically classified based on the files modified.

Applied Labels

  • gssoc:approved
  • backend

Primary Review Area

  • backend

Reviewer

@Harxhit has been identified as the primary reviewer for this pull request.

If you have any questions regarding the affected area or implementation details, feel free to reach out to the assigned reviewer.

Thank you for your contribution!

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown

CI — All Checks Passed

Backend — PASS

Check Result
Lint PASS
Test PASS
Typecheck PASS

Mobile — SKIP

Check Result
Lint -
Test -

Web — SKIP

Check Result
Build -

Last updated: Wed, 17 Jun 2026 08:30:32 GMT

@Harxhit

Harxhit commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Please attach the video proof as mentioned in the issue.

@udaycodespace

Copy link
Copy Markdown
Contributor Author

Hi @Harxhit,

As requested, I've attached the demo video for Issue #543.

Note:
The recording does not contain voice/audio due to a recording issue on my side, but the video demonstrates the complete implementation and verification steps.

Video:
https://drive.google.com/file/d/1_0GGT5d8eWtKRosuxo56xI9Cw0hrEhi0/view?usp=sharing

The video covers:

  • Schema optimization changes
  • Automated refresh token cleanup implementation
  • Scheduled cleanup execution
  • Active token safety verification
  • Test execution (16/16 passing)
  • TypeScript validation
  • Backend CI verification

Please let me know if you'd like me to record a follow-up video with audio or additional demonstrations.

Thank you.

@Harxhit Harxhit left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Checked this out locally and tested it. Nice, focused feature — the active-token-safety reasoning in the description holds up.

Verified ✅

  • npm run typecheck → passes
  • npx vitest run src/__tests__/refreshTokenCleanup.test.ts16/16 pass (the Connection failure / Transaction deadlock logs are the intentional error-path tests with a mocked Prisma — expected)
  • eslint on all changed files → clean
  • Logic is correct: deleteMany on revokedAt != null OR expiresAt < now cannot match active tokens (revokedAt == null AND expiresAt > now).
  • Plugin is registered after prismaPlugin, guarded by NODE_ENV !== 'test', and clears its interval in onClose — good lifecycle hygiene.

Suggestions

1. (Medium) No migration for the new indexes. schema.prisma adds @@index([expiresAt]) and @@index([revokedAt]), but there's no prisma/migrations/** file in the PR. Without a migration, prisma migrate deploy won't create these indexes on existing/production databases, so the cleanup query won't actually benefit from them there. Consider:

npx prisma migrate dev --name refresh_token_cleanup_indexes

and committing the generated migration.

2. (Nit) app.ts was reformatted to double quotes. The rest of the codebase — and this PR's own new files — use single quotes. The import-block reformatting adds diff churn unrelated to the feature and will muddy git blame. Suggest reverting app.ts to single quotes to keep the diff minimal.

3. (Minor) Startup cleanup blocks boot. await runCleanup() runs before the server starts listening. It's wrapped in try/catch so a failure won't crash startup, but a slow DB will delay readiness. Optional: let the first run be non-blocking (void runCleanup()), since the interval runs it anyway.

4. (Minor / future) Multi-instance deployments will each run their own setInterval, duplicating the cleanup. deleteMany is idempotent so it's safe — just redundant work. Worth a note if the service scales horizontally (a single scheduled job or an advisory lock would avoid it).

Overall: clean, well-tested, and correct. The missing migration (#1) is the only thing I'd want addressed before merge; the rest are optional.

Reviewed locally on commit head of feat/543-refresh-token-cleanup.

@udaycodespace

Copy link
Copy Markdown
Contributor Author

Thanks for the review and for testing it locally.

My planned follow-up:

  • Generate and commit the Prisma migration for the new "expiresAt" and "revokedAt" indexes.
  • Review the "app.ts" formatting changes and reduce unrelated diff churn where possible.
  • Revisit the startup cleanup execution approach based on the feedback provided.

I'll work on these updates and push them by this afternoon.

Thank you for the detailed review.

@Harxhit

Harxhit commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Hi @Harxhit,

As requested, I've attached the demo video for Issue #543.

Note:
The recording does not contain voice/audio due to a recording issue on my side, but the video demonstrates the complete implementation and verification steps.

Video: https://drive.google.com/file/d/1_0GGT5d8eWtKRosuxo56xI9Cw0hrEhi0/view?usp=sharing

The video covers:

* Schema optimization changes

* Automated refresh token cleanup implementation

* Scheduled cleanup execution

* Active token safety verification

* Test execution (16/16 passing)

* TypeScript validation

* Backend CI verification

Please let me know if you'd like me to record a follow-up video with audio or additional demonstrations.

Thank you.

The video should have DB entries getting deleted.

@udaycodespace

Copy link
Copy Markdown
Contributor Author

Hi @Harxhit,
As requested, I've attached the demo video for Issue #543.

Note:
The recording does not contain voice/audio due to a recording issue on my side, but the video demonstrates the complete implementation and verification steps.

Video: https://drive.google.com/file/d/1_0GGT5d8eWtKRosuxo56xI9Cw0hrEhi0/view?usp=sharing
The video covers:

* Schema optimization changes

* Automated refresh token cleanup implementation

* Scheduled cleanup execution

* Active token safety verification

* Test execution (16/16 passing)

* TypeScript validation

* Backend CI verification

Please let me know if you'd like me to record a follow-up video with audio or additional demonstrations.
Thank you.

The video should have DB entries getting deleted.

Thanks for the clarification.

Understood. The current video demonstrates the implementation, tests, and verification steps, but I understand that you'd like to see the actual database records being removed by the cleanup process.

I'll prepare a database-backed demo showing the refresh token records before cleanup and after cleanup execution, and I'll upload the updated video by tomorrow afternoon.

Thank you for the clarification.

@udaycodespace

Copy link
Copy Markdown
Contributor Author

PR #583 Status Update

Progress: ~80-85%

Completed

  • Addressed Review Comment 2 (app.ts cleanup and minimal diff)
  • Addressed Review Comment 3 (non-blocking startup cleanup)
  • TypeScript validation passing
  • Refresh token cleanup test suite passing (16/16)

Remaining
• Migration for refresh token cleanup indexes (#1)
• Demo video showing actual database entries being deleted
• Final validation, commit, and push

@udaycodespace

Copy link
Copy Markdown
Contributor Author

@Harxhit ,

Migration Question (#1)

I'm a bit stuck on the migration part and wanted to check before proceeding.

I looked into it and found that the repository currently only has these committed migrations:

  • 20260312125106_init
  • 20260312162249_analytics_models

However, the current schema.prisma already contains models such as RefreshToken, UserIdentity, Team, and Event, but I couldn't find migrations that create those tables.

Because of this, when I generate a migration locally, Prisma creates a much larger migration that tries to create several existing schema models/tables instead of only adding the new indexes for expiresAt and revokedAt.

Could you please let me know the preferred approach here? I want to avoid committing a large unrelated migration just to add these indexes.

Remaining

  • Migration for refresh token cleanup indexes #1
  • Demo video showing actual database entries being deleted
  • Final validation, commit, and push

@udaycodespace

Copy link
Copy Markdown
Contributor Author

Hi @HARSHIT Singh,

All review feedback for PR #583 has now been addressed.

Item Status
Review Comment #1 (Migration) [x] Completed
Review Comment #2 [x] Completed
Review Comment #3 [x] Completed
Refresh token cleanup tests [x] 16/16 Passing
Migration validation [x] Completed
Database deletion demonstration [x] Completed

Demo Video: https://drive.google.com/file/d/1Oybd7eT1OyKVUvXuXTA969BI9l-dScyJ/view?usp=sharing

Video Summary

  • Applied migration successfully
  • Verified refresh_tokens table and indexes:
    • refresh_tokens_expires_at_idx
    • refresh_tokens_revoked_at_idx
  • Inserted 3 refresh token records:
    • 1 expired token
    • 1 revoked token
    • 1 valid token
  • Verified all 3 records existed before cleanup
  • Started backend and triggered automated cleanup
  • Cleanup log reported:
    • deletedCount: 2
  • Verified database state after cleanup:
    • expired token deleted
    • revoked token deleted
    • valid token remained

Terminal Evidence

Refresh token cleanup completed
deletedCount: 2
SELECT COUNT(*) FROM refresh_tokens;

 count
-------
     1

Final Result

  • Expired tokens are removed
  • Revoked tokens are removed
  • Valid tokens remain untouched
  • Cleanup job executes successfully on startup
  • Migration applied successfully with indexes on:
    • expiresAt
    • revokedAt

Ready for re-review. Thank you.

@udaycodespace udaycodespace requested a review from Harxhit June 17, 2026 08:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend gssoc:approved Required label for every approved PR. Gives the base +50 points and enables contribution tracking.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Automated Refresh Token Cleanup and Schema Optimization

2 participants