Skip to main content

PMB 2025 Frontend - Documentation

πŸ”Ž Background

Overview​

The PMB 2025 Frontend is the student-facing web application for the RISTEK PMB (Penerimaan Mahasiswa Baru) platform. It provides new students with an interactive onboarding experience including SSO-based login, profile setup, friendship/invitation matching (Pansos & Katalink), puzzle games, assignment submissions, event browsing, leaderboards, badges, and QR code interactions β€” all wrapped in a responsive, mobile-friendly UI.

Stakeholders​

  • Users: New students (maba), senior mentors, PMB committee (panitia)
  • Upstream Dependencies: PMB 2025 Backend API (https://api.pmb.cs.ui.ac.id), UI SSO CAS (https://sso.ui.ac.id/cas2/), AWS S3 (image hosting)
  • Downstream Consumers: None (this is the end-user client application)

Scope & Boundaries​

  • In Scope: User-facing pages (login, onboarding, home, friends, profile, events, assignments, leaderboard, about), SSO authentication flow, Redux state management, API integration with the PMB backend, responsive UI, QR code token system, puzzle game interface.
  • Out of Scope: Admin panel (separate project: pmb2025-admin-panel), backend API logic, Data Science recommendation engine, infrastructure provisioning.

βš™οΈ Architecture & Design

System Diagram​

Architecture Decisions (ADRs)​

  • Language/Framework: TypeScript 4.3.2 / Next.js 12.2.4 (Pages Router) / React 17.0.2
  • State Management: Redux Toolkit with redux-persist (localStorage) and async thunks
  • Styling: Tailwind CSS 2.1.4 + styled-components 5.3.0 + Chakra UI 1.6.5 + Emotion
  • HTTP Client: Axios with JWT interceptor (Authorization: JWT <token>)
  • Form Handling: Formik + Yup (validation), react-hook-form (alternative usage)
  • Animation: Framer Motion
  • Error Monitoring: Sentry (@sentry/nextjs)
  • Deployment: Vercel (production on master, staging preview on staging)
  • Communication: Synchronous REST calls to PMB Backend API; no SSR data fetching, all API calls happen client-side.

πŸ’»Technical Specifications

API Documentation​

The frontend communicates with the PMB Backend via an Axios-based service layer in api/services/. All requests include: Authorization: JWT <token> header (from localStorage) Timezone header (from Intl.DateTimeFormat) Base URL resolution (config.ts):

EnvironmentURL
prodhttps://api.pmb.cs.ui.ac.id
devhttps://stg.api.pmb.cs.ui.ac.id
localhttp://localhost:5000
Service Modules:
ServiceFile
------
ssoapi/services/sso.ts
tokenapi/services/token.ts
profileapi/services/profile.ts
invitationsapi/services/invitations.ts
puzzleapi/services/puzzle.ts
seniorsapi/services/seniors.ts
assignmentapi/services/assignment.ts
eventsapi/services/events.ts
katalinkapi/services/katalink.ts

Pages & Routes​

RouteFileAuthDescription
/pages/index.tsxrequireAnonLogin page (SSO UI popup / LDAP form)
/terms-and-conditionspages/terms-and-conditions/index.tsxrequireAuthTerms & conditions (pre-onboarding)
/onboardingpages/onboarding.tsxrequireAuth3-step onboarding: personal info β†’ interests β†’ match
/homepages/home.tsxrequireAuthHomepage with events, FAQ, token section
/friendspages/friends/index.tsxrequireAuthFriends hub (tabs: Katalink, Puzzle, Seniors/Juniors)
/friends/invitationspages/friends/invitations/index.tsxrequireAuthSent & received invitations list
/friends/invitations/[id]pages/friends/invitations/[id].tsx–Invitation detail
/friends/[id]pages/friends/[id].tsx–Friend profile detail
/friends/seniors/[id]pages/friends/seniors/[id].tsx–Senior profile detail
/friends/invite/[id]pages/friends/invite/[id].tsx–Send invitation flow
/friends/puzzle/[id]pages/friends/puzzle/[id].tsx–Puzzle game interface
/profilepages/profile/index.tsxrequireAuthUser profile page
/profile/badgepages/profile/badge/index.tsx–Badge collection
/profile/badge/[id]pages/profile/badge/[id].tsx–Badge detail
/assignmentpages/assignment/index.tsxrequireAuthAssignment list (Maba only)
/assignment/[id]pages/assignment/[id].tsx–Assignment detail with submission
/eventspages/events/index.tsxrequireAuthEvents list (internal/external tabs)
/events/[slug]pages/events/[slug].tsx–Event detail
/leaderboardpages/leaderboard/index.tsx–Leaderboard (individual & group)
/aboutpages/about/index.tsx–About Fasilkom UI
/failed-qrpages/failed-qr/index.tsx–Failed QR scan handling
/404pages/404.tsx–Custom 404 page

State Management (Redux)​

The app uses Redux Toolkit with redux-persist for selective state persistence to localStorage.

SlicePersistedPurpose
authYes (token, account)Authentication state, login/logout, new account flag
profileNoProfile data, loading states, messages
invitationsNoSent/received invitation lists
assignmentYesAssignment list and details
eventYesEvent list
seniorsNoSenior list, details, loading states
Services are injected into thunks via extraArgument in the Redux middleware configuration. A custom logger middleware is active in development mode.

Authentication Flow​

  • SSO UI Login: user clicks login β†’ popup opens backend URL GET /api/auth/login β†’ backend redirects to UI SSO CAS β†’ CAS authenticates β†’ backend renders index.ejs with token β†’ popup sends token to parent via window.postMessage β†’ frontend stores JWT in localStorage.
  • LDAP Fallback: username/password form β†’ POST /api/auth/ldap β†’ backend authenticates via RISTEK SSO LDAP or SSO Proxy β†’ returns JWT β†’ frontend stores JWT in localStorage.
  • Route Protection: requireAuth HOC checks localStorage for token and redirects to / if missing.
  • Onboarding Guard: users without jurusan or User_Interest are redirected through /terms-and-conditions β†’ /onboarding β†’ /home.
  • Anonymous Guard: requireAnon HOC redirects logged-in users away from the login page to /home.
  • Maba vs Senior: distinguished by comparing angkatan against NEXT_PUBLIC_PMB_YEAR. Maba users have access to assignments; seniors have different friend matching flows.

Data Model/Schema​

Core TypeScript interfaces defined in types/:

Type FileKey Interfaces
common.d.tsErrorAttribute, ServerError, UserData, ProfileData
seniors.d.tsFriends
puzzle.d.tsFriends, PuzzleFriends, MabaReview, Question, QuestionForMaba, Puzzle, PuzzlePayload, PuzzleAnswers, Answer
Additional interfaces are co-located with components (e.g. match.d.ts, invitationInterface.d.ts, friend.d.ts).

Project Structure​

pmb2025-frontend/
β”œβ”€β”€ .github/
β”‚ └── workflows/
β”‚ β”œβ”€β”€ deploy.yml # Production: push to master β†’ Vercel prod
β”‚ └── staging.yml # Staging: push/PR to staging β†’ Vercel preview
β”œβ”€β”€ api/
β”‚ └── services/
β”‚ β”œβ”€β”€ index.ts # Axios interceptor setup + service aggregation
β”‚ β”œβ”€β”€ sso.ts # SSO/LDAP auth calls
β”‚ β”œβ”€β”€ token.ts # Token & QR API calls
β”‚ β”œβ”€β”€ profile.ts # Profile, interests, badges, invitations
β”‚ β”œβ”€β”€ invitations.ts # Invitation CRUD
β”‚ β”œβ”€β”€ puzzle.ts # Puzzle game API
β”‚ β”œβ”€β”€ seniors.ts # Senior profiles, messaging
β”‚ β”œβ”€β”€ assignment.ts # Assignments & submissions
β”‚ β”œβ”€β”€ events.ts # Events & carousel
β”‚ └── katalink.ts # Friendship recommendations
β”œβ”€β”€ components/
β”‚ β”œβ”€β”€ common/
β”‚ β”‚ β”œβ”€β”€ layout.tsx # Main layout wrapper with Navbar
β”‚ β”‚ β”œβ”€β”€ requireAuth.tsx # Auth guard HOC (protected routes)
β”‚ β”‚ β”œβ”€β”€ requireAnon.tsx # Anonymous-only HOC (login page)
β”‚ β”‚ └── analytics.ts # Analytics utilities
β”‚ β”œβ”€β”€ container/ # Page-level container components
β”‚ β”‚ β”œβ”€β”€ Login/ # SSO popup + LDAP login form
β”‚ β”‚ β”œβ”€β”€ Onboarding/ # 3-step onboarding flow
β”‚ β”‚ β”œβ”€β”€ Profile/ # Profile view + edit
β”‚ β”‚ β”œβ”€β”€ Friends/ # Friends hub with tabs
β”‚ β”‚ β”œβ”€β”€ Invitations/ # Invitation management
β”‚ β”‚ β”œβ”€β”€ Events/ # Event listing + detail
β”‚ β”‚ β”œβ”€β”€ Assignments/ # Assignment listing + submission
β”‚ β”‚ β”œβ”€β”€ Leaderboard/ # Individual & group rankings
β”‚ β”‚ β”œβ”€β”€ About/ # About Fasilkom
β”‚ β”‚ β”œβ”€β”€ homepage/ # Home page sections
β”‚ β”‚ β”œβ”€β”€ Footer/ # Page footer
β”‚ β”‚ β”œβ”€β”€ Loading/ # Loading spinner
β”‚ β”‚ β”œβ”€β”€ Error/ # Error display
β”‚ β”‚ β”œβ”€β”€ TermsConditions/ # T&C page
β”‚ β”‚ β”œβ”€β”€ FailedQR/ # QR failure handling
β”‚ β”‚ └── FloatingContactButton/ # Contact button overlay
β”‚ β”œβ”€β”€ module/ # Shared complex modules
β”‚ β”‚ β”œβ”€β”€ Navbar/ # Top navigation bar with profile dropdown
β”‚ β”‚ └── DetailsNavbar/ # Back-navigation for detail pages
β”‚ └── elements/ # Reusable UI primitives
β”‚ β”œβ”€β”€ Button/, Card/, Form/, Input/
β”‚ β”œβ”€β”€ Toast/, Popup/, SearchBar/, PageTab/
β”‚ β”œβ”€β”€ Token/, FriendRequestCard/, Dropzone/
β”‚ β”œβ”€β”€ InterestBadge/, InfiniteScroll/, Podium/
β”‚ β”œβ”€β”€ ModalReview/, AdminMessage/
β”‚ └── FloatingContactButton/
β”œβ”€β”€ hooks/
β”‚ β”œβ”€β”€ windowSize.ts # useWindowSize hook
β”‚ └── swiperRef.ts # useSwiperRef hook
β”œβ”€β”€ libs/
β”‚ β”œβ”€β”€ index.ts # Date checks, URL helpers, puzzle utilities
β”‚ β”œβ”€β”€ dateTime/ # Date/time formatting helpers
β”‚ β”œβ”€β”€ Slugify/ # URL slug generation
β”‚ β”œβ”€β”€ capitalize/ # String capitalization
β”‚ └── Assignment/ # Assignment-specific utilities
β”œβ”€β”€ pages/
β”‚ β”œβ”€β”€ _app.tsx # App root (Redux Provider, PersistGate, ChakraProvider)
β”‚ β”œβ”€β”€ _document.tsx # Custom HTML document
β”‚ β”œβ”€β”€ _error.tsx # Error page with Sentry reporting
β”‚ β”œβ”€β”€ 404.tsx # Custom 404 page
β”‚ β”œβ”€β”€ index.tsx # Login page (root route)
β”‚ β”œβ”€β”€ onboarding.tsx # Onboarding page
β”‚ β”œβ”€β”€ home.tsx # Home dashboard
β”‚ β”œβ”€β”€ friends/ # Friends routes (index, [id], invitations, puzzle, seniors)
β”‚ β”œβ”€β”€ profile/ # Profile routes (index, badge)
β”‚ β”œβ”€β”€ assignment/ # Assignment routes (index, [id])
β”‚ β”œβ”€β”€ events/ # Events routes (index, [slug])
β”‚ β”œβ”€β”€ leaderboard/ # Leaderboard
β”‚ β”œβ”€β”€ about/ # About page
β”‚ β”œβ”€β”€ terms-and-conditions/ # T&C page
β”‚ └── failed-qr/ # Failed QR page
β”œβ”€β”€ public/
β”‚ β”œβ”€β”€ images/ # Static images and illustrations
β”‚ β”œβ”€β”€ favicon/ # Favicon assets
β”‚ └── fonts/ # Custom fonts (SFProDisplay, Literata, SpaceMono, Oswald)
β”œβ”€β”€ redux/
β”‚ β”œβ”€β”€ store.ts # Redux store config (RTK, persist, thunk with services)
β”‚ β”œβ”€β”€ reducers.ts # Root reducer combining all slices
β”‚ β”œβ”€β”€ middlewares/logger/ # Dev-only logging middleware
β”‚ └── slices/
β”‚ β”œβ”€β”€ auth/ # Auth slice (login, logout, token)
β”‚ β”œβ”€β”€ profile/ # Profile slice
β”‚ β”œβ”€β”€ invitations/ # Invitations slice
β”‚ β”œβ”€β”€ assignment/ # Assignment slice
β”‚ β”œβ”€β”€ seniors/ # Seniors slice
β”‚ └── event/ # Event slice
β”œβ”€β”€ styles/
β”‚ β”œβ”€β”€ globals.css # Global styles (font imports, Swiper overrides)
β”‚ └── Home.module.css # CSS Module for home page
β”œβ”€β”€ types/
β”‚ β”œβ”€β”€ common.d.ts # UserData, ProfileData, errors
β”‚ β”œβ”€β”€ seniors.d.ts # Friends type
β”‚ └── puzzle.d.ts # Puzzle, MabaReview, Question types
β”œβ”€β”€ config.ts # API base URL resolution by environment
β”œβ”€β”€ next.config.js # Next.js config (image domains, TS/ESLint ignore)
β”œβ”€β”€ tailwind.config.js # Tailwind config (custom colors, fonts, sizing)
β”œβ”€β”€ postcss.config.js # PostCSS config
β”œβ”€β”€ tsconfig.json # TypeScript config (strict mode, ES5 target)
β”œβ”€β”€ .eslintrc.js # ESLint config
β”œβ”€β”€ .prettierrc # Prettier config
β”œβ”€β”€ sentry.client.config.js # Sentry browser initialization
β”œβ”€β”€ sentry.server.config.js # Sentry server initialization
└── package.json # Dependencies and scripts

Components​

LayerPathsResponsibility
Logincomponents/container/LoginProvides two auth methods β€” SSO UI popup (opens backend /api/auth/login in a new window, listens for postMessage with JWT) and LDAP form (username/password POST to backend). Redirects to onboarding or home based on profile completeness.
Onboardingcomponents/container/OnboardingThree-step wizard: (1) personal information form (name, birth date, school, social media, domicile), (2) interest selection from predefined categories, (3) friend match preview. Uses Formik + Yup for validation.
Layoutcomponents/common/layout.tsxWraps page content with the Navbar component. Navbar is hidden on / (login) and /onboarding. Includes logout popup confirmation.
Friends Hubcomponents/container/FriendsTabbed interface with three sections β€” Katalink (recommendation-based friend matching), Puzzle (puzzle game matching), and Seniors/Juniors (cross-cohort connections). Each tab has its own detail views, invitation flows, and review mechanisms.
Token Sectioncomponents/elements/TokenQR code-based friend connection system. Users can generate QR tokens, scan others' codes, and send friend requests via token input.
Assignmentscomponents/container/AssignmentsAvailable only to Maba users. Lists assignments with due dates, supports file upload to S3 via presigned URLs using react-dropzone, and tracks submission status.
Eventscomponents/container/EventsDisplays PMB events separated by internal/external tabs, with carousel/banner for featured items. Uses Swiper for carousel slides.
Leaderboardcomponents/container/LeaderboardRanking display with individual and group (kelompok) views, featuring a podium component for top 3 and virtualized scrolling for the full list.
Navbarcomponents/module/NavbarTop navigation with profile avatar, dropdown menu (profile, badges, logout), and responsive mobile hamburger menu.

☁️ Operational Playbook

Infrastructure​

  • Cloud Provider: Vercel
  • Production Deployment: Push to master branch β†’ GitHub Actions triggers Vercel production deploy (deploy.yml)
  • Staging Deployment: Push/PR to staging branch β†’ GitHub Actions triggers Vercel preview deploy (staging.yml)
  • Image CDN: Next.js Image Optimization with allowed domains: images.ctfassets.net, pmb22-staging.s3.ap-southeast-1.amazonaws.com
  • Link: https://pmb.cs.ui.ac.id

Environment Variables​

(example)

KeyDescriptionDefault (Dev)Sensitive?
NEXT_PUBLIC_NODE_ENVEnvironment selector for API base URL (prod / dev / local)localNo
NEXT_PUBLIC_PMB_YEARCohort year for Maba vs senior distinction2025No
NEXT_PUBLIC_BEGIN_MAMA (Maba Activity) start dateβ€”No
NEXT_PUBLIC_BEGIN_MMMM (Maba Matching) start dateβ€”No
NEXT_PUBLIC_DEADLINE_MAMA deadline timestampβ€”No
NEXT_PUBLIC_DEADLINE_MMMM deadline timestampβ€”No
NEXT_PUBLIC_DEADLINE_MM_SENIORSenior MM deadline timestampβ€”No
SENTRY_DSNSentry DSN (server-side)β€”Yes
NEXT_PUBLIC_SENTRY_DSNSentry DSN (client-side)β€”Yes
WEBDEV_VERCEL_TOKENVercel deploy token (GitHub Actions secret)β€”Yes
ORG_IDVercel organization ID (GitHub Actions secret)β€”Yes
PROJECT_IDVercel project ID (GitHub Actions secret)β€”Yes

πŸ™‹Questions

πŸ—’ List of frequently asked questions or question that need to be answered that is related to this initiative ..