Milestone 2 - Frontend
Duration: 2 months
Goal: Build the Mastic web frontend as a React application deployed as an IC asset canister. The frontend provides Internet Identity authentication and a Mastodon-like interface covering all user stories from Milestones 0 and 1. After this milestone, users can interact with the Mastic node entirely through a browser.
User Stories: UC1, UC2, UC3, UC4, UC5, UC6, UC7, UC8, UC9, UC10, UC11, UC12, UC15, UC16, UC20, UC21
Prerequisites: Milestone 1 completed.
Work Items
WI-2.1: Frontend project scaffold & Internet Identity authentication
Description: Set up the React project as an IC asset canister with Internet Identity sign-in, agent configuration, and basic app shell.
What should be done:
- Initialize a React project (Vite + TypeScript) under
crates/canisters/frontend/ - Configure
dfx.jsonwith the frontend asset canister - Set up
@dfinity/agentwith actor factories generated from the.didfiles for Directory, Federation, and User canisters - Integrate
@dfinity/auth-clientfor Internet Identity sign-in/sign-out - Implement sign-up page: handle input + call
sign_upon the Directory Canister - Post-auth routing: call
whoamito resolve the User Canister principal, store in app state - Basic app shell: navigation bar with auth status, client-side routing skeleton
Acceptance Criteria:
- The frontend deploys as an asset canister via
dfx deploy - Users can sign in with Internet Identity and sign out
- New users can sign up by choosing a handle
- After sign-in, the app resolves the User Canister principal and stores it in state
- The navigation bar shows the authenticated user’s handle
- Routing works for at least
/,/sign-up, and a placeholder home page
WI-2.2: Feed view & status composer
Description: Build the main timeline view with paginated feed and a status composer for publishing new statuses.
What should be done:
- Implement a feed page that calls
read_feedon the User Canister and renders a paginated list of statuses - Build a status card component displaying: author handle, display name, avatar, content, timestamp, like count, boost count
- Implement infinite scroll or “load more” pagination using the cursor
returned by
read_feed - Build a compose form: text input with character count + call
publish_statuson the User Canister - New statuses appear at the top of the feed after publishing
Acceptance Criteria:
- The feed displays statuses from followed users and the user’s own statuses
- Pagination loads additional statuses without reloading the page
- Status cards show all required fields (author, content, timestamp, counts)
- Publishing a status adds it to the feed
- Empty feed shows a meaningful placeholder message
WI-2.3: Profile view & management
Description: Display user profiles and allow users to edit or delete their own profile.
What should be done:
- Implement a profile page at
/users/{handle}:- Call
get_useron the Directory Canister to resolve the User Canister - Call
get_profileon the target User Canister - Display: handle, display name, bio, avatar, header image, follower/following counts
- Call
- Own profile: show an edit form for display name, bio, avatar URL, and
header URL that calls
update_profileon the User Canister - Delete account flow: confirmation dialog that calls
delete_profileon the Directory Canister, then redirects to the landing page - Make author names/avatars in status cards clickable to navigate to the author’s profile
Acceptance Criteria:
- Any user’s profile can be viewed by navigating to
/users/{handle} - The own profile displays an edit button that opens the edit form
- Updating a field persists the change (verified by reloading the profile)
- Account deletion requires confirmation and redirects after success
- Author links in the feed navigate to the correct profile page
WI-2.4: Follow, like & boost interactions
Description: Implement follow/unfollow, like/unlike, and boost/unboost UI interactions.
What should be done:
- Follow/unfollow button on profile pages:
- Show “Follow” or “Unfollow” based on current relationship
- Call
follow_user/unfollow_useron the User Canister
- Followers and following lists on the profile page:
- Call
get_followers/get_followingon the User Canister - Render paginated lists of user cards linking to their profiles
- Call
- Like button on status cards:
- Toggle like state, call
like_status/undo_like - Update like count optimistically
- Toggle like state, call
- Boost button on status cards:
- Toggle boost state, call
boost_status/undo_boost - Update boost count optimistically
- Toggle boost state, call
- Liked statuses page: call
get_likedand render the list
Acceptance Criteria:
- Follow/unfollow toggles correctly and updates the button state
- Followers and following lists display correct users with pagination
- Like and boost buttons toggle state and update counts immediately
- Undoing a like or boost reverses the action
- The liked statuses page shows all statuses the user has liked
WI-2.5: User search
Description: Implement a search interface for discovering users on the Mastic node.
What should be done:
- Add a search bar in the navigation or a dedicated search page
- Call
search_profileson the Directory Canister with the query string - Display results as user cards (avatar, handle, display name) linking to the user’s profile
- Implement pagination for search results
- Debounce input to avoid excessive queries
Acceptance Criteria:
- Typing a query returns matching users
- Results link to the correct user profiles
- Pagination works when there are many results
- Empty or whitespace-only queries are handled gracefully
- No excessive API calls while the user is still typing
WI-2.6: Moderation tools
Description: Build moderator-specific UI for content and user moderation. These controls are only visible to users who are moderators.
What should be done:
- Detect moderator status (e.g., by checking with the Directory Canister whether the current principal is a moderator)
- Show a delete button on any status card when the user is a moderator:
- Call
delete_statuson the author’s User Canister - Remove the status from the feed on success
- Call
- Show a suspend button on user profiles when the user is a moderator:
- Confirmation dialog explaining the action
- Call
suspendon the Directory Canister
- Moderator management page (accessible from settings or nav):
- List current moderators
- Add moderator by principal: call
add_moderator - Remove moderator: call
remove_moderator(with safeguard against removing the last moderator)
- Block user button on profile pages (available to all users):
- Call
block_useron the User Canister
- Call
Acceptance Criteria:
- Non-moderators do not see moderation controls (delete on others’ statuses, suspend, moderator management)
- Moderators can delete any status and it disappears from the feed
- Moderators can suspend a user, who then cannot interact with the platform
- The moderator list is displayed correctly
- Adding and removing moderators works, with a safeguard against removing the last one
- Any user can block another user from their profile page
WI-2.7: Frontend build pipeline & deployment
Description: Integrate the frontend build into the existing just
command workflow and CI pipeline.
What should be done:
- Add
just build_frontendcommand: runs the Vite production build and outputs to the asset canister directory - Add
just dfx_deploy_frontendcommand: deploys the asset canister locally - Update
just build_allto include the frontend build - Update
just dfx_deploy_localto include the frontend canister - Ensure the frontend build works in CI (install Node.js dependencies, run build)
- Add
just test_frontendcommand for running frontend unit tests
Acceptance Criteria:
just build_frontendproduces a production build without errorsjust dfx_deploy_localdeploys all canisters including the frontend- The deployed frontend is accessible at the asset canister URL
- CI can build and deploy the frontend
- Frontend unit tests run via
just test_frontend
WI-2.8: Frontend end-to-end tests
Description: Write end-to-end tests that exercise the full user journey through the frontend against real canisters deployed on a local dfx replica.
What should be done:
- Set up a Playwright (or Cypress) test harness:
- Install test dependencies and configure the test runner
- Add
just test_frontend_e2ecommand - Tests start a local dfx replica, deploy all canisters, and run against the deployed frontend
- Implement e2e test flows:
- Sign-up & sign-in: Navigate to sign-up page, create account with a handle, verify redirect to home feed
- Publish status: Compose and publish a text status, verify it appears in the feed
- View profile: Navigate to own profile, verify handle, display name, and status list are shown
- Update profile: Edit display name and bio, verify changes persist after reload
- Follow user: Navigate to another user’s profile, click follow, verify follower count updates and statuses appear in feed
- Unfollow user: Unfollow a followed user, verify follower count decreases
- Like & boost: Like and boost a status, verify count updates; undo both, verify counts revert
- Reply to status: Reply to a status, verify the reply appears in the thread view
- Media attachment: Publish a status with an image attachment, verify it renders in the feed
- Search: Search for a user by handle prefix, verify results link to the correct profile
- Delete status: Delete own status, verify it disappears from feed
- Delete account: Delete account, verify redirect to landing page and sign-in fails
- Moderation (moderator role): As a moderator, delete another user’s status and suspend a user, verify the actions take effect
- Block user: Block a user, verify their content is hidden
- CI integration: add e2e tests to the CI pipeline (may run as a separate job due to replica startup time)
Acceptance Criteria:
- All e2e test flows pass against a local dfx replica
- Tests run via
just test_frontend_e2e - Tests are independent and idempotent (each test sets up its own state)
- CI runs e2e tests (or they can be triggered manually)
- Tests cover both happy paths and key error cases (e.g., duplicate handle on sign-up)