Product Backlog

EPICs, user stories, sprints, and pull requests pulled live from the GitHub Project.

EPICUser StoryAcceptance CriteriaEstimate
EPIC 1US1-1
As new user
I want to register as either a student or a tutor using my email and password
So that I can access the platform with an account matching my role
Given a valid email, a password of at least 8 characters, and a role of "student" or "tutor"
When the user submits registration
Then the account is created and the role is stored correctly
3
Given a password shorter than 8 characters
When the user submits registration
Then it is rejected with a clear error
Given an email that already exists
When the user submits registration
Then it is rejected with a clear error
Given a successful registration
When the account is created
Then the user receives an authentication token
Given a user registers
When the password is stored
Then it is never stored in plain text
US1-2
As registered user
I want to log in with my email and password
So that I can access my account and use the platform
Given a registered user with a correct email and password
When they log in
Then they receive an authentication token
3
Given an incorrect password
When the user attempts to log in
Then it is rejected with a generic invalid-credentials error
Given an email that doesn't exist
When the user attempts to log in
Then it is rejected with the same generic invalid-credentials error
Given a valid issued token
When the user accesses an authenticated endpoint
Then access is granted
US1-3
As newly registered user
I want to be required to complete my role-specific profile information right after registering
So that the platform has the data it needs before I can use other features
Given a user has just completed registration
When registration succeeds
Then they are directed to a profile completion page
5
Given the user's role
When the profile completion page loads
Then a student sees the student-specific field set and a tutor sees the tutor-specific field set
Given the profile is incomplete
When the user attempts to navigate to other pages
Then they cannot access them until all required fields are filled in
Given required fields are missing
When the user submits the form
Then it is rejected with clear validation errors
Given all required fields are filled in
When the user submits the form successfully
Then the profile data is saved and the user can proceed to the rest of the app
EPIC 2US2-1
As user
I want to view my account profile
So that I can review my personal information
Given the user is signed in
When the user opens My Profile Management
Then the system displays the account's common fields and role-specific fields
3
Given private fields such as phone, Line ID, and email
When the owner views the profile
Then they are visible only to the owner unless explicit visibility settings allow otherwise
US2-2
As user
I want to edit my personal information
So that my account details remain up to date
Given a user opens the profile management page
When the page loads
Then their current personal information is pre-filled
3
Given the user updates one or more fields
When they save the changes
Then the updates are accepted
Given changes have been saved
When the profile page is loaded again
Then the saved changes are reflected
Given a field is edited
When it is validated
Then the same validation rules as initial profile completion apply (per role)
Given invalid data is submitted
When the user saves
Then clear validation errors are shown and no changes are saved
US2-3
As student
I want to top up my balance by selecting from preset amount options
So that I can access teaching services
Given a student is in their account/dashboard area
When they navigate to the top-up page
Then the page loads
3
Given the top-up page is open
When it loads
Then it displays the student's current balance
Given the top-up page is open
When it loads
Then it shows a fixed list of preset top-up amounts as selectable choices (no numeric input field)
Given a preset amount is selected
When the student confirms
Then the top-up is applied
Given a successful top-up confirmation
When the balance updates
Then the displayed balance reflects the increase without a full manual refresh being required to see updated state on next load
Given a top-up is confirmed
When it is processed
Then no real payment provider, bank transfer, or card charge is triggered — the top-up is simulated/mocked
Given no preset amount is selected
When the student attempts to confirm
Then a validation message is shown and the balance does not change
Given a non-student role
When they attempt to access the top-up page
Then access is denied
US2-4
As tutor
I want to withdraw funds from my balance by selecting from preset amount options
So that I can access my earnings outside the platform
Given a tutor is in their account/dashboard area
When they navigate to the balance withdraw page
Then the page loads
2
Given the withdraw page is open
When it loads
Then it displays the tutor's current balance
Given the withdraw page is open
When it loads
Then it shows a fixed list of preset withdrawal amounts as selectable choices (no numeric input field)
Given a preset amount is selected that is less than or equal to the current balance
When the tutor confirms
Then the withdrawal is applied
Given a successful withdrawal confirmation
When the balance updates
Then the displayed balance reflects the decrease without a full manual refresh being required to see updated state on next load
Given a withdrawal is confirmed
When it is processed
Then no real payout, bank transfer, or card transaction is triggered — the withdrawal is simulated/mocked
Given no preset amount is selected
When the tutor attempts to confirm
Then a validation message is shown and the balance does not change
Given a selected amount exceeds the current balance
When the tutor attempts to confirm
Then it is rejected with a clear error and the balance does not change
Given a non-tutor role
When they attempt to access the withdraw page
Then access is denied
US2-5
As tutor
I want to set my account to active or inactive
So that I can stop taking on new work without deleting my account or being blocked by outstanding-obligation checks
Given an authenticated tutor
When they set their status to inactive
Then the status is saved without any outstanding-class or outstanding-balance check.
2
Given a tutor is inactive
When students search or attempt to book
Then that tutor does not appear as available.
Given a tutor is inactive
When they set their status back to active
Then they become available for new bookings again.
Given a tutor has outstanding classes or an outstanding balance
When they toggle to inactive
Then the toggle still succeeds (no rejection).
US2-6
As user
I want to log out from the profile management page
So that I can securely end my session
Given a signed-in user is on the profile management page
When they click the logout button
Then their session ends
2
Given a user has logged out
When they attempt to access authenticated pages
Then they are redirected away and cannot access them without logging in again
Given no active session
When the logout API is called
Then it does not crash and returns an appropriate response
US2-7
As user
I want to my profile picture upload on the complete profile and edit profile pages to actually save my image
So that my real photo is visible instead of a mocked placeholder
Given a signed-in user is on the complete profile page
When they upload a profile image
Then the image is stored in GCS and its URL is saved to the database
5
Given a signed-in user is on the edit profile page
When they upload a profile image
Then the image is stored in GCS and its URL is saved to the database
Given a profile image has been uploaded successfully
When the user views their profile
Then the uploaded image is retrievable and displays correctly
Given an upload fails
When the user attempts to upload a profile image
Then an error is shown to the user and no broken/invalid URL is saved to the database
Given the real upload flow is implemented
When either profile page is inspected
Then no mock upload logic remains
EPIC 3US3-1
As student
I want to browse active tutors with search, filters, and sorting
So that I can quickly find a tutor that fits my subject, budget, and quality preferences
Given tutors with mixed active and inactive status
When a student views the tutor list
Then only active tutors appear
8
Given a search term is entered
When a student searches
Then only tutors matching the term are returned
Given a subject filter is applied
When a student filters by subject
Then only tutors teaching that subject are shown
Given a price range is applied
When a student filters by price
Then only tutors within the given min/max price appear
Given rating sort is selected
When a student sorts by rating
Then tutors are ordered by average review score, descending by default
Given price sort is selected
When a student sorts by price
Then tutors are ordered by price, ascending by default
Given popularity sort is selected
When a student sorts by popularity
Then tutors are ordered by number of past students, descending by default
Given search, filters, and sort are all set
When a student applies them together
Then the results reflect all criteria combined
Given a tutor has a review score
When their rating is displayed
Then it shows as a score out of 5 (e.g. "4.8/5")
Given a tutor has taught students
When popularity is displayed
Then it shows the count of students who have learned with the tutor
US3-2
As student
I want to click a tutor card and see their full details with reviews
So that I can evaluate a tutor before deciding to contact them
Given a student is on the tutor list page
When they click a tutor card
Then they are navigated to that tutor's detail page
5
Given a student is on a tutor's detail page
When the page loads
Then the tutor's full information is displayed
Given a tutor has mocked reviews
When a student views the detail page
Then a list of reviews (reviewer, rating, comment) is displayed
Given a student is on the tutor detail page
When the page loads
Then a "Message" button is visible
Given a student is on the tutor detail page
When they click the "Message" button
Then they are navigated to a chat page route
EPIC 4US4-1
As user
I want to see a list of my conversations
So that I can quickly find and open a chat with a specific person
Given a signed-in user has conversations
When they open the chat inbox page
Then they see a list of all their conversations
8
Given a conversation is in the list
When it is displayed
Then it shows the other participant's name and last message preview
Given a conversation has unread messages
When it is displayed in the list
Then it is visually indicated as unread
Given multiple conversations exist
When the list is displayed
Then conversations are sorted with the most recently active first
Given a conversation is in the list
When the user clicks it
Then its chat view opens
US4-2
As user
I want to send and receive messages in real time within a conversation
So that I can communicate with a tutor or student instantly, like a normal chat app
Given an existing conversation
When a user opens it
Then the existing message history loads
13
Given a user sends a message
When it is sent
Then it appears in the sender's view immediately
Given a message is sent
When the other participant is viewing the conversation
Then they receive it in real time without refreshing the page
Given the chat connection
When messages are sent or received
Then delivery uses WebSocket
Given the signed-in user is a tutor viewing a chat with a student
When the chat view loads
Then a "Create Classroom" button is visible
Given the "Create Classroom" button is visible
When a tutor clicks it
Then no action is required to occur yet
EPIC 5US5-1
As tutor
I want to create a classroom from a student's message inbox
So that I can manage the course for that student
Given I am an active tutor viewing a conversation with a student
When the inbox loads
Then a Create Classroom action is visible.
—
Given I am a student or the conversation is not with a student
When the inbox loads
Then the Create Classroom action is not available.
Given I start classroom creation from a student conversation
When the form opens
Then that student is selected automatically and cannot be replaced with another user.
Given the form opens
When my tutor profile has a default hourly rate
Then the price field is prefilled with that value.
Given I keep the default price
When I create the classroom
Then the tutor's current default hourly rate is stored as the classroom's `pricePerHour`.
Given I enter a different valid price
When I create the classroom
Then the new value is stored for that classroom without changing my tutor profile.
Given I select a valid subject and provide all required information
When I submit the form
Then exactly one active classroom is created for me and the student in the conversation.
Given the selected subject does not exist or is not assigned to me
When I submit the form
Then creation is rejected.
Given the price is zero, negative, or invalid
When I submit the form
Then a validation error is displayed and no classroom is created.
Given no price override or valid tutor default rate is available
When I submit the form
Then creation is rejected with a clear error.
Given classroom creation succeeds
When the API responds
Then I am redirected to `/classroom/[classroomId]`.
Given classroom creation fails
When the error is returned
Then I remain in the creation flow and my entered values are preserved.
Given a conversation does not include the authenticated tutor
When its ID is submitted
Then the API rejects the request.
Given I am authenticated as a student
When I call the classroom creation endpoint
Then access is denied.
US5-2
As tutor
I want to review a classroom's details
So that I can confirm its information and current status
Given I am the tutor assigned to a classroom
When I select it from My Classroom
Then I am navigated to `/classroom/[classroomId]`.
—
Given I am the assigned tutor
When the detail page loads
Then I can see the subject, assigned student summary, price per hour, status, and creation date.
Given I am the student assigned to a classroom
When I select it from My Classroom
Then I can open its detail page.
Given I am the assigned student
When the detail page loads
Then I can see the subject, assigned tutor summary, price per hour, and status.
Given I am the assigned student
When the detail page loads
Then tutor-only information is not returned or displayed.
Given I am neither the assigned tutor nor the assigned student
When I request the classroom detail
Then access is denied and no classroom information is exposed.
Given the classroom ID is malformed
When the detail endpoint is requested
Then the API returns a validation error.
Given the classroom does not exist
When the detail endpoint is requested
Then a not-found state is displayed.
Given classroom data is loading
When the page is waiting for the API
Then an appropriate loading state is displayed.
Given the request fails
When the error is returned
Then a clear error state is displayed without stale classroom data.
Given the classroom price is stored as a Prisma decimal
When it is returned by the API
Then the frontend receives and displays a valid numeric value.
Given the page is viewed on a narrow screen
When the detail content renders
Then it remains readable without horizontal overflow.
US5-3
As tutor
I want to update classroom details after creation
So that the classroom information remains accurate
Given I am the tutor assigned to a classroom
When I open its detail page
Then an Edit action is visible.
—
Given I am the student assigned to a classroom
When I open its detail page
Then no Edit action is displayed.
Given I am the assigned tutor
When I enter edit mode
Then the current subject and price per hour are prefilled.
Given I select a valid subject and enter a valid positive price
When I save
Then the classroom is updated and the new values are displayed.
Given I update the classroom price
When the save succeeds
Then my tutor profile's default hourly rate remains unchanged.
Given I select Cancel
When I return to view mode
Then no API update occurs and the previous saved values remain displayed.
Given the price is zero, negative, or invalid
When I attempt to save
Then a validation error is displayed and the classroom is not updated.
Given the selected subject does not exist or is not assigned to me
When I attempt to save
Then the API rejects the request.
Given an update is pending
When I attempt to save again
Then a duplicate update is not submitted.
Given the update fails
When the error is returned
Then I remain in edit mode and my entered values are preserved.
Given I am the assigned student
When I call the update endpoint directly
Then access is denied.
Given I am an unrelated tutor
When I call the update endpoint directly
Then access is denied.
Given an update request includes a tutor, student, status, ID, or creation date change
When it reaches the API
Then those fields are rejected or ignored and remain unchanged.
Given the classroom ID is malformed or does not exist
When an update is attempted
Then an appropriate validation or not-found error is returned.
Given the page is viewed on a narrow screen
When edit mode is displayed
Then the form remains usable without horizontal overflow.
US5-4
As tutor
I want to search and filter my classrooms
So that I can find and browse them easily
Given I am logged in as a tutor
When I open My Classroom
Then only classrooms assigned to me are displayed.
—
Given another tutor has classrooms
When I open My Classroom
Then their classrooms are not returned or displayed.
Given I have active classrooms
When the page first loads
Then my active classrooms are shown by default.
Given I enter part of a student's name
When the search completes
Then matching classrooms are displayed.
Given I enter part of a subject name
When the search completes
Then matching classrooms are displayed.
Given I use different letter casing or surrounding whitespace
When I search
Then matching results are still returned.
Given I select a subject filter
When the results update
Then only classrooms for that subject are displayed.
Given I select the Active status filter
When the results update
Then only active classrooms are displayed.
Given I select the Completed status filter
When the results update
Then only completed classrooms are displayed.
Given I select the All status option
When the results update
Then both active and completed classrooms may be displayed.
Given I combine search, subject, and status filters
When the results update
Then only classrooms matching every selected condition are displayed.
Given no classrooms match the current search and filters
When the request succeeds
Then a clear no-results state is displayed.
Given I do not have any classrooms
When the page loads
Then a clear empty-list state is displayed.
Given I clear the search and filters
When the results refresh
Then the default active classroom list is restored.
Given classroom results are displayed
When I view an item
Then I can see its student, subject, price per hour, status, and creation date.
Given I select a classroom
When navigation occurs
Then I am taken to `/classroom/[classroomId]`.
Given the API request is pending
When the page is waiting
Then an appropriate loading state is displayed.
Given the API request fails
When the error is returned
Then a clear error state is displayed without showing stale results as current.
Given I am logged in as a student
When I call the tutor classroom-list endpoint
Then access is denied.
Given the page is viewed on a narrow screen
When the list and filters render
Then they remain usable without horizontal overflow.
US5-5
As tutor
I want to deactivate a finished classroom
So that it no longer appears in my active classroom list
Given I am the tutor assigned to an active classroom
When I open its detail page
Then a Deactivate Classroom action is visible.
—
Given I am the assigned student
When I open the classroom detail page
Then the deactivation action is not displayed.
Given I am an unrelated user
When I open or request the classroom details
Then I cannot deactivate the classroom.
Given I select Deactivate Classroom
When the confirmation dialog opens
Then it explains that the classroom will leave the active list while its data is retained.
Given the confirmation dialog is open
When I select Cancel
Then no API request is made and the classroom remains active.
Given I confirm deactivation
When the request succeeds
Then the classroom status changes from `active` to `completed`.
Given deactivation succeeds
When the update is complete
Then the classroom row and related records remain in the database.
Given deactivation succeeds
When the frontend handles the response
Then I am redirected to `/classroom`.
Given active classroom queries filter by `status = active`
When the classroom has been deactivated
Then it is no longer included in their results.
Given deactivation is pending
When I select Confirm again
Then another request is not submitted.
Given deactivation fails
When the API returns an error
Then I remain on the detail page and the classroom is not presented as successfully deactivated.
Given I am a student or unrelated tutor
When I call the deactivation endpoint directly
Then access is denied.
Given the classroom ID is malformed or does not exist
When deactivation is requested
Then an appropriate validation or not-found error is returned.
Given the classroom is already completed
When deactivation is requested again
Then the operation does not create additional side effects.