Last updated: 2026-06-04
MAC Study is a mobile-first progressive web app for Monash Association of Coding students to track study time, study with friends, and compete in lightweight group leaderboards.
For the MVP, MAC Study is scoped to the MAC community. The app can scale later to broader Monash or public study groups, but the first version should feel like a MAC-built space for MAC members.
The core experience is simple:
- A user opens MAC Study.
- They choose a subject, such as
FIT3159orFIT3077. - If they want the session to count toward a group leaderboard, they start from a group or select a group context.
- They tap Start Study.
- The session keeps counting even if the app is closed, the phone is locked, or the browser is suspended.
- When they return and tap Stop, the app logs the session under that subject and, if selected, that group.
The app should feel like a native mobile app when installed to the home screen, while staying web-first so it can be built from Windows and used by both iPhone and Android users.
The visual identity should be dark, sharp, and club-branded:
:root {
--color-background: #252525;
--color-mac-yellow: #FFE330;
}Recommended supporting colors:
:root {
--color-surface: #303030;
--color-surface-raised: #3A3A3A;
--color-border: #484848;
--color-text: #F7F7F2;
--color-text-muted: #B8B8B0;
--color-success: #42D392;
--color-danger: #FF6B6B;
--color-info: #6CB6FF;
}Use yellow as the main accent for primary actions, active timers, ranks, progress rings, and key highlights. Avoid making every element yellow; the app should read as black/charcoal with confident yellow accents.
- Framework: Next.js App Router
- Language: TypeScript
- UI: React
- Styling: Tailwind CSS
- Component base: shadcn/ui or Radix UI primitives with custom MAC styling
- Icons: lucide-react
- Database: Supabase Postgres
- Auth: Supabase Auth
- Realtime: Supabase Realtime
- Push notifications: Web Push with VAPID keys and a service worker
- Hosting: Vercel for the Next.js app
- Backend logic: Next.js Server Actions and/or Route Handlers
- Validation: Zod
- Dates: date-fns or Day.js
- Charts: Recharts or Tremor-style custom chart components
- Testing: Vitest for unit tests, Playwright for end-to-end PWA/user-flow tests
Supabase is the best fit for this app because MAC Study needs relational data, auth, permissions, group membership rules, realtime updates, and eventually chat. Supabase gives you a hosted Postgres database, Auth, Realtime database changes, and Row Level Security in one platform.
For the MVP, use Supabase generated TypeScript types and SQL migrations. You do not need Prisma at the start. Add Drizzle or Prisma later only if server-side query complexity grows.
Use standard Web Push first. It works with service workers, VAPID keys, and browser push services. For this PWA, that is enough for nudges, reminders, and active-session check-ins.
Firebase Cloud Messaging can be considered later if the app expands into native Android or broader notification tooling, but it adds an extra platform dependency that is not necessary for the first version.
- The timer must not depend on JavaScript running continuously in the background.
- On Start Study, store
started_atin the database. - On Stop Study, store
ended_at. - Calculate elapsed time from timestamps.
- On iPhone, push notifications require the app to be added to the Home Screen and notification permission to be granted.
- Web Push notifications can appear on the lock screen and lead users back into the PWA.
- A live-updating lock-screen timer with a reliable Stop control is not available to a PWA on iOS. That belongs in a future native app using iOS Live Activities.
- A PWA cannot detect that the user opened Instagram, TikTok, Messages, or other native apps.
Primary users:
- MAC Monash Association of Coding members
- MAC members studying Monash computing/software engineering subjects
- Study groups preparing for assignments, exams, and weekly labs
Secondary users:
- Future Monash students outside MAC
- Future friends outside Monash who want lightweight group study tracking
MAC Study should start as MAC-only. The implementation can still use standard Google sign-in or email magic links, but the product should include an access gate:
- allowlist approved emails, or
- require an invite code/link from an existing MAC group/admin, or
- require a Monash/MAC verification step later.
Decision: start with Google sign-in and email magic links, then enforce MAC-only access through invite links/admin approval. This keeps onboarding easy, covers users who do not want to use Google, and avoids password reset/support work during the MVP.
- Make starting a study session feel frictionless.
- Let users see subject-level study time per day.
- Let groups compete through leaderboards and rankings.
- Make the app social through group chat, active status, and nudges.
- Keep the app web-first and installable on iPhone and Android.
- Encourage healthy, honest study habits instead of unhealthy leaderboard grinding.
- Detecting whether a user opened Instagram or another distracting native app.
- Reading phone-wide Screen Time or Digital Wellbeing data.
- Blocking apps.
- Native iOS or Android apps.
- Live-updating lock-screen timer UI or native lock-screen Stop controls.
- Complex AI productivity coaching.
- Full Monash timetable integration.
- Payment or subscriptions.
- As a user, I can start a study timer for a subject.
- As a user, I can optionally start a timer inside a group so the time counts toward that group's leaderboard.
- As a user, I can leave the app and return later without losing timer progress.
- As a user, I can stop the timer and have the time logged under the selected subject.
- As a user, I can see today's time per subject and total time across all subjects.
- As a user, I can edit or delete a mistaken session.
- As a user, I can see whether I currently have an active session.
Example:
FIT3159: 00:30:00FIT3077: 00:50:00- Total: 01:20:00
- As a user, I can create a subject with a code and optional name.
- As a user, I can choose a subject before starting a timer.
- As a user, I can view daily, weekly, and all-time totals per subject.
- As a user, I can archive old subjects from previous semesters.
- As a user, I can create a custom group.
- As a user, I can invite friends via a join code or link.
- As a group member, I can see who is currently studying.
- As a group member, I can view a group leaderboard for sessions started inside that group.
- As a group admin, I can rename the group, remove members, and manage invite links.
- As a group admin, I can enable or disable nudges for the group.
- As a group member, I can see daily rankings by total study time.
- As a group member, I can see weekly rankings by total study time.
- As a group member, I can see subject-specific rankings.
- As a group member, I only see sessions that were started inside that group counted on that group's leaderboard.
- As a user, I can see my rank, total time, and change from yesterday/last week.
- As a group member, I can send messages in a group chat.
- As a group member, I can see recent chat history.
- As a group member, I can receive chat updates in realtime while the app is open.
- As a group admin, I can delete inappropriate messages.
- As a group member, I can tap another member and press Nudge.
- The recipient receives a push notification like:
{Sender} woke you up. - Nudges should have cooldowns to prevent spam.
- Users should be able to mute nudges from a group or a specific person.
- Account creation and login
- MAC-first access gate using approved sign-in and/or invite flow
- Profile setup
- Subject creation
- Start/stop study timer by subject
- Start/stop study timer inside a selected group
- Active session persistence using timestamps
- Daily subject totals
- Daily total study time
- Custom groups
- Invite links / join codes
- Group daily leaderboard
- Basic active-now status
- PWA manifest and installable app shell
- Responsive mobile-first UI
- Group chat
- Weekly leaderboard
- Subject-specific group leaderboard
- Web Push notification setup
- Nudge feature
- Nudge cooldowns and mute controls
- Session editing
- Streaks
- Daily/weekly goals
- Pomodoro mode
- Study rooms / timed sprints
- Session notes
- Weekly recap
- Profile badges
- Exam countdowns
- Subject color customization
- Group roles and moderation tools
- Offline start/stop queue with later sync
- Native iOS app with Screen Time APIs
- Native Android app with usage stats permission
- Native iOS Live Activity for a lock-screen/Dynamic Island study timer
- Optional distraction detection
- Optional app blocking/focus mode
- Home screen widgets
The app should not rely on a background timer. Instead, it should persist timestamps.
When a user starts studying:
session.status = active
session.started_at = now()
session.ended_at = nullWhen a user stops studying:
session.status = completed
session.ended_at = now()
duration_seconds = ended_at - started_atWhen showing the active timer in the UI:
elapsed = current_time - started_atThis works even if:
- the app is minimized
- the browser tab is suspended
- the phone is locked
- the user closes the app
- the user opens the app from another device
For the MVP, a group leaderboard only counts sessions explicitly started inside that group. A normal personal session should still count toward the user's personal totals, but it should not automatically count toward every group the user belongs to.
When a user starts a session from a group page:
session.group_id = selected_group_idWhen a user starts a session from the general timer page without a group:
session.group_id = nullThis avoids confusing cases where one study session appears on multiple group leaderboards at once.
PWA MVP behavior:
- The app can send lock-screen push notifications, such as
Still studying FIT3159?. - Tapping the notification should open MAC Study directly to the active session.
- The app can show an in-app active timer after the user opens it again.
Not available in the PWA MVP:
- A continuously updating lock-screen timer.
- A reliable Stop Study button directly on the iOS lock screen.
- Dynamic Island timer UI.
Future native behavior:
- A native iOS app could use Live Activities to show the active study timer on the Lock Screen and Dynamic Island.
- A native Android app could offer a persistent/ongoing notification with richer timer controls.
Problem: users may forget to stop a timer and accidentally log 12 hours.
Recommended lightweight rules:
- After 3 hours, optionally send a push notification:
Still studying FIT3159? - After 6 hours, mark the session as
needs_confirmation. - When the user returns, ask them to confirm or trim the session.
- Group leaderboards can visually flag unconfirmed sessions.
Do not silently delete long sessions. Let users correct them. Forgotten timers are not a major MVP blocker, but this protection prevents obviously broken leaderboard entries.
For MVP, each user should only have one active session at a time. If they start a new subject while another timer is active, ask whether to stop the current timer and start a new one.
Database-level protection:
create unique index one_active_session_per_user
on study_sessions (user_id)
where ended_at is null and deleted_at is null;Stores user-facing profile data.
id uuid primary key references auth.users(id)
display_name text
username text unique
avatar_url text
course text
access_status text -- pending, active, blocked
access_granted_at timestamptz null
access_granted_by uuid references profiles(id) null
access_granted_source text null
created_at timestamptz
updated_at timestamptzInvite codes for MAC-only access.
id uuid primary key
code text unique
note text
created_by uuid references profiles(id) null
max_uses integer null
uses_count integer default 0
expires_at timestamptz null
revoked_at timestamptz null
created_at timestamptzTracks which user redeemed which invite.
invite_id uuid references access_invites(id)
user_id uuid references profiles(id)
redeemed_at timestamptz
primary key (invite_id, user_id)User-created subjects.
id uuid primary key
user_id uuid references profiles(id)
code text
name text
color text
archived_at timestamptz null
created_at timestamptzSuggested rule: code is required, name is optional.
Custom study groups.
id uuid primary key
name text
description text
owner_id uuid references profiles(id)
invite_code text unique
visibility text -- invite_only, public
nudges_enabled boolean default true
nudge_cooldown_seconds integer default 600
created_at timestamptz
updated_at timestamptzMembership and roles.
group_id uuid references groups(id)
user_id uuid references profiles(id)
role text -- owner, admin, member
status text -- active, removed, banned
joined_at timestamptz
last_seen_at timestamptz
primary key (group_id, user_id)Study session records.
id uuid primary key
user_id uuid references profiles(id)
subject_id uuid references subjects(id)
group_id uuid references groups(id) null
started_at timestamptz
ended_at timestamptz null
status text -- active, completed, needs_confirmation, voided
source text -- timer, manual_adjustment
note text null
deleted_at timestamptz null
created_at timestamptz
updated_at timestamptzDuration should usually be computed from started_at and ended_at, not trusted from the client.
id uuid primary key
group_id uuid references groups(id)
user_id uuid references profiles(id)
body text
deleted_at timestamptz null
created_at timestamptzid uuid primary key
group_id uuid references groups(id)
sender_id uuid references profiles(id)
recipient_id uuid references profiles(id)
message text
created_at timestamptz
delivered_at timestamptz null
read_at timestamptz nullPer-user notification and nudge settings for a group.
user_id uuid references profiles(id)
group_id uuid references groups(id)
nudges_muted boolean default false
chat_muted boolean default false
created_at timestamptz
updated_at timestamptz
primary key (user_id, group_id)Lets a user mute nudges from a specific person.
user_id uuid references profiles(id)
muted_user_id uuid references profiles(id)
group_id uuid references groups(id) null
created_at timestamptz
primary key (user_id, muted_user_id, group_id)id uuid primary key
user_id uuid references profiles(id)
endpoint text unique
p256dh text
auth text
user_agent text
created_at timestamptz
last_seen_at timestamptz
revoked_at timestamptz nullid uuid primary key
user_id uuid references profiles(id)
subject_id uuid references subjects(id) null
period text -- daily, weekly
target_seconds integer
created_at timestamptz
updated_at timestamptzFor each user, group completed sessions by local date and subject:
user_id
local_date
subject_id
total_secondsuser_id
local_date
total_secondsgroup_id
local_date
user_id
display_name
total_seconds
rankImportant decision: group leaderboards only count sessions explicitly started "inside" that group. This requires study_sessions.group_id to match the leaderboard group.
Purpose: start studying fast.
Content:
- Active timer card
- Subject selector
- Optional group selector or visible current group context
- Start/Stop button
- Today's subject totals
- Today's total
- Current streak or goal progress
Primary action:
- Start Study / Stop Study
Purpose: manage and inspect subject-level time.
Content:
- Subject list
- Today, week, and all-time totals
- Subject detail page
- Session history for subject
Purpose: social competition and accountability.
Content:
- Group list
- Create group
- Join group by code
- Active members
- Group leaderboard
- Group chat
- Member profile sheet with Nudge button
- Group setting to enable/disable nudges
Purpose: ranking and motivation.
Filters:
- Group
- Daily / weekly / all-time
- All subjects / specific subject
Purpose: identity and settings.
Content:
- Display name
- Username
- Avatar
- Total study time
- Subjects
- Notification settings
- Nudge mute settings
- Privacy settings
- User opens a group.
- User taps a member.
- Member sheet opens.
- User taps Nudge.
- System creates a
nudgesrecord. - Server sends Web Push notification to recipient.
- Recipient sees:
{Sender} woke you up.
- Group admins can enable or disable nudges in group settings.
- If nudges are disabled for the group, no member can send a nudge in that group.
- Group admins can configure a simple cooldown, defaulting to 10 minutes per sender-recipient pair.
- A user can mute nudges from a group.
- A user can mute nudges from an individual person.
- A user cannot nudge themselves.
- Nudges should be logged so abuse can be reviewed by group admins.
Default:
{Sender} woke you upAlternatives:
{Sender} says get back to it
{Sender} nudged you to study
{Sender} is calling you back to MAC StudyRecommendation: keep the default as {Sender} woke you up because it has personality and matches your original idea.
- Text-only messages
- Realtime updates
- Message timestamps
- Delete own message
- Admin delete any message
- No attachments in MVP
Group chat increases moderation requirements. For a student club app, this is still manageable, but you should include:
- report message
- admin deletion
- member removal
- basic profanity/spam protection later
If implementation time is tight, ship group leaderboards first and add chat in P1.
- User can choose display name and avatar.
- User can leave a group.
- User can mute nudges.
- User can disable push notifications.
- User can edit/delete mistaken sessions.
Recommended defaults:
- Group members can see each other's total study time and active studying status.
- Group members do not need to see detailed session notes unless the user opts in.
- Subject-level leaderboard visibility should be configurable by group.
Potential problem: leaderboards can encourage unhealthy studying or fake sessions.
Mitigations:
- Add daily goals, not just rankings.
- Flag unusually long unconfirmed sessions.
- Celebrate consistency, not only total hours.
- Consider "focus streak" badges and "goal met" states instead of only top-rank status.
This is not feasible in a PWA because the browser cannot know what native app the user opened.
Future native path:
- iOS: use Screen Time APIs such as Family Controls and Device Activity, with Apple entitlements.
- Android: use UsageStatsManager with user-granted usage access permission.
Recommended product framing:
- MVP: honor-system study timer with long-session confirmation.
- Later native extension: optional distraction detection/focus enforcement.
- Percentage of users who start their first session within 2 minutes of signup.
- Percentage of users who create or join a group.
- Daily active users.
- Study sessions per user per week.
- Average number of active group members per day.
- Nudge sends and nudge opens.
- Day 1, Day 7, and Day 30 retention.
- Weekly active groups.
- Users who log study time at least 3 days per week.
- Percentage of sessions marked
needs_confirmation. - Number of edited/deleted sessions.
- Nudge mute rate.
- Chat report rate.
- Create Next.js app with TypeScript and Tailwind.
- Add MAC Study theme tokens.
- Set up Supabase project.
- Add Supabase Auth.
- Create profiles table.
- Add MAC-only invite/admin access gate.
- Add PWA manifest.
- Create subjects table.
- Create study_sessions table.
- Build Start/Stop timer flow.
- Support optional
group_idon timer sessions. - Enforce one active session per user.
- Build today's subject totals.
- Build session history.
- Create groups and group_members tables.
- Build create/join group flow.
- Build group dashboard.
- Build daily group leaderboard from sessions where
study_sessions.group_id = group.id. - Add active-now status.
- Add service worker.
- Add push subscription flow.
- Store push subscriptions.
- Send test notification.
- Add nudge records.
- Send nudge notifications.
- Add group chat.
- Add weekly leaderboard.
- Add session edit/delete.
- Add nudge cooldowns/muting.
- Add profile and notification settings.
/ landing or redirect
/app main timer dashboard
/app/subjects subjects list
/app/subjects/[subjectId] subject detail
/app/groups groups list
/app/groups/[groupId] group dashboard
/app/groups/[groupId]/chat group chat
/app/leaderboards leaderboard explorer
/app/profile profile/settings
/auth/login login
/auth/callback Supabase auth callbackapp/
(auth)/
(app)/
api/
manifest.ts
components/
timer/
groups/
leaderboard/
chat/
nudges/
ui/
lib/
supabase/
auth/
timer/
notifications/
validation/
db/
migrations/
types.ts
public/
sw.js
icons/- MAC Study is MAC-only for the MVP.
- Login should support Google sign-in and email magic links.
- Access is still controlled through invite/admin flow rather than open public signup.
- Group leaderboards count only sessions explicitly started inside that group.
- Nudges can be controlled through group settings.
- Users can mute nudges for a group or mute nudges from specific people.
- Forgotten timers are a minor concern, handled with lightweight confirmation rather than heavy anti-cheat.
These decisions still shape the MVP:
- Should subjects be user-created only, or should there be a shared Monash subject catalogue?
- Should chat be part of MVP, or should the first release focus on timer + groups + leaderboards + nudges?
- Should nudges only be sent to inactive users, or can you nudge anyone in a group?
- Should the tone be playful and club-like, or more serious and productivity-focused?
- Should weekly leaderboards reset Monday morning in Australia/Sydney time?
- Should users be able to make their study totals private in some groups?
Recommended setup:
- Keep the GitHub repository private while building MAC Study.
- Do not choose MIT, Apache-2.0, GPL, AGPL, BSD, ISC, or any other open-source license if you do not want others copying or reusing the product.
- Use no open-source license, or add a custom proprietary
LICENSE.mdthat says all rights are reserved. - Add a short notice to
README.mdmaking the intent obvious.
Recommended LICENSE.md text:
Copyright (c) 2026 MAC Study contributors.
All rights reserved.
This source code and associated materials are proprietary and confidential.
No permission is granted to copy, modify, distribute, sublicense, publish,
deploy, or use this software or any substantial portion of it without prior
written permission from the copyright holder.Recommended README.md notice:
## License
MAC Study is proprietary software. All rights reserved.
No part of this codebase may be copied, modified, distributed, or used without permission.Important notes:
- If a public GitHub repository has no license, default copyright law applies, so others do not receive permission to reproduce, distribute, or create derivative works. However, GitHub's terms allow other GitHub users to view and fork public repositories on GitHub.
- If multiple friends contribute code, decide early who owns the IP. Otherwise, each contributor may own copyright in their own contributions unless there is a written agreement.
- Third-party dependencies still have their own licenses. The app can be proprietary while using open-source packages, but dependency license obligations still need to be respected.
- Next.js official PWA guide: https://nextjs.org/docs/app/guides/progressive-web-apps
- Next.js manifest docs: https://nextjs.org/docs/app/api-reference/file-conventions/metadata/manifest
- Supabase docs: https://supabase.com/docs/
- Supabase Realtime docs: https://supabase.com/docs/guides/realtime
- Supabase Auth SSR docs: https://supabase.com/docs/guides/auth/server-side
- Supabase Row Level Security docs: https://supabase.com/docs/guides/database/postgres/row-level-security
- Firebase Cloud Messaging web docs, for optional future comparison: https://firebase.google.com/docs/cloud-messaging/web/get-started
- WebKit Web Push for iOS/iPadOS Home Screen web apps: https://webkit.org/blog/13878/web-push-for-web-apps-on-ios-and-ipados/
- MDN Notification actions docs: https://developer.mozilla.org/en-US/docs/Web/API/Notification/actions
- Apple Human Interface Guidelines for Live Activities: https://developer.apple.com/design/human-interface-guidelines/live-activities
- Apple ActivityKit Live Activities overview: https://developer.apple.com/documentation/ActivityKit/displaying-live-data-with-live-activities
- GitHub repository licensing docs: https://docs.github.com/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/licensing-a-repository