StudyApp is a modern peer-to-peer tutoring marketplace that connects students directly with expert tutors. Students choose what to learn, who to learn from, and when β on their own terms.
The app is split into two independent codebases:
- Flutter frontend β cross-platform app (Android, iOS, Web)
- NestJS backend β REST API backed by PostgreSQL on Supabase
See _server/README.md for detailed API documentation.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Flutter App (Client) β
β β
β features/auth/ features/student/ features/teacher/ β
β features/chat/ features/subscription/ β
β β
β core/services/ β
β AuthService β all auth HTTP calls (login/register) β
β AuthState β singleton: JWT token, userId, role β
β UserApiService β all user HTTP calls (profile, etc.) β
β β
β core/themes/ AppColors Β· AppTypography Β· AppSizes β
β core/widgets/ PrimaryButton Β· TextInput Β· AvatarWidgetβ
β routes/ named routes, Navigator.pushNamed(...) β
ββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β HTTP / JSON (REST)
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β NestJS Backend (_server/) β Modular Monolith β
β AuthModule Β· UserModule Β· BookingModule Β· MessagesModule β
β CoinsModule Β· ReviewsModule Β· NotificationsModule β
β OffersModule Β· DailyModule Β· AdminModule Β· InternalModule β
ββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β SQL via Prisma ORM
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PostgreSQL on Supabase β
β profiles Β· bookings Β· messages Β· reviews Β· transactions β
β tutor_offers Β· tutor_availabilities Β· subjects Β· notificationsβ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
study-app/
β
βββ lib/ # Flutter Frontend
β βββ main.dart # App entry point
β β
β βββ features/ # Feature modules (screens + widgets)
β β βββ auth/
β β β βββ screens/
β β β βββ splash_screen.dart β
done
β β β βββ onboarding_screen.dart β
done
β β β βββ login_screen.dart β
done
β β β βββ register_screen.dart β
done
β β β βββ update_profile_screen.dart β
done
β β β
β β βββ student/
β β β βββ screens/
β β β βββ student_dashboard.dart β
done (5-tab nav)
β β β βββ course_detail_screen.dart β
done (UI)
β β β βββ live_class_screen.dart β
done (UI)
β β β
β β βββ teacher/
β β β βββ screens/
β β β βββ teacher_dashboard.dart β
done (5-tab nav)
β β β
β β βββ chat/
β β β βββ screens/
β β β βββ chat_detail_screen.dart β
done (UI only, not wired to API)
β β β
β β βββ subscription/
β β β βββ screens/
β β β βββ subscription_plans_screen.dart β
done (UI only)
β β β βββ payment_screen.dart β
done (UI only)
β β β βββ payment_success_screen.dart β
done (UI only)
β β β
β β βββ test/ # Test/playground screens
β β
β βββ core/
β β βββ constants/
β β β βββ app_config.dart β
done (useMock toggle, apiUrl, timeout)
β β β
β β βββ services/
β β β βββ auth_service.dart β
done (login, register, logout β centralized)
β β β βββ auth_state.dart β
done (JWT singleton: token, userId, role)
β β β βββ user_api_service.dart β
done (updateProfile)
β β β
β β βββ themes/
β β β βββ app_theme.dart β
done
β β β βββ app_colors.dart β
done (primary: #1479FF)
β β β βββ app_typography.dart β
done
β β β βββ app_sizes.dart β
done
β β β
β β βββ widgets/
β β βββ primary_button.dart β
done
β β βββ text_input.dart β
done
β β βββ password_text_field.dart β
done
β β βββ avatar_widget.dart β
done
β β βββ search_input.dart β
done
β β
β βββ models/ # Shared data models
β β βββ user_model.dart β
done
β β βββ course_model.dart β
done
β β βββ teacher_model.dart β
done
β β βββ live_class_model.dart β
done
β β
β βββ routes/
β β βββ app_routes.dart β
done (all named routes)
β β
β βββ assets/images/
β βββ logo.jpeg β
app logo
β
βββ _server/ # NestJS Backend β see _server/README.md
β βββ src/
β β βββ auth/ β
complete
β β βββ user/ β
complete
β β βββ generated/prisma/ β
auto-generated
β βββ prisma/
β βββ schema.prisma β
complete (9 tables)
β βββ migrations/
β
βββ docs.md # Full architectural documentation
βββ pubspec.yaml # Flutter dependencies
βββ README.md # This file
| Area | What's done |
|---|---|
| Auth flow | Full end-to-end: splash β onboarding β login/register β update profile β dashboard |
| Auth service | Centralized AuthService β login, register, logout, mock mode for dev |
| Auth state | AuthState singleton β stores JWT token, userId, email, role across the whole app |
| Mock mode | AppConfig.useMock = true β screens work without a live backend for development |
| Login screen | Email + password form, error display, loading state |
| Register screen | Email + password + confirm, delegates to AuthService |
| Update profile | Full name, username, bio, role picker β calls UserApiService.updateProfile |
| Student dashboard | 5-tab nav: Home, Explore, Learning, Messages, Profile |
| Teacher dashboard | 5-tab nav: Home, Courses, Students, Earnings, Profile |
| Chat UI | Full chat detail screen with message list + input (UI only) |
| Subscription UI | Plans screen (Free/Premium/Pro, monthly/yearly toggle) |
| Payment UI | Payment method selection + order summary |
| Payment success | Animated success screen |
| Shared widgets | PrimaryButton, TextInput, PasswordTextField, AvatarWidget, SearchInput |
| Theme system | Material 3, AppColors, AppTypography, AppSizes |
| Routing | All named routes in AppRoutes, navigator helpers |
| Task | Status |
|---|---|
Centralized AuthService refactor |
β done on this branch β replacing inline HTTP calls in screens |
AppConfig mock/live toggle |
β
done β useMock flag for dev without backend |
Wiring auth screens to AuthService |
β login, register, update profile all use it |
| Student dashboard API integration | π in progress β real tutor data from GET /user/tutors/all |
| Priority | Task |
|---|---|
| High | Wire student dashboard to live API (tutor browse, search, filter) |
| High | Google Sign-In integration on login screen |
| High | AuthState persistence β survive app kill/restart (SharedPreferences or secure storage) |
| High | Tutor detail screen β show profile + offers from GET /user/tutor/:id |
| High | Booking flow β select offer β confirm β payment |
| Medium | Chat API integration β send/receive real messages |
| Medium | Teacher dashboard API integration β show real bookings, students |
| Medium | Profile screen β display and edit own profile |
| Medium | Subscription backend integration |
| Medium | Tutor availability management (teacher side) |
| Low | Push notifications |
| Low | Review/rating UI |
| Low | Offline mode / error states |
| Low | Dark mode |
| Low | iOS build testing |
See _server/README.md for full details.
| Module | Status |
|---|---|
| Auth (signup, login, Google OAuth, JWT) | β Complete |
| User profiles (CRUD, tutor search/filter) | β Complete |
| Booking (create, confirm, reschedule, expire) | β Complete |
| Messages (per-booking chat) | β Complete |
| Reviews (post-session rating) | β Complete |
| Tutor offers (create, manage, pricing) | β Complete |
| Coins (balance, transactions, price proposals) | β Complete |
| Notifications | β Complete |
| Admin module (ban, verify tutors, refunds) | β Complete |
| Payment (Midtrans QRIS integration) | β Complete |
| Withdrawal requests (tutor cashout) | β Complete |
| Daily jobs (auto-expire bookings, etc.) | β Complete |
| Unit tests β 62 tests, 5 suites | β Passing |
| Tool | Purpose |
|---|---|
| Flutter 3.5+ | Cross-platform UI framework |
| Dart | Language |
| HTTP | REST API calls |
| Google Sign-In | OAuth |
| Google Fonts | Typography |
| Font Awesome Flutter | Icons |
| Material 3 | Design system |
| Tool | Purpose |
|---|---|
| NestJS v11 | Modular Node.js framework |
| TypeScript | Language |
| Prisma ORM v7 | Type-safe DB access + migrations |
| PostgreSQL | Database (hosted on Supabase) |
| argon2 | Password hashing |
| JWT + Passport | Stateless auth + strategy guards |
| Helmet | HTTP security headers |
| @nestjs/throttler | Rate limiting |
| Midtrans | Payment gateway (QRIS, Indonesia) |
| Jest + ts-jest | Unit testing |
| Route | Screen | Status |
|---|---|---|
/ |
Splash screen β animated logo, auto-navigate | β |
/onboarding |
4-page swipeable intro | β |
/login |
Email + password login | β |
/register |
Email + password registration | β |
/update-profile |
Name, username, bio, role | β |
/student |
Student dashboard (5-tab) | β |
/teacher |
Teacher dashboard (5-tab) | β |
/chat |
Chat detail | β (UI only) |
/subscription |
Subscription plans | β (UI only) |
/payment |
Payment screen | β (UI only) |
/payment-success |
Payment success | β (UI only) |
/tutor/:id |
Tutor detail + offers | π² Not built |
/booking |
Booking flow | π² Not built |
/profile |
Own profile view/edit | π² Not built |
- Flutter SDK
^3.5.0 - Node.js
v18+& npm - Supabase project (PostgreSQL)
- Git
git clone https://github.com/hiyokun-d/study-app.git
cd study-appcd _server
npm install
cp .env.example .env # fill in DATABASE_URL, DIRECT_URL, JWT_SECRET, GOOGLE_CLIENT_ID
npx prisma generate
npx prisma migrate deploy
npm run start:dev # API at http://localhost:3000# From project root
flutter pub get
flutter run -d android # Android emulator (API URL is pre-configured)
flutter run -d chrome # Web
flutter run # First available deviceNote: The app is currently in mock mode (
AppConfig.useMock = true). Screens work without a running backend. To use the real API, setuseMock = falseinlib/core/constants/app_config.dart.
Android emulator: API URL is
http://10.0.2.2:3000β that's how Android emulators reachlocalhoston the host machine.
/login β AuthService.login() β AuthState.setFromResponse() β navigate to /student or /teacher
/register β AuthService.register() β AuthState.setFromResponse() β navigate to /update-profile
/update-profile β UserApiService.updateProfile() β AuthState.role = result β navigate to dashboard
- Add method to
UserApiService(or create a new service) - Check
AuthState.instance.isLoggedInfor protected calls - Pass
AuthState.instance.authHeadersfor JWT - Return a result object β never throw
- Handle
result.success/result.errorMessagein the widget
- Add method to the service (
user.service.tsor create new module) - Add route to the controller with optional
@UseGuards(AuthGuard('jwt')) - Write tests (service: mock Prisma; controller: mock service)
- Run
npm test
See docs.md for complete step-by-step guides.
cd _server
npm run test # all unit tests
npm run test:watch # watch mode
npm run test:cov # with coverage
npm run test:e2e # end-to-endflutter testNever push directly to main. All changes go through Feature Branch + Pull Request.
| Prefix | When |
|---|---|
feat/ |
New feature |
fix/ |
Bug fix |
api/ |
Backend API work |
docs/ |
Documentation |
refactor/ |
Cleanup |
feat: add tutor detail screen
fix: resolve login crash on empty password
api: add booking module with create endpoint
docs: update API reference for /user/tutor/:id
- Push branch:
git push origin feat/your-feature - Open PR on GitHub
- Describe what and why
- Wait for review β address feedback
- Squash-merge into
main
| File | Contents |
|---|---|
README.md |
This file β app overview, structure, progress |
_server/README.md |
API server documentation β endpoints, architecture, tests |
docs.md |
Full developer reference β every pattern, how-to guide, troubleshooting |
Under development. Not licensed for public distribution. Contact the repository owner for licensing inquiries.
