Skip to main content

Ristek Tutor Kelas Frontend - Documentation

πŸ”Ž Background

Overview​

The Ristek Tutor Kelas Frontend is the web application for the RISTEK peer tutoring platform. It provides UI students with an interface to find and book tutoring sessions, manage schedules, and track session logs. Tutors can create availability slots, manage their sessions, and submit post-session logs with proof for admin verification. The application integrates with UI SSO for authentication and supports role-based navigation for tutees and tutors.

Stakeholders​

  • Users: UI students (tutees seeking tutoring), student tutors, admin (log verification via backend)
  • Upstream Dependencies: Ristek Tutor Kelas Backend API, UI SSO CAS (https://sso.ui.ac.id/cas2), MinIO/S3 (file storage for images)
  • Downstream Consumers: None (this is the end-user client application)

Scope & Boundaries​

  • In Scope: Landing page, SSO authentication flow, user profile management with onboarding, tutor registration with course scores, session browsing and booking (with payment proof upload), session management (tutor and tutee views), session rescheduling, schedule creation (tutor), session log creation and detail view, role-based navigation, responsive design.
  • Out of Scope: Backend API logic, admin panel for log verification/payment, payment gateway integration, email notifications.

βš™οΈ Architecture & Design

System Diagram​

Architecture Decisions (ADRs)​

  • Language/Framework: TypeScript 5 / Next.js 15 (App Router) / React 19
  • Build: Turbopack in development (next dev --turbopack)
  • State Management: React Context (AuthContext) + local useState; no global state library
  • Styling: Tailwind CSS 4 with tw-animate-css, class-variance-authority for component variants, tailwind-merge + clsx for class composition
  • UI Primitives: Radix UI (accordion, dialog, dropdown, popover, checkbox, scroll area, separator) + RSuite (rich components)
  • Form Handling: react-hook-form 7 + Zod 4 for schema validation
  • Data Tables: TanStack React Table 8 with custom pagination and filters
  • HTTP Client: Axios 1.10 with 401 interceptor for automatic token refresh
  • Icons: Lucide React + React Icons
  • Toast Notifications: Sonner
  • Date Handling: date-fns + react-day-picker
  • Fonts: Geist, Geist Mono, Poppins (via next/font/google)
  • Deployment: Vercel via GitHub Actions
  • Rendering: force-dynamic root layout with server-side user fetching; server actions for data mutations

πŸ’»Technical Specifications

API Documentation​

The frontend uses a dual-layer API approach: Next.js API Routes (app/api/) β€” BFF proxy for authentication, handling cookie management (httpOnly JWT tokens) Server Actions (actions/) β€” Direct backend calls with auth headers for data operations Backend base URL: NEXT_PUBLIC_API_URL environment variable. Axios configuration (config/axiosConfig.ts): Base URL from NEXT_PUBLIC_API_URL withCredentials: true for cookie-based auth 401 response interceptor: attempts token refresh via /api/auth/refresh, retries request; on failure redirects to /login

Next.js API Routes (BFF Proxy)​

EndpointMethodBackend TargetDescription
/api/auth/loginPOSTSSO redirectInitiates SSO login, returns CAS login URL
/api/auth/callbackPOSTPOST /user/sso/callback/Validates CAS ticket, sets JWT cookies
/api/auth/login-devPOSTPOST /user/login/Dev login with username/password, sets JWT cookies
/api/auth/refreshPOSTPOST /user/token/refresh/Refresh JWT, updates cookies
/api/auth/meGETGET /user/me/Get current user from access token cookie
/api/auth/logoutPOSTβ€”Clears JWT cookies
/api/tutor/upgradePOSTPOST /user/apply/Submit tutor application

Server Actions (actions/)​

ActionBackend TargetDescription
getUserActionGET /user/me/Fetch current user profile (server-side)
getTutorsActionGET /user/tutorsList all tutors
submitProfileFormPATCH /user/update_profile/Update user profile (onboarding)
submitApplyTutorActionPOST /user/apply/Submit tutor application with course scores
registerTutorActionPOST /user/apply/Register as tutor
getMatkulActionGET /tutor-session/matkul/List mata kuliah
getAvailableSessionsGET /tutor-session/sessions/Browse available sessions (filterable)
createTutorSessionPOST /tutor-session/tutor/sessions/Create tutor session
getMySessionsActionGET /tutor-session/...List own sessions
getSessionDetailActionGET /tutor-session/...Session detail
getTutorSessionsActionGET /tutor-session/tutor/sessions/List tutor sessions
getTuteeSessionsActionGET /tutor-session/tutee/sessions/List tutee sessions
getTuteeSessionGET /tutor-session/tutee/sessions/{id}/Tutee session detail
submitPesanSesiFormPOST /tutor-session/tutee/book/{id}/Book a session
updateSessionStatusActionPUT /tutor-session/...Update session status
updateSessionEmailsActionPATCH /tutor-session/tutee/sessions/{id}/emails/Update booking emails
updateTuteeSessionActionPUT /tutor-session/tutee/sessions/{id}/Update tutee session
upgradeBookingActionPUT /tutor-session/tutee/sessions/{id}/Upgrade session package
rescheduleSessionActionPOST /tutor-session/tutee/reschedule/...Reschedule session
getRescheduleSessionDataGET /tutor-session/...Get reschedule data
getTutorLogsGET /logs/tutor/logsList tutor logs
getTutorLogDetailGET /logs/tutor/logs/{id}Log detail
createLogSesiPOST /logs/tutor/logsCreate session log

Pages & Routes​

RouteFileAuthDescription
/app/page.tsxPublicLanding page (hero, info sections, FAQ)
/loginapp/login/page.tsxPublicSSO UI login page
/profilapp/profil/page.tsxProtectedUser profile (view & edit, onboarding)
/profil/register-tutorapp/profil/register-tutor/page.tsxProtectedTutor registration form (course scores, GPA)
/pesan-sesiapp/pesan-sesi/page.tsxProtectedBrowse and book tutoring sessions (multi-step)
/pesan-sesi/berhasilapp/pesan-sesi/berhasil/page.tsxProtectedBooking success confirmation
/sesi-sayaapp/sesi-saya/page.tsxProtectedMy sessions (tutor/tutee table view)
/sesi-saya/[id]app/sesi-saya/[id]/page.tsxProtectedSession detail (status, links, actions)
/sesi-saya/[id]/upgradeapp/sesi-saya/[id]/upgrade/page.tsxProtectedUpgrade session package type
/tambah-jadwalapp/tambah-jadwal/page.tsxProtectedAdd schedule/availability (tutor only)
/log-sesiapp/log-sesi/page.tsxProtectedTutor session logs list
/log-sesi/tambahapp/log-sesi/tambah/page.tsxProtectedCreate new session log
/log-sesi/[id]app/log-sesi/[id]/page.tsxProtectedLog detail view

Authentication Flow​

  • SSO Login: user clicks login β†’ frontend redirects to https://sso.ui.ac.id/cas2/login?service=<APP_URL>/login β†’ CAS authenticates β†’ redirects back with ?ticket= parameter.
  • Ticket Processing: SSOHandler detects ?ticket= in the URL β†’ calls POST /api/auth/callback with ticket and service URL β†’ API route validates ticket with backend POST /user/sso/callback/ β†’ backend returns JWT tokens β†’ API route sets access_token (7-day) and refresh_token (30-day) as httpOnly cookies.
  • Session Restoration: on page load, root layout.tsx calls getUserAction() server-side to fetch the current user β†’ passes it as initialUser to AuthWrapper context.
  • Token Refresh: Axios 401 interceptor calls POST /api/auth/refresh β†’ API route reads refresh_token cookie β†’ sends it to backend β†’ updates access_token cookie β†’ retries the failed request.
  • Logout: calls POST /api/auth/logout β†’ clears cookies β†’ sends hidden iframe to SSO logout URL (https://sso.ui.ac.id/cas2/logout) for SSO session cleanup β†’ redirects to /.
  • Dev Login: POST /api/auth/login-dev with username/password for development and testing.
  • Middleware (middleware.ts): checks access_token cookie on all non-public routes. Public routes are / and /login. Unauthenticated requests are redirected to /login?redirect=<originalPath>.

Data Model/Schema​

FileKey Types
types/user.tsUserType (npm, username, email, full_name, is_tutor, application_status, tutor_profile, jurusan, batch, preferred_subjects, is_complete, profile_picture_url), TutorProfile, Subject, ApplicationStatus, ClassTypeEnum
types/session.tsSessionStatus (tersedia, telah dipesan, dikonfirmasi, direschedule, in request reschedule, dibatalkan, etc.), TutorSession, sessionPackage (triad/penta/hepta/deca), SessionTableData, SessionOption
types/log.tsLogStatus, MataKuliah, TutorSessionInfo, TutorLog, LogTableData
types/matkul.tsMatkul, MatkulOption
types/navbar.tsUserRole, NavLinkType, BaseNavLink, IconNavLink, StringNavLink
Zod schemas (form validation):
modules/PesanSesi/schema.ts β€” pesanSesiSchema (date range, email list, package selection)
modules/TambahLogSesi/types/schema.ts β€” logSesiSchema (log creation validation)

Project Structure​

ristek-tutor-frontend/
β”œβ”€β”€ .github/
β”‚ └── workflows/
β”‚ β”œβ”€β”€ deploy.yml # Production: push to main β†’ Vercel prod
β”‚ └── staging.yml # Staging: push to staging β†’ Vercel preview
β”œβ”€β”€ actions/ # Server actions (backend API calls)
β”‚ β”œβ”€β”€ getUserAction.ts # Fetch current user
β”‚ β”œβ”€β”€ getTutorsAction.ts # List tutors
β”‚ β”œβ”€β”€ submitProfileForm.ts # Update profile (onboarding)
β”‚ β”œβ”€β”€ submitApplyTutorAction.ts # Apply as tutor
β”‚ β”œβ”€β”€ getMatkulAction.ts # List mata kuliah
β”‚ β”œβ”€β”€ getAvailableSessions.ts # Browse sessions
β”‚ β”œβ”€β”€ createTutorSession.ts # Create session (tutor)
β”‚ β”œβ”€β”€ getMySessionsAction.ts # My sessions
β”‚ β”œβ”€β”€ getSessionDetailAction.ts # Session detail
β”‚ β”œβ”€β”€ getTutorSessionsAction.ts # Tutor sessions
β”‚ β”œβ”€β”€ getTuteeSessionsAction.ts # Tutee sessions
β”‚ β”œβ”€β”€ getTuteeSession.ts # Tutee session detail
β”‚ β”œβ”€β”€ submitPesanSesiForm.ts # Book session
β”‚ β”œβ”€β”€ updateSessionStatusAction.ts # Update session status
β”‚ β”œβ”€β”€ updateSessionEmailsAction.ts # Update booking emails
β”‚ β”œβ”€β”€ updateTuteeSessionAction.ts # Update tutee session
β”‚ β”œβ”€β”€ upgradeBookingAction.ts # Upgrade session package
β”‚ β”œβ”€β”€ rescheduleSessionAction.ts # Reschedule session
β”‚ β”œβ”€β”€ getRescheduleSessionData.ts # Reschedule data
β”‚ β”œβ”€β”€ getTutorLogs.ts # List tutor logs
β”‚ β”œβ”€β”€ getTutorLogDetail.ts # Log detail
β”‚ β”œβ”€β”€ createLogSesi.ts # Create session log
β”‚ └── registerTutorAction.ts # Register tutor
β”œβ”€β”€ app/
β”‚ β”œβ”€β”€ api/
β”‚ β”‚ β”œβ”€β”€ auth/
β”‚ β”‚ β”‚ β”œβ”€β”€ callback/route.ts # SSO CAS ticket validation
β”‚ β”‚ β”‚ β”œβ”€β”€ login/route.ts # SSO login redirect
β”‚ β”‚ β”‚ β”œβ”€β”€ login-dev/route.ts # Dev login (username/password)
β”‚ β”‚ β”‚ β”œβ”€β”€ logout/route.ts # Clear JWT cookies
β”‚ β”‚ β”‚ β”œβ”€β”€ me/route.ts # Current user proxy
β”‚ β”‚ β”‚ └── refresh/route.ts # JWT refresh proxy
β”‚ β”‚ └── tutor/
β”‚ β”‚ └── upgrade/route.ts # Tutor application proxy
β”‚ β”œβ”€β”€ layout.tsx # Root layout (AuthWrapper, Navbar, Footer, Toaster)
β”‚ β”œβ”€β”€ globals.css # Global styles (Tailwind, design tokens)
β”‚ β”œβ”€β”€ page.tsx # Landing page
β”‚ β”œβ”€β”€ login/page.tsx # Login page
β”‚ β”œβ”€β”€ profil/ # Profile pages
β”‚ β”‚ β”œβ”€β”€ layout.tsx # Profile layout
β”‚ β”‚ β”œβ”€β”€ page.tsx # Profile view/edit
β”‚ β”‚ └── register-tutor/page.tsx # Tutor registration
β”‚ β”œβ”€β”€ pesan-sesi/ # Session booking
β”‚ β”‚ β”œβ”€β”€ page.tsx # Browse & book sessions
β”‚ β”‚ └── berhasil/page.tsx # Booking success
β”‚ β”œβ”€β”€ sesi-saya/ # My sessions
β”‚ β”‚ β”œβ”€β”€ page.tsx # Sessions table
β”‚ β”‚ └── [id]/
β”‚ β”‚ β”œβ”€β”€ page.tsx # Session detail
β”‚ β”‚ └── upgrade/page.tsx # Upgrade package
β”‚ β”œβ”€β”€ tambah-jadwal/page.tsx # Add schedule (tutor)
β”‚ └── log-sesi/ # Session logs
β”‚ β”œβ”€β”€ page.tsx # Logs list
β”‚ β”œβ”€β”€ tambah/page.tsx # Create log
β”‚ └── [id]/page.tsx # Log detail
β”œβ”€β”€ components/
β”‚ β”œβ”€β”€ auth/
β”‚ β”‚ └── SSOHandler.tsx # Detects ?ticket= and triggers SSO callback
β”‚ β”œβ”€β”€ elements/
β”‚ β”‚ β”œβ”€β”€ Layout/
β”‚ β”‚ β”‚ β”œβ”€β”€ Navbar.tsx # Top nav with role-based links
β”‚ β”‚ β”‚ β”œβ”€β”€ Footer.tsx # Site footer
β”‚ β”‚ β”‚ β”œβ”€β”€ NavLink.tsx # Nav link component
β”‚ β”‚ β”‚ └── ProfileDropdown.tsx # Profile menu with logout
β”‚ β”‚ β”œβ”€β”€ form/
β”‚ β”‚ β”‚ β”œβ”€β”€ RistekCalendar.tsx # Calendar date picker
β”‚ β”‚ β”‚ β”œβ”€β”€ RistekCalendarModal.tsx # Calendar in modal
β”‚ β”‚ β”‚ β”œβ”€β”€ RistekCombobox.tsx # Searchable combobox
β”‚ β”‚ β”‚ β”œβ”€β”€ RistekDropdownFilter.tsx # Dropdown filter
β”‚ β”‚ β”‚ β”œβ”€β”€ RistekFileInput.tsx # File upload input
β”‚ β”‚ β”‚ β”œβ”€β”€ RistekInput.tsx # Text input
β”‚ β”‚ β”‚ β”œβ”€β”€ RistekMultiSelect.tsx # Multi-select
β”‚ β”‚ β”‚ └── RistekTimeInput.tsx # Time picker
β”‚ β”‚ β”œβ”€β”€ table/
β”‚ β”‚ β”‚ β”œβ”€β”€ DataTable.tsx # Generic data table
β”‚ β”‚ β”‚ β”œβ”€β”€ FilterBar.tsx # Table filter bar
β”‚ β”‚ β”‚ β”œβ”€β”€ Pagination.tsx # Pagination controls
β”‚ β”‚ β”‚ β”œβ”€β”€ TablePagination.tsx # Table pagination variant
β”‚ β”‚ β”‚ └── ActionButtons.tsx # Row action buttons
β”‚ β”‚ β”œβ”€β”€ AccordionFAQ.tsx # FAQ accordion
β”‚ β”‚ β”œβ”€β”€ FAQCard.tsx # FAQ card
β”‚ β”‚ β”œβ”€β”€ InfoContainer.tsx # Info section container
β”‚ β”‚ β”œβ”€β”€ LogStatusCard.tsx # Log status display
β”‚ β”‚ β”œβ”€β”€ ProfileCard.tsx # User profile card
β”‚ β”‚ β”œβ”€β”€ RistekBreadcrumb.tsx # Breadcrumb navigation
β”‚ β”‚ β”œβ”€β”€ RistekCheckbox.tsx # Checkbox
β”‚ β”‚ β”œβ”€β”€ RistekToast.tsx # Toast notification wrapper (Sonner)
β”‚ β”‚ β”œβ”€β”€ SessionStatusCard.tsx # Session status display
β”‚ β”‚ β”œβ”€β”€ StatusBadge.tsx # Status badge (colored)
β”‚ β”‚ └── Typography.tsx # Typography variants
β”‚ β”œβ”€β”€ ui/ # Radix-based primitives (shadcn/ui pattern)
β”‚ β”‚ β”œβ”€β”€ accordion.tsx, badge.tsx, breadcrumb.tsx, button.tsx
β”‚ β”‚ β”œβ”€β”€ calendar.tsx, checkbox.tsx, combobox.tsx, command.tsx
β”‚ β”‚ β”œβ”€β”€ dialog.tsx, dropdown-menu.tsx, multi-select.tsx
β”‚ β”‚ β”œβ”€β”€ popover.tsx, scroll-area.tsx, separator.tsx
β”‚ β”‚ β”œβ”€β”€ sonner.tsx, table.tsx
β”‚ └── ErrorList.tsx # Error list display
β”œβ”€β”€ config/
β”‚ └── axiosConfig.ts # Axios instance with 401 refresh interceptor
β”œβ”€β”€ context/
β”‚ └── AuthContext.tsx # Auth state, SSO callback handler, logout
β”œβ”€β”€ hooks/
β”‚ β”œβ”€β”€ useFileUpload.ts # File upload hook
β”‚ └── useMediaQuery.ts # Responsive media query hook
β”œβ”€β”€ lib/
β”‚ β”œβ”€β”€ utils.ts # cn() class merge utility
β”‚ β”œβ”€β”€ roleUtils.ts # Role-based redirect helpers
β”‚ β”œβ”€β”€ sessionUtils.ts # Session status/type helpers
β”‚ └── tableUtils.ts # Table formatting utilities
β”œβ”€β”€ modules/ # Feature modules (page-level components)
β”‚ β”œβ”€β”€ LandingPage/ # Landing: hero, info sections, FAQ
β”‚ β”œβ”€β”€ Login/ # Login page module
β”‚ β”œβ”€β”€ Profil/ # Profile: view, edit, tutor registration
β”‚ β”œβ”€β”€ PesanSesi/ # Book session: multi-step (browse β†’ details)
β”‚ β”œβ”€β”€ SesiSaya/ # My sessions: table, detail, reschedule, upgrade
β”‚ β”œβ”€β”€ TambahJadwal/ # Add schedule form (tutor)
β”‚ β”œβ”€β”€ LogSesi/ # Log list with data table
β”‚ └── TambahLogSesi/ # Create log form with Zod schema
β”œβ”€β”€ types/ # Shared TypeScript types
β”‚ β”œβ”€β”€ user.ts, session.ts, log.ts, matkul.ts, navbar.ts
β”œβ”€β”€ public/
β”‚ β”œβ”€β”€ images/ # Static images (landing, profile, navbar, footer)
β”‚ └── icons/ # SVG icons
β”œβ”€β”€ middleware.ts # Route protection (access_token cookie check)
β”œβ”€β”€ next.config.ts # Next.js config (10mb body limit, image domains)
β”œβ”€β”€ tsconfig.json # TypeScript config (strict, @/* alias)
β”œβ”€β”€ postcss.config.mjs # PostCSS (Tailwind)
β”œβ”€β”€ eslint.config.mjs # ESLint config
└── package.json # Dependencies and scripts

Components​

LayerPathsResponsibility
Root Layoutapp/layout.tsxServer-side async layout that fetches the current user via getUserAction() and provides it as initialUser to AuthWrapper. Wraps all pages with Navbar, Footer, SSOHandler, and Toaster (Sonner). Uses force-dynamic rendering. Loads Geist, Geist Mono, and Poppins fonts.
SSOHandlercomponents/auth/SSOHandler.tsxClient component that monitors the URL for ?ticket= query parameters on mount. When detected, triggers handleSSOCallback() from AuthContext to complete the SSO login flow. Handles the CAS redirect-back automatically.
Navbarcomponents/elements/Layout/Navbar.tsxRole-aware navigation bar. Shows different links for tutors (Sesi Saya, Tambah Jadwal, Log Sesi) vs tutees (Pesan Sesi, Sesi Saya). Includes mobile hamburger menu and ProfileDropdown with avatar and logout.
Profile Modulemodules/Profil/Profile view and edit form with onboarding support. Includes ProfileForm for personal details (name, phone, LINE ID, preferred subjects, class type), DaftarTutor section for tutor registration, DaftarUlang for re-registration, and VerifiedCard for verified status display.
Register Tutormodules/Profil/RegisterTutor/Tutor registration form with RegisterTutorForm section for submitting course scores and GPA.
Pesan Sesi Modulemodules/PesanSesi/Multi-step session booking flow. Step 1: browse available sessions with filters (mata kuliah, tutor, date). Step 2: fill booking details (package type, participant emails, payment proof upload). Uses Zod schema validation. SessionCard and SessionSelect components for session selection UI.
Sesi Saya Modulemodules/SesiSaya/Session management with TanStack Table (SesiSayaTable), column definitions (tableSchema), RescheduleModal for rescheduling flow, and UpgradePaket for upgrading session package types.
Tambah Jadwal Modulemodules/TambahJadwal/Tutor schedule creation form with date picker, time input, and mata kuliah selection.
Log Sesi Modulemodules/LogSesi/ + modules/TambahLogSesi/Session log management. LogDataTable with filters for listing logs. LogSesiForm for creating logs with participant count, session selection, and image proof upload. Uses Zod schema for validation.
Data Tablecomponents/elements/table/DataTable.tsxGeneric reusable data table built on TanStack React Table with FilterBar, Pagination, and ActionButtons. Used across sessions and logs views.
Form Componentscomponents/elements/form/Suite of reusable RISTEK-branded form inputs: RistekInput, RistekCalendar, RistekCalendarModal, RistekCombobox, RistekDropdownFilter, RistekFileInput, RistekMultiSelect, RistekTimeInput. Built on top of Radix UI and RSuite primitives.

☁️ Operational Playbook

Infrastructure​

  • Cloud Provider: Vercel
  • Production Deployment: Push to main β†’ GitHub Actions (deploy.yml) β†’ Vercel production deploy
  • Staging Deployment: Push to staging β†’ GitHub Actions (staging.yml) β†’ Vercel preview deploy
  • Image CDN: Next.js Image Optimization with allowed remote patterns: localhost:8000, localhost:9000, stg.api.classtutor.ristek.cs.ui.ac.id, storage.ristek.cs.ui.ac.id
  • Server Actions: Body size limit set to 10mb (for file uploads)

Environment Variables​

(example)

KeyDescriptionDefault (Dev)Sensitive?
NEXT_PUBLIC_API_URLBackend API base URLβ€”No
NEXT_PUBLIC_APP_URLFrontend base URL (used for SSO service URL and logout redirect)β€”No
NODE_ENVEnvironment (controls cookie secure flag)developmentNo
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 ..