Skip to content

Sequence Diagrams (Final)

Mehmet Bora Sarioglu edited this page May 16, 2026 · 3 revisions

Sequence Diagrams — Final Milestone

1. Mentor discovery → request → accept → shared goal → first milestone

Mentee browses ranked mentors via MatchingController.getTopMentors, sends a request via MentorshipRequestController.createRequest, the mentor accepts via MentorshipService.acceptRequest (which cancels every other pending request from this mentee), either party sets the shared goal, and the mentor creates the first milestone. MentorshipPreconditions.requireSharedGoal throws GoalRequiredException (HTTP 409 GOAL_REQUIRED) when a milestone is created before the shared goal is set.

SD-1: Onboarding

2. Mentee cancels pending request → auto-ban → retry blocked → admin lifts

Cancellation flips the request to CANCELLED and records the violation via BanService.recordCancellation. Once the threshold is crossed, the next POST /api/mentorship-requests is short-circuited with the structured 403 BANNED_UNTIL envelope. The admin lifts the ban via BanAdminController.liftBan.

SD-2: Cancel → Ban → Lift

3. Authenticated post creation with hashtag extraction + attachment fanout

FeedPostController.create is rate-limited (USER-keyed bucket feed-post-create, 30/h), normalises hashtags via HashtagNormalizer, links pre-uploaded attachments, persists the post, and emits a FeedPostCreatedEvent. The FeedFanoutListener (@Async, @TransactionalEventListener(AFTER_COMMIT)) fans out STOMP frames to every follower of the author on /topic/feed.{followerId}.

SD-3: Post creation + fanout

4. For-You feed read path including the AFTER_COMMIT bandit listener

FeedReadService.forYouFeed loads a rolling candidate window (default 200 posts) and hands it to the FeedRanker (either the baseline InterestOverlapFeedRanker or the advanced ForYouScoringPipeline behind FEED_ADVANCED_RANKER). On every engagement (POST /api/feed/posts/{id}/like), the FeedEngagementBanditListener fires AFTER_COMMIT in a REQUIRES_NEW transaction on a second Hikari connection — the reason the prod pool was bumped from 10 → 20 in application-prod.properties.

SD-4: For-You + bandit

5. Feed search with keyword + hashtag + viewer-side keyword mute filtering

FeedReadController.search requires at least one of q / hashtag / since / until / lang. The keyword path uses pg_trgm-accelerated LIKE on the post body with % and _ escaped at the service boundary so they cannot act as wildcards. Hashtag matching normalises via HashtagNormalizer. Viewer keyword-mutes are applied after the SQL fetch, so the visible page may surface fewer than size items.

SD-5: Feed search + mute filter

6. Mentor-pair message send with attachment + WebSocket fanout + read receipt

Optional attachment upload via AttachmentController.upload (with per-user-hourly quota), then MentorPairMessageController.send (rate-limited 60/min), then MessageBroadcastListener (@Async, AFTER_COMMIT) STOMP-broadcasts on /topic/mentor-pair.{convId} and publishes a NEW_MESSAGE notification. The recipient marks-read via PATCH …/messages/read.

SD-6: Mentor-pair messaging

7. Scheduled job: mentorship auto-completion at term end

MentorshipAutoCompletionScheduler (cron-driven via @Scheduled) sweeps Mentorship rows where endDate < now AND status=ACTIVE. Each row's status flip runs in its own REQUIRES_NEW transaction so a single per-row failure doesn't abort the sweep. Both mentor and mentee receive a MENTORSHIP_AUTO_COMPLETED notification.

SD-7: Scheduled auto-completion

8. User reports a feed post → admin resolves → optional ban

ReportController.createReport validates the target type (POST / USER / MENTORSHIP), enforces the target's existence + visibility, rejects self-reports, prevents duplicates via a Postgres partial-unique-index translation in ReportService, and emits a ReportSubmittedEvent. The ReportFanoutListener (@Async, AFTER_COMMIT) fans out REPORT_RECEIVED notifications to every admin. Admin transitions the report via AdminReportController.transition gated by ReportStatusMachine.assertValid. Optional follow-up: admin bans the reported user via AdminController.banUser.

