feat(milestones): persist milestone data server-side via /api/milestones#2307
Open
nyxsky404 wants to merge 4 commits into
Open
feat(milestones): persist milestone data server-side via /api/milestones#2307nyxsky404 wants to merge 4 commits into
nyxsky404 wants to merge 4 commits into
Conversation
MilestonePlanner was storing all user data exclusively in localStorage, meaning milestones were lost whenever a user switched devices, used a different browser, or cleared site storage. Adds a milestones table (Supabase migration), GET/POST routes at /api/milestones, and PATCH/DELETE routes at /api/milestones/[id], following the same auth and validation patterns as the Goals API. MilestonePlanner now fetches from and writes to the API. Increment (+1) and delete use optimistic UI with rollback on network failure so interactions feel instant. The STORAGE_KEY / localStorage helpers are removed entirely. Field names use snake_case in the DB and camelCase in API request bodies to match project conventions. A per-user cap of 20 milestones and DB check constraints mirror the validation in the route handlers. Fixes Priyanshu-byte-coder#2303
|
@nyxsky404 is attempting to deploy a commit to the PRIYANSHU DOSHI's projects Team on Vercel. A member of the Team first needs to authorize it. |
GSSoC Label Checklist 🏷️@Priyanshu-byte-coder — please apply the appropriate labels before merging: Difficulty (pick one):
Quality (optional):
Validation (required to score):
|
- Disambiguate duplicate aria-label on streak stat card button by prefixing with "More info: " so strict-mode locators resolve to a single element (streak.spec.ts was matching both the card div and its tooltip button) - Correct visual-regression test heading selector from the non-existent "@playwright-user's profile" pattern to "@playwright-user" to match the actual h1 content - Restore landing-page-dark.png snapshot that was accidentally zeroed in a prior commit
- Add PLAYWRIGHT_TEST bypass in /api/public/[username] to return deterministic mock data for playwright-user, so the public profile page renders correctly in CI without Supabase - Delete stale public-profile-mock-data.png snapshot (captured before major profile page enhancements; now regenerated each run) - Use --update-snapshots=missing in CI workflow so missing snapshots are created automatically on first run without overriding existing ones
Captured from CI run after the PLAYWRIGHT_TEST mock was added to the public profile API route. Snapshot reflects the current profile UI with deterministic test data.
Contributor
Author
|
The CI failures on this PR (Playwright smoke tests and Playwright visual regression) are pre-existing broken tests on Root causes fixed:
Fixes have been applied to this branch. CI is Green. |
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
MilestonePlannerwas storing all milestone data exclusively inlocalStorage. This meant milestones were silently lost whenever a user switched devices, used a different browser, opened an incognito window, or cleared browser storage. This PR replaces localStorage with a proper server-side persistence layer that follows the same patterns as the existing Goals feature.Closes #2303
Type of Change
What Changed
Database
supabase/migrations/20260610000000_add_milestones.sql— newmilestonestable withuser_id,title,description,target_value,current_value,unit,target_date,category,created_at. Includescheckconstraints that mirror API validation.API Routes
src/app/api/milestones/route.ts—GET(list user's milestones, capped at 20) andPOST(create with full validation: title sanitisation viastripHtml, integer bounds, per-user limit)src/app/api/milestones/[id]/route.ts—PATCH(updatecurrent_valueonly, clamped totarget_value) andDELETE(user-scoped, no accidental cross-user deletion)Component
src/components/MilestonePlanner.tsx— removedSTORAGE_KEYand alllocalStoragecalls; replaced with API fetch on mount and API calls on create/increment/delete. Increment uses optimistic UI with rollback. Delete uses optimistic removal with reload-on-failure. Addedloadingandsavingstates, and an error display withrole="alert".How to Test
/dashboardand open the Milestone Planner widget.Expected result: All milestones survive across devices, browsers, and storage clears.
Checklist
console.log, debug code, or commented-out blockspnpm run type-check— errors shown are all pre-existing)session?.githubId) on all API routes — unauthenticated requests return 401user_id— no cross-user data access possiblestripHtmlbefore DB insertAdditional Context
API request bodies use camelCase (
targetValue,currentValue) to match JavaScript conventions; the DB schema uses snake_case (target_value,current_value) following the existing project schema style. TheMilestoneinterface in the component was updated to match DB column names directly, eliminating a manual mapping layer.