UniSync is a mobile application designed to simplify communication, collaboration, and resource sharing within a university environment. It enables students and faculty to connect through announcements, events, messaging, and shared resources in a single unified platform with full offline support.
Home Screen • Chat System • Events Dashboard
User Profile • Resources
Authentication
- Secure sign-up and login with university email validation (
.edu,.edu.bd,.ac.bd,.ac.uk,.ac.in) - Role-based access automatically assigned from institutional ID (Student / Faculty)
- Password reset via email
Announcements
- Faculty post categorised updates — Academic, Financial, General, Club
- Students view and bookmark announcements in real time
- Type-based filtering
Events
- Faculty create campus events with location, date, time, and category
- Students browse events on a calendar view and RSVP with one tap
- Attendee count updated atomically via database function
Chat
- One-to-one and group messaging with real-time delivery
- Online presence indicators and unread message counts
- Offline message queue — messages sent while offline are delivered automatically on reconnect
Resource Sharing
- Upload PDFs, DOCX, PPT, and image files (up to 10 MB)
- Browse resources filtered by department, semester, and type
- Download counter and 5-star rating system
Offline-First
- All content cached locally with Isar; app works fully without internet
- Write operations queued and replayed automatically when connectivity returns
- Optimistic UI, actions appear instantly without waiting for the server
Push Notifications
- Instant alerts for new announcements, events, chat messages, and resources
- Powered by OneSignal + Firebase Cloud Messaging
| Layer | Technology |
|---|---|
| Framework | Flutter (Dart 3.2+) |
| Backend | Supabase- Postgres, Auth, Storage, Realtime, Edge Functions |
| Local Database | Isar (offline cache & pending-action queue) |
| State Management | Flutter Riverpod |
| Push Notifications | OneSignal + Firebase Cloud Messaging |
| Notifications Edge Function | Deno / TypeScript (Supabase Edge Function) |
| Role | Permissions |
|---|---|
| Student | View & bookmark announcements · Browse & RSVP events · Send & receive chat · Upload & download resources · Edit own profile |
| Faculty | All student permissions + Post announcements · Create events · Delete any resource |
Roles are assigned automatically at sign-up by a PostgreSQL trigger that reads the institutional ID format:
| ID Format | Role |
|---|---|
Starts with 3, 8 digits (e.g. 31234567) |
student |
Starts with 1, 8 digits (e.g. 11234567) |
faculty |
Clients cannot self-assign or escalate roles — this is enforced at the database level.
unisync/
├── lib/
│ ├── main.dart # App entry point
│ │ # Init order: dotenv → Firebase → Isar
│ │ # → ConnectivityService → Supabase
│ │ # → OneSignal → ProviderScope
│ │
│ ├── models/
│ │ ├── user_model.dart # AppUser
│ │ ├── announcement_model.dart # Announcement
│ │ ├── chat_model.dart # ChatRoom, ChatMessage
│ │ ├── event_model.dart # Event
│ │ ├── resource_model.dart # Resource
│ │ ├── isar_announcement.dart # Isar collection schema
│ │ ├── isar_chat.dart # Isar collection schema (room + message)
│ │ ├── isar_event.dart # Isar collection schema
│ │ ├── isar_resource.dart # Isar collection schema
│ │ ├── isar_pending_action.dart # Offline write queue schema
│ │ └── *.g.dart # Generated — do not edit manually
│ │
│ ├── services/
│ │ ├── auth_service.dart # signUp · signIn · signOut · getUser
│ │ ├── announcement_service.dart # getAnnouncements · postAnnouncement
│ │ │ # bookmarkToggle · deleteAnnouncement
│ │ ├── chat_service.dart # getRooms · getMessages · sendMessage
│ │ │ # createRoom · presence · unread
│ │ ├── event_service.dart # getEvents · createEvent · rsvpEvent
│ │ │ # deleteEvent
│ │ ├── resource_service.dart # getResources · uploadResource
│ │ │ # incrementDownloads · rateResource
│ │ │ # deleteResource
│ │ ├── profile_service.dart # uploadProfilePhoto · searchUsers
│ │ ├── notification_service.dart # initialize · uploadPendingToken
│ │ │ # send() [static]
│ │ ├── connectivity_service.dart # isOnline · isOffline
│ │ │ # onConnectionRestored callback
│ │ ├── offline_sync_service.dart # syncAll · pendingCount
│ │ ├── marking_service.dart # toggleResourceBookmark
│ │ │ # syncBookmarks
│ │ ├── local_database_service.dart # Isar open/close + all cache ops
│ │ └── supabase_client.dart # Supabase singleton (supabase getter)
│ │
│ ├── providers/
│ │ ├── auth_provider.dart # authStateProvider
│ │ │ # currentUserProvider (StateNotifier)
│ │ │ # authServiceProvider
│ │ ├── announcement_provider.dart # announcementServiceProvider
│ │ ├── chat_provider.dart # chatServiceProvider
│ │ ├── event_provider.dart # eventServiceProvider
│ │ ├── resource_provider.dart # resourceServiceProvider
│ │ ├── connectivity_provider.dart # connectivityServiceProvider
│ │ └── marking_provider.dart # markingServiceProvider
│ │
│ ├── screens/
│ │ ├── auth/
│ │ │ ├── login_screen.dart # Email + password · forgot password
│ │ │ └── signup_screen.dart # Pre-filled role + ID from onboarding
│ │ ├── onboarding/
│ │ │ └── onboarding_screen.dart # 3 feature slides → role/ID selection
│ │ │ # Validates ID regex before proceeding
│ │ ├── dashboard/
│ │ │ ├── main_dashboard.dart # IndexedStack · 5-tab bottom nav
│ │ │ │ # BackdropFilter frosted glass nav bar
│ │ │ ├── home_tab.dart # Announcement feed (home tab)
│ │ │ └── announcements_screen.dart # Full list + type filter chips
│ │ ├── chat/
│ │ │ ├── chat_list_screen.dart # Room list with unread badges
│ │ │ ├── chat_room_screen.dart # Message thread + send bar
│ │ │ └── new_chat_screen.dart # searchUsers → create DM or group
│ │ ├── events/
│ │ │ ├── events_list_screen.dart
│ │ │ ├── event_detail_screen.dart # RSVP toggle + live attendee count
│ │ │ └── event_creation_screen.dart # Faculty only
│ │ ├── resources/
│ │ │ ├── resources_screen.dart # Filter by department + type
│ │ │ ├── resource_detail_screen.dart # Download + star rating
│ │ │ └── resource_upload_screen.dart
│ │ └── profile/
│ │ ├── profile_screen.dart
│ │ └── edit_profile_screen.dart # Name · semester · avatar upload
│ │
│ ├── widgets/
│ │ └── shared_widgets.dart # Cards · shimmer loaders · empty states
│ │
│ └── theme/
│ └── app_theme.dart # AppTheme.primary · AppTheme.ink900 etc.
│ # Material 3 theme + AppBackground widget
│
├── supabase/
│ └── functions/
│ └── send-notification/
│ └── index.ts # Deno edge function — OneSignal dispatch
│
├── android/
│ └── app/
│ ├── google-services.json # Firebase — never commit real values
│ └── src/main/kotlin/.../MainActivity.kt
│
├── assets/
│ └── images/
│ ├── logo.png
│ ├── logo_bg.png
│ └── background.jpg
│
├── sql/
│ ├── SUPABASE_SETUP.sql # Full DB bootstrap — run once in SQL Editor
│ └── NOTIFICATIONS_SETUP.sql # Adds user_push_tokens table
│
├── .env.example # Copy to .env and fill in secrets
├── pubspec.yaml
└── build_run.ps1 # Windows build helper script
- Flutter SDK ≥ 3.2.0
- Android Studio / Android SDK
- A Supabase project
- A Firebase project (required for OneSignal on Android)
- A OneSignal account
git clone https://github.com/ZannatulRaian/UniSync-Mobile-App.git
cd unisync-
Open the Supabase SQL Editor and run the full contents of
SUPABASE_SETUP.sql(creates all tables, indexes, RLS policies, and RPC functions). -
Also run
NOTIFICATIONS_SETUP.sql(creates theuser_push_tokenstable). -
In the Supabase dashboard create two Storage buckets named
resourcesandavatars, both set to Public. -
Deploy the push notification Edge Function:
supabase functions deploy send-notification
-
In the Supabase dashboard go to Project Settings → Edge Functions and add:
Variable Where to find it ONESIGNAL_APP_IDOneSignal Dashboard → Settings → Keys & IDs ONESIGNAL_REST_API_KEYOneSignal Dashboard → Settings → Keys & IDs SUPABASE_URLSupabase → Project Settings → API SUPABASE_SERVICE_ROLE_KEYSupabase → Project Settings → API
- Go to the Firebase Console and open your project.
- Navigate to Project Settings → Your Apps → Android App.
- Download
google-services.jsonand place it at:android/app/google-services.json
cp .env.example .envEdit .env and fill in your values:
SUPABASE_URL=https://<your-project-id>.supabase.co
SUPABASE_ANON_KEY=eyJhbGci...
ONESIGNAL_APP_ID=<your-onesignal-app-id>Never commit
.envto version control. It is already listed in.gitignore.
flutter pub get
dart run build_runner build --delete-conflicting-outputs# Run on a connected Android device
flutter run
# Build a release APK
flutter build apk --releaseRelease APK location: build/app/outputs/apk/release/app-release.apk
Every service emits Isar-cached data instantly before touching the network. When a write is attempted offline (message, announcement, event, file upload):
- The operation is stored in an
IsarPendingActionqueue. - An optimistic local record (prefixed
pending_) appears in the UI immediately. OfflineSyncService.syncAll()replays all queued actions against Supabase the moment connectivity is restored.
Actions that fail after 5 retries are abandoned so they do not block the queue.
- All communication over HTTPS
- University email domain enforced at both sign-in and sign-up
- Roles assigned by a server-side PostgreSQL trigger — cannot be spoofed by clients
- Row-Level Security policies enforced on every database table
- Chat rooms accessible only to their members
- File storage access controlled via Supabase Storage policies
- Input validation on both client and database layers
google-services.json not found
ls android/app/google-services.json
# If missing: Firebase Console → Project Settings → Your Apps → Android → DownloadApp cannot connect to backend
Verify SUPABASE_URL and SUPABASE_ANON_KEY in .env match the values shown in Supabase → Project Settings → API.
Device not detected
flutter devices
# Enable USB Debugging on your Android phone under Developer OptionsIsar model errors after pulling new code
dart run build_runner clean
dart run build_runner build --delete-conflicting-outputs
flutter clean && flutter pub getOneSignal initialisation failed
Ensure Firebase is initialised before OneSignal in main.dart:
await Firebase.initializeApp();
await NotificationService.instance.initialize(appId);- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature - Commit your changes:
git commit -m 'Add your feature' - Push to the branch:
git push origin feature/your-feature - Open a Pull Request
This project is licensed for educational and academic purposes.





