The Problem I Set Out to Solve
As a Placement Representative for PSG Tech's MCA batch (2025-2027), I faced a coordination nightmare. Managing 123 students across multiple dimensions—attendance, LeetCode practice, announcements, and daily tasks—was becoming unsustainable.
The existing workflow relied on:
- WhatsApp groups flooded with messages (important updates got buried)
- Google Sheets that nobody updated consistently
- Manual follow-ups that consumed hours every week
I needed a centralized system that could handle real-time updates, enforce accountability, and scale without constant manual intervention.

Technical Architecture
Why Flutter + Supabase?
I chose this stack deliberately:
| Layer | Technology | Reasoning | |-------|------------|-----------| | Frontend | Flutter 3.27+ | Single codebase for Android & iOS, hot reload for rapid iteration | | Backend | Supabase | PostgreSQL with built-in auth, realtime subscriptions, and generous free tier | | State | Provider | Lightweight, battle-tested, easy to reason about |
Supabase was particularly appealing—I didn't want to manage infrastructure. Their Row-Level Security (RLS) meant I could enforce permissions at the database level, not just in the UI.
Project Structure
I organized the codebase using a feature-first approach:
lib/
├── features/
│ ├── attendance/
│ │ ├── data/
│ │ ├── domain/
│ │ └── presentation/
│ ├── tasks/
│ ├── announcements/
│ └── leaderboard/
├── core/
│ ├── services/
│ └── repositories/
└── shared/
├── widgets/
└── utils/
This structure keeps each feature self-contained. Adding new modules doesn't require touching existing code—a decision that paid off when I added the LeetCode integration mid-development.
Role-Based Access Control
One of the trickier aspects was designing a permission system that reflected our actual organizational hierarchy:
| Role | What They Can Do | |------|-----------------| | Student | View their own attendance, tasks, announcements, and LeetCode stats | | Team Leader | Mark attendance for their assigned team (5-6 students each) | | Coordinator | Access reports and assist with administrative tasks | | Placement Rep | Full access—create announcements, manage tasks, view all data |

Dual-Layer Security
I enforce permissions at two levels. First, the UI adapts based on the user's role:
// UI-level permission check
Widget build(BuildContext context) {
final user = context.watch<UserProvider>().currentUser;
return switch (user.role) {
UserRole.student => StudentDashboard(),
UserRole.teamLeader => TeamLeaderDashboard(),
UserRole.coordinator => CoordinatorDashboard(),
UserRole.placementRep => AdminDashboard(),
};
}
Second, Supabase RLS policies ensure that even if someone bypasses the UI, they can't access unauthorized data:
-- Team leaders can only mark attendance for their own team
CREATE POLICY "team_leader_attendance" ON attendance
FOR INSERT
WITH CHECK (
auth.uid() IN (
SELECT leader_id FROM teams WHERE id = team_id
)
);
This dual-layer approach gives me confidence that the system is secure, even if the client is compromised.
Core Features
Attendance Tracking
This was the primary pain point. Previously, team leaders would message attendance counts in WhatsApp—no accountability, no history, no way to verify.
Now, team leaders mark attendance directly in the app:

What I built:
- Single-tap marking for each team member
- Real-time sync via Supabase Realtime—updates appear instantly on all devices
- Historical view with date-range filtering
- Summary cards showing present/absent/total at a glance
The UNIQUE(student_id, date) constraint in PostgreSQL prevents duplicate entries, eliminating the "I already marked!" confusion we had before.
Task Management
Every day, I assign two types of tasks:
- LeetCode problems with direct links
- Core CS topics (networking, OS, DBMS concepts)

I can filter by date range, bulk upload tasks for the week, and students see exactly what they need to complete each day. No more scrolling through WhatsApp history.
Announcements System
Placement drives, deadlines, schedule changes—these need to reach everyone immediately.

Key design decisions:
- Auto-expiry for time-sensitive announcements (no stale notifications cluttering the feed)
- Priority levels to filter by importance
- Push notifications via Firebase Cloud Messaging for urgent updates
Analytics Dashboard
As a placement rep, I need visibility into batch-wide progress:

Available metrics:
- Total students and scheduled classes
- Daily and average attendance rates
- Team-wise breakdown for identifying struggling groups
- Export options (CSV download for detailed analysis)
LeetCode Integration
Consistent practice is crucial for placements. I integrated LeetCode stats to create friendly competition:
What's displayed:
- Problems solved (Easy/Medium/Hard breakdown)
- Global ranking
- Current streak
class LeetCodeService {
Future<LeetCodeStats> fetchStats(String username) async {
final response = await http.get(
Uri.parse('https://leetcode-stats-api.herokuapp.com/$username'),
);
if (response.statusCode == 200) {
return LeetCodeStats.fromJson(jsonDecode(response.body));
}
throw LeetCodeFetchException('Failed to fetch stats');
}
}
Caching strategy: I cache stats locally and refresh every 6 hours. This avoids rate limiting while keeping the leaderboard reasonably current. Users can also manually refresh if they want immediate updates after solving problems.
Authentication
I implemented OTP-based email verification through Supabase Auth:

The flow:
- User enters their registered email (must exist in our student whitelist)
- Supabase sends a one-time password to their inbox
- User enters the OTP and sets their password
- Profile data auto-populates from the whitelist
Why this approach?
- Only whitelisted students can register—no random signups
- Email verification confirms identity without complex KYC
- Simpler than managing password resets
Design Language
I went with a dark theme featuring orange accents—easy on the eyes during late-night study sessions:
| Element | Value |
|---------|-------|
| Background | #121212 |
| Surface | #1E1E1E |
| Primary | #FF9800 (Orange) |
| Success | #4CAF50 |
| Error | #F44336 |
Custom components include stat cards with colored accents, smooth toggle animations, and a bottom navigation bar with clear active states.
Installation
Android
- Download the latest APK from GitHub Releases
- Before installing, disable Google Play Protect:
- Open Play Store → Tap your profile icon → Play Protect → Settings (gear icon)
- Turn off Scan apps with Play Protect
- Open the downloaded APK and tap Install
- After installation, you can re-enable Play Protect if desired
Why disable Play Protect? Since the app isn't distributed through the Play Store, Google flags it as "unknown." This is a standard requirement for sideloaded apps.
iOS
iOS installation guide coming soon. The app will be distributed via TestFlight or AltStore.
What I Learned
Things That Worked
- Supabase Realtime was a game-changer. Attendance updates appear instantly across all devices—no manual refresh needed.
- Role simulation in dev tools (visible in the profile screen) let me test all four permission levels without logging in/out repeatedly.
- Feature-first architecture made it trivial to add the LeetCode module without touching attendance or tasks code.
Challenges I Faced
| Problem | How I Solved It | |---------|-----------------| | LeetCode API rate limits | 6-hour local caching with manual refresh option | | Offline attendance marking | Local queue using Hive, syncs when connection returns | | Play Store restrictions | GitHub Releases + clear sideloading instructions |
What's Next
- Push notification scheduling for deadline reminders
- Offline-first architecture with full local persistence
- Placement drive calendar with company-wise tracking
- AI-powered LeetCode recommendations based on weak areas
Current Status
| Version | Released | Notes | |---------|----------|-------| | 1.0.7 | Jan 2026 | Latest stable release | | 1.0.5 | Jan 28, 2026 | OTP auth improvements, LeetCode integration, Android 12+ compatibility |
Links
- Source Code: github.com/brittytino/psgmx-flutter
- Download APK: Latest Release
- Report Issues: GitHub Issues
Built for PSG Tech MCA Batch 2025-2027 • Flutter + Supabase