SD-8: Report flow + admin resolve

9. Meeting lifecycle: schedule → confirm → reschedule → reminders → auto-cancel

MeetingController.createMeetings stores meetings as PENDING_CONFIRMATION with a confirmationDeadline; the mentee confirms via POST /confirm or declines via POST /decline. Either party can open a reschedule request which the counterpart approves or rejects through MeetingService.approveReschedule (which may auto-flip a still-pending meeting straight to CONFIRMED). MeetingScheduler.run() (cron 0 */5 * * * *) sweeps in per-row REQUIRES_NEW transactions: it fires 24h / 1h reminders for CONFIRMED meetings inside the configured window and auto-expires PENDING_CONFIRMATION rows whose deadline has passed, publishing a MEETING_AUTO_DECLINED notification.

SD-9: Meeting lifecycle

10. End mentorship → audit → notification → mentee rates

MentorshipService.endMentorship (mentor only, mentorship must be ACTIVE) flips status to COMPLETED, writes a MentorshipAuditLog row for the ACTIVE → COMPLETED transition, and publishes MENTORSHIP_ENDED. The mentee can then POST /api/mentorships/{id}/rating once; MentorRatingService.createRating enforces the gate (mentorship in COMPLETED or CANCELLED) and idempotency (existsByMentorshipId check plus a UNIQUE(mentorship_id) backstop translated to 409 ALREADY_RATED). Aggregate stars and rating count are computed on profile read via MentorRatingRepository.aggregateForMentor — they are not stored on the user row.

SD-10: End + rate

11. Task assigned → submitted → reviewed (APPROVED / NEEDS_REVISION cycle)

TaskService.createTask gates on MentorshipPreconditions.requireSharedGoal (409 GOAL_REQUIRED if the shared goal has not been set yet) and saves the task as PENDING. The mentee submits via POST /api/tasks/{id}/submission (appends a TaskSubmission row and flips the task to SUBMITTED); the mentor reviews via PATCH /api/tasks/{id}/feedback which sets feedback / reviewedAt / reviewedBy on the latest submission and transitions the task to either COMPLETED or REVISION_REQUESTED. A REVISION_REQUESTED task can be re-submitted — submissions are append-only and surfaced in submittedAt DESC order. ReminderNotificationScheduler.processTaskReminders (cron 0 0/30 * * * *) emits 24h-before-due reminders for tasks in PENDING or REVISION_REQUESTED.

SD-11: Task cycle

12. Follow user → Postgres → AFTER_COMMIT Neo4j sync + push fanout

FollowService.follow uses a native INSERT … ON CONFLICT DO NOTHING (FollowRepository.upsertFollow) so re-follow returns 200 idempotently while a fresh edge returns 201 and publishes a FollowChangedEvent. FollowGraphSyncListener (@TransactionalEventListener(AFTER_COMMIT)) retries FollowGraphWriter.apply up to 3 times — failures land in the FailedGraphSync outbox swept nightly by FollowGraphResyncJob. In parallel, NotificationEventListener (@Async, AFTER_COMMIT, REQUIRES_NEW) persists the in-app NEW_FOLLOWER row and dispatches FCM push via FcmPushDeliveryService, pruning rejected tokens through UserDeviceRepository.deleteByToken. The prod Hikari pool was bumped 10 → 20 to keep this second Neo4j transaction from starving the request-path connection.

SD-12: Follow + Neo4j

Team Members

Lab Reports


Weekly Meetings


Customer Meetings


Stakeholder Meetings


Project Requirements


🎦 Scenarios and Mock-ups

Use Case Diagrams

Class Diagram

Sequence Diagrams

Test Plan and Coverage


Project Standards


Final Milestone and MVP Plan

MVP Report


Final Milestone Report

Per-Member Prompt Logs


Future Work

Clone this wiki locally