Final Milestone Plan - bounswe/bounswe2026group4 GitHub Wiki
Final Milestone Plan — Local History Story Map
Deadline: 14-05-2026 | Planning Date: March 26, 2026 | Duration: 5 weeks
Table of Contents
- Milestone Overview
- Milestone Goals and Success Criteria
- Scope: Deferred Features Now In Scope
- Sprint Plan
- Week 1 (14 April - 20 April) — Profile Enhancements & Follows
- Week 2 (20 April - 26 April) — Media, Tags, Search, Bookmarks & Popular Feed
- Week 3 (26 April - 2 May) — Notifications, Email Service Foundation & Timeline
- Week 4 (2 May - 8 May) — Email-dependent Auth & Gamification
- Week 5 (8 May - 14 May) — Reporting, Moderation, Testing & Release
- Feature Requirements Mapping
- Testing Strategy
- Risk Register
- Definition of Done
Milestone Overview
| Milestone | Name | Target | Gate Condition |
|---|---|---|---|
| FM1 | Profile & Follows Complete | End of Week 1 | Full profile management works end-to-end; users can follow each other |
| FM2 | Media, Tags, Search, Bookmarks & Popular Feed Complete | End of Week 2 | Audio/video uploads, tags, enhanced search + radius filtering, bookmarks, and popular sort are all functional |
| FM3 | Notifications, Email Service & Timeline Ready | End of Week 3 | Notification panel + preferences live; email provider integrated with verified templates; timeline view is live |
| FM4 | Email-dependent Auth & Gamification Complete | End of Week 4 | Email verification, password reset, points, and badges are functional |
| FM5 | Full Release Ready | End of Week 5 | Reporting and admin panel live, all tests passing in CI, documentation updated |
Buffer: Reserve the final 2 days of Week 5 for deployment fixes and final polish. No new features in this window.
Load distribution: Weeks 1 and 2 are intentionally dense to unblock user-facing value early. Weeks 3–5 have lighter feature scope but carry email/notifications/timeline/admin complexity and final integration testing.
Notification trigger wiring: Notifications are built in Week 3. Triggers for events introduced in later weeks (badge earned → W4; story removed, report resolved → W5) are wired in during the week that event originates. The notification layer is designed so a new trigger is a single
emit(event_type, user_id, target)call from the emitting feature.
Milestone Goals and Success Criteria
- A new user receives and must validate a 6-digit email verification code during registration
- A user can reset their forgotten password via an emailed link
- A user can upload a profile photo and set optional fields (location, birth date, bio) with per-field visibility control
- A user can delete their account; their stories are anonymized unless explicitly deleted
- A user can follow and unfollow other users; followers and following lists are visible on the profile
- A story can include audio and video uploads in addition to images
- Tags can be created, attached to stories, filtered on, and browsed by tag page
- The timeline feature allows exploring stories by time period, optionally scoped by location
- The feed can be sorted by most popular (total likes) in addition to most recent
- A user can save and unsave stories; saved stories appear in their profile
- Search covers narrative text and tags in addition to title and location name
- A user can report a story or comment with a selected reason
- Admins can review reports, remove content, ban users, and manage tags
- Users receive in-app notifications for relevant events (including new followers) and can configure preferences
- The points system awards and deducts points correctly based on contributions and engagement
- Badges are awarded for registration, story milestones, and point thresholds
- A user can filter stories based on their current geographic location using a selectable distance radius (e.g., 1 km, 2 km, 5 km), and only stories within the selected radius are displayed
- All new features are covered by automated tests and pass in CI
- README and API reference are updated to reflect all new endpoints
Scope: Deferred Features Now In Scope
| Deferred Feature | Requirement Ref | Week |
|---|---|---|
| Profile photo upload | 1.2.2.1, 1.2.2.4 | Week 1 |
| Profile optional fields (location, birth date, bio) | 1.2.2.1 | Week 1 |
| Profile privacy settings (field-level visibility) | 1.2.2.2 | Week 1 |
| Contributor name visibility preference | 1.2.2.3 | Week 1 |
| Account deletion with anonymization | 1.1.2.11 | Week 1 |
| User follow / unfollow | 1.1.2.x (TBD) | Week 1 |
| Audio and video uploads | 1.4.2.1, 1.4.2.2 | Week 2 |
| Tags (creation, attachment, filtering, tag pages) | 1.3.6, 1.3.5.2, 1.3.5.3 | Week 2 |
| Search by narrative text and tags | 1.3.5.1 | Week 2 |
| Current-location radius filtering | 1.3.5.7 | Week 2 |
| Saved stories / bookmarks | 1.1.2.6, 1.2.2.5 | Week 2 |
| Feed sorting by most popular | 1.3.2.4 | Week 2 |
| Notifications (events, panel, preferences) | 1.6.1, 1.6.2, 1.6.3 | Week 3 |
| Email service provider integration (foundation) | — | Week 3 |
| Timeline feature | 1.3.4 | Week 3 |
| Email verification (6-digit code on registration) | 1.2.1.2 | Week 4 |
| Password reset via email link | 1.2.1.9 | Week 4 |
| Points system | 1.7.1 | Week 4 |
| Badges and achievements | 1.7.2 | Week 4 |
| Reporting workflow (user-side) | 1.5.1 | Week 5 |
| Admin moderation panel | 1.1.3.1–1.1.3.8 | Week 5 |
Sprint Plan
Week 1 (14 April - 20 April) — Profile Enhancements & Follows
Goal: Users can manage a complete profile with optional fields and per-field privacy controls. Users can follow each other.
Load: Dense. Two parallel tracks (profile + follows). Prioritize backend endpoints early so frontend is not blocked.
Backend
- Profile update endpoint —
PATCH /users/:idaccepts all optional fields and visibility flags; restricted to the authenticated owner - Profile photo upload —
POST /users/:id/photo; validate type (jpg/jpeg/png) and size (≤ 2 MB); store in existing object storage; persist URL on user record - Account deletion —
DELETE /users/:id; anonymize stories unless story deletion is also requested; require explicit confirmation - Follows schema — create
followstable:follower_id,followed_id,created_at; unique constraint on(follower_id, followed_id); prevent self-follow - Follow / unfollow endpoints —
POST /users/:id/followandDELETE /users/:id/follow; authenticated users only; idempotent - Followers / following endpoints —
GET /users/:id/followersandGET /users/:id/following; paginated - Follower / following counts — include
followers_countandfollowing_countin the user profile response - Follow event emission — emit a
new_followerevent on successful follow (no-op until Week 3 wires the notification trigger)
Frontend
- Profile edit page — form for all optional fields; per-field visibility toggle next to each field; profile photo upload with preview
- Contributor visibility toggle — checkbox in story submission form: "Show my name on this story"
- Account deletion flow — settings page option; confirmation modal explaining anonymization; requires password re-entry
- Follow / Unfollow button — on other users' profile pages; filled/unfilled state; optimistic update; hidden on own profile
- Followers and following counts — clickable counts on the profile header
- Followers / following lists — modal or dedicated view showing a paginated list of users with follow buttons
Week 2 (20 April - 26 April) — Media, Tags, Search, Bookmarks & Popular Feed
Goal: Stories support all media types. Tag system is fully functional. Search covers narrative text and tags. Bookmarks and popular sort are live.
Load: Very dense. This is the biggest feature-delivery week of the milestone.
Backend
- Audio and video upload — extend
POST /media/uploadto accept audio (mp3, wav, ogg) and video (mp4, webm); store in existing object storage; return playable URL - Media validation — validate MIME type server-side for all media categories; return descriptive errors on failure
- Tag endpoints —
GET /tagslists all tags;POST /tagscreates a new tag if the slug does not exist; assignment handled on story create/update - Tag page endpoint —
GET /tags/:slug/storiesreturns a paginated feed of stories with that tag - Search enhancements — extend
GET /stories/search?q=to match narrative text and tags in addition to title and location name - Filter enhancements — extend feed and map endpoints to accept a
tagfilter parameter; combining tag, time, and location filters must work correctly - Current-location radius filtering — extend feed and map endpoints to accept current-location-based filtering parameters (e.g., latitude, longitude, radius_km); return only stories located within the selected radius
- Bookmarks —
POST /stories/:id/bookmarkandDELETE /stories/:id/bookmark; restricted to authenticated users; idempotent - Saved stories endpoint —
GET /users/:id/bookmarksreturns the user's saved stories in reverse chronological order - Feed sort by popular — extend feed endpoint to accept
sort=popular, ordering by total likes descending
Frontend
- Story submission — media — add audio and video upload fields alongside the existing image field
- Story page — media playback — render audio player and video player inline using HTML5 elements
- Tag input — autocomplete from existing tags; allow creating a new tag inline; enforce 3-tag maximum and slug format with inline validation
- Tag chips — render tags as clickable chips on story page and feed cards
- Tag page — clicking a tag opens a feed filtered to that tag
- Filter panel — add tag filter to the existing filter panel; individual filter removal and "Clear all" supported
- Current-location distance filter — add a location-based filter option that requests user permission, detects the current location, and allows selecting a distance radius (e.g., 1 km, 2 km, 5 km)
- Location permission handling — show a clear error or fallback message if location permission is denied or unavailable
- Bookmark button — on story page and feed cards; filled/unfilled state; optimistic update on click
- Saved stories tab — "Saved" section on the profile page listing bookmarked stories
- Feed sort control — toggle between "Most Recent" and "Most Popular" in the feed header
Week 3 (26 April - 2 May) — Notifications, Email Service Foundation & Timeline
Goal: In-app notifications are live with configurable preferences. Email provider is integrated and transactional templates are ready to be wired into auth flows in Week 4. Timeline view is live end-to-end.
Load: Moderate. Notifications are the main feature; email work is infrastructure-heavy but narrow in scope; timeline fills the remaining capacity cleanly.
Backend
- Notifications schema — create
notificationstable:user_id,event_type,target_type,target_id,is_read,created_at - Notification trigger layer — pluggable
emit(event_type, user_id, target)API so new triggers in W4/W5 require only a single call from the emitting feature - Notification triggers — wire current events — new comment on own story, new like on own story, new follower (from W1)
- Notification endpoints —
GET /notifications;PATCH /notifications/:id/read;DELETE /notificationsclears all - Notification preferences — per-type enable/disable flags and a global "stop all" toggle on user settings
- Email service integration — configure transactional email provider (e.g., Resend or SendGrid); credentials wired into staging and production env
- Email templates — verification code template and password reset template; send test emails end-to-end from staging
- Email sending utility — thin internal wrapper used by auth flows in Week 4
- Timeline endpoint —
GET /stories/timelineacceptsyear,year_range, ordecade; optionally scoped bylocation; returns stories sorted chronologically
Frontend
- Notification panel — bell icon in navbar; unread count badge; reverse chronological list; clicking navigates to relevant content (including follower profiles)
- Mark as read — individual and "mark all as read" actions in the panel
- Notification preferences — settings page section with per-type toggles (including new-follower) and global off switch
- Timeline view — new route; time period selector (year, range, decade); stories in chronological order; clicking a story opens its page
- Timeline location scope — allow scoping the timeline to a selected location; reflects active location filter
Week 4 (2 May - 8 May) — Email-dependent Auth & Gamification
Goal: Email verification and password reset work end-to-end. Points and badges are live.
Load: Moderate. Builds directly on the Week 3 email and notification foundations.
Backend
- Email verification — on
POST /auth/register, generate and send a 6-digit code; addPOST /auth/verify-emailto validate the code before activating the account; expire codes after 15 minutes; resend endpoint - Password reset —
POST /auth/forgot-passwordsends a reset link;POST /auth/reset-passwordvalidates the token and updates the password; invalidate token after single use - Points — add
pointsfield tousers; createpoints_logtable for auditability; award 50 on publish, 2 per like, 4 per comment, 3 per save; deduct on rescission or removal; floor at 0 - Badges — create
badgesanduser_badgestables; award registration badge on activation; story-count badges at 1, 3, 5, 10, 50; points-threshold badges at 50, 100, 200, 500, 1000 - Points and badges endpoints —
GET /users/:id/points;GET /users/:id/badges - Notification trigger — badge earned — wire
new_badgeevent into the Week 3 notification layer
Frontend
- Email verification screen — prompt for 6-digit code after registration; handle wrong/expired code errors; provide resend option
- Forgot password flow — email entry form → confirmation screen; password reset form at link destination
- Points display — total points on the public profile page
- Badges display — earned badge icons on the public profile page with tooltip (name, condition)
Week 5 (8 May - 14 May) — Reporting, Moderation, Testing & Release
Goal: Users can report content. Admins have a functional moderation panel. All tests pass in CI. Production deployment is updated and verified.
Backend
- Reports schema — create
reportstable:reporter_id,target_type,target_id,reason,status,resolution,created_at - Report endpoint —
POST /reports; authenticated users only; reason required from: spam, false/misleading content, harassment, privacy violation, explicit media, other - Admin endpoints — all restricted to admin role:
GET /admin/reports— list reports, filterable by statusPATCH /admin/reports/:id— resolve with outcome (no_action / content_removed / user_banned)DELETE /admin/stories/:id— remove story, store moderation reasonDELETE /admin/comments/:id— remove commentPATCH /admin/users/:id/ban— disable account loginDELETE /admin/tags/:id— remove tag and dissociate from all stories
- Notification triggers — moderation/reports — wire
story_removed,moderation_action, andreport_resolvedevents into the Week 3 notification layer
Frontend
- Report button — on story page and individual comments; opens a reason-selection modal
- Admin panel — protected route (admin only); sections: Reports, Stories, Comments, Users, Tags
Testing
- Integration tests — register → verify → login; forgot password → reset; upload audio → playable on story page; tag story → tag page returns it; bookmark → appears in saved; follow → appears in followers/following + followed user notified; report → admin resolves; like → points awarded → unlike → deducted; publish → badge awarded
- Manual smoke test — all new flows on production; re-verify the three MVP core flows for regressions
Release
- Email provider credentials verified in production environment
- All new migrations applied to production database
- Admin account provisioned in production
- All flows verified on production URL
- README and API reference updated for all new endpoints
- Deferred features section in documentation replaced with "all requirements implemented"
Feature Requirements Mapping
| Req ID | Description | Week |
|---|---|---|
| 1.1.2.11 | Account deletion with anonymization | Week 1 |
| 1.1.2.x (TBD) | Follow / unfollow users | Week 1 |
| 1.2.2.1 | Optional profile fields | Week 1 |
| 1.2.2.2 | Per-field profile privacy | Week 1 |
| 1.2.2.3 | Contributor visibility preference | Week 1 |
| 1.2.2.4 | Profile photo upload | Week 1 |
| 1.1.2.6 | Save / bookmark stories | Week 2 |
| 1.2.2.5 | Saved stories in profile | Week 2 |
| 1.3.2.4 | Feed sort by most popular | Week 2 |
| 1.3.5.1 | Search by narrative text and tags | Week 2 |
| 1.3.5.3 | Filter by tags | Week 2 |
| 1.3.5.7 | Current-location radius-based filtering | Week 2 |
| 1.3.6 | Tags | Week 2 |
| 1.4.2.1–1.4.2.2 | Audio and video uploads | Week 2 |
| 1.3.4 | Timeline feature | Week 3 |
| 1.6.1–1.6.3 | Notifications | Week 3 |
| 1.2.1.2 | Email verification (6-digit code) | Week 4 |
| 1.2.1.9 | Password reset via email | Week 4 |
| 1.7.1 | Points system | Week 4 |
| 1.7.2 | Badges and achievements | Week 4 |
| 1.1.2.8 | Report stories and comments | Week 5 |
| 1.1.3.1–1.1.3.8 | Admin moderation panel | Week 5 |
| 1.5.1 | Reporting workflow | Week 5 |
Testing Strategy
Unit Tests
- Profile field visibility enforcement
- Follow idempotency and self-follow prevention
- Tag slug format validation and per-story duplicate prevention
- Audio/video MIME type and size validation
- Bookmark idempotency
- Current-location radius filter parameter validation
- Radius-based story distance filtering logic
- Notification preference filtering
- Notification trigger dispatch on emit
- Verification code TTL expiry and single-use invalidation
- Password reset token lifecycle
- Points award, deduction, and floor-at-zero logic
- Badge trigger conditions
Integration Tests
- Profile update with per-field privacy → public view respects flags
- Follow user → appears in followed user's followers list and current user's following list
- Follow user → followed user gets a
new_followernotification (after W3) - Timeline by decade scoped to location returns correct stories
- Upload audio → appears playable on story page
- Tag a story →
GET /tags/:slug/storiesreturns it - Bookmark story → appears in
GET /users/:id/bookmarks - Apply current-location radius filter → only stories within the selected radius are returned on map and feed
- Deny location permission → current-location filter cannot be applied and a meaningful message is shown
- Register → verify email → account active → login succeeds
- Forgot password → reset link → new password set → old token rejected
- Like story → points awarded → unlike → points deducted
- Publish story → story-count badge awarded → badge notification delivered
- Report story → admin sees it → admin resolves → status updated → reporter/target notified
Manual Smoke Test
Walk through all new flows on the deployed production URL. Re-verify the three MVP core flows to confirm no regressions.
Risk Register
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Week 1 overloaded with two parallel tracks (profile + follows) | Medium | High | Split tracks across team members on Day 1; backend endpoints first to unblock frontend |
| Week 2 overloaded | High | High | Backend-first; push non-critical UI polish to Week 5 buffer if needed |
| Audio/video playback compatibility across browsers | Medium | Medium | Use standard HTML5 elements; test on Chrome, Firefox, Edge during Week 2 |
| Email provider setup delays Week 3 | Medium | High | Start email provider spike on Day 1 of Week 3; use Resend (minimal setup); test delivery end-to-end before Week 4 starts |
| Cross-week notification triggers (new_follower from W1, new_badge from W4, moderation from W5) not wired cleanly | Medium | Medium | Design the W3 notification layer as a pluggable emit API; features in W1/W4/W5 only need a one-line call at event emission points; add trigger integration tests in W5 |
| Points edge cases (concurrent actions, deductions below zero) | Medium | Medium | Unit test edge cases before implementing; enforce floor of 0 |
| Regressions in MVP flows after schema migrations | Medium | High | Run MVP integration tests in CI after every migration; verify on production immediately after deploy |
Definition of Done
A feature is done when:
- The endpoint is implemented and returns correct responses for both happy and error paths
- The frontend consumes the endpoint and renders correctly
- Role-based access is enforced where applicable
- At least one automated test covers the happy path
- The feature works on the production URL
The Final Milestone is done when:
- Every deferred requirement from MVP is implemented and verified on production
- All three MVP core flows pass without regression
- The full test suite passes in CI
- README and API reference are updated and committed