IlmLoop is a cross-platform peer-learning community for discovering people who can teach a skill, sharing what you know, and organizing learning sessions. The Flutter client brings authentication, profiles, a searchable skill marketplace, conversations, scheduling, and an in-app notification inbox into one experience backed by Firebase.
IlmLoop requires a Firebase project supplied at build time. This repository contains no private Firebase credentials or user data. Use your own Firebase project and restrict its client keys before deployment.
- Email/password authentication, password recovery, and an onboarding flow
- Google sign-in entry points (requires a separately configured OAuth client)
- Skill offers and learning requests with search and category filters
- Firestore-backed conversations and messages
- Session requests, calendar-based scheduling, and status updates
- User profiles and skill management, including display of existing rating summaries and reviews
- In-app notification inbox, plus optional Firebase Cloud Messaging device-registration scaffolding
- Responsive Flutter targets for Android, iOS, macOS, Windows, and web
Profile-photo upload and rating submission components remain in the codebase as legacy scaffolding, but they are not currently exposed through the primary application flow.
- Flutter and Dart
- Firebase Authentication
- Cloud Firestore and Firebase Storage
- Firebase Cloud Messaging client scaffolding (optional)
- Shared Preferences for local onboarding state
lib/
├── main.dart # App bootstrap, Firebase startup, and routes
├── *_screen.dart # Feature-focused UI screens
├── services/ # Firestore, search, presence, media, notifications
├── theme/ # Shared visual design tokens
└── widgets/ # Reusable UI components
firestore.rules # Firestore authorization rules
firestore.indexes.json # Composite index definitions
database.rules.json # Realtime presence authorization rules
storage.rules # Profile-photo authorization and size rules
firebase.json # Firestore and web-hosting deployment config
web/icons/ilmloop-icon.svg # Editable source for the platform app icons
- Flutter 3.29.0 (stable) or a compatible SDK with Dart 3.7+
- Node.js 22 and npm for the Firebase Emulator Suite tests
- Java 21 for the Firebase emulators
- A Firebase project
- Firebase CLI for rules, indexes, or Hosting deployment
- FlutterFire CLI if you want help registering platform applications
Clone the project and install packages:
git clone https://github.com/muhammadzain-byte/IlmLoop.git
cd IlmLoop
flutter pub get-
In the Firebase console, create or select a project.
-
Enable Email/Password authentication. Enable Google authentication only if you also complete its platform OAuth setup.
-
Create Cloud Firestore, Firebase Storage, and Realtime Database, then enable Cloud Messaging where supported.
-
Copy the configuration template without committing the local copy:
cp firebase.defines.example.json firebase.defines.json
-
Replace the placeholders in
firebase.defines.jsonwith values from Firebase console → Project settings → Your apps.
The four required compile-time values are:
ILMLOOP_FIREBASE_API_KEYILMLOOP_FIREBASE_APP_IDILMLOOP_FIREBASE_MESSAGING_SENDER_IDILMLOOP_FIREBASE_PROJECT_ID
The template also includes optional values for auth domain, Realtime Database, Storage, Analytics measurement, OAuth client IDs, the Apple bundle ID, and the public web-push VAPID key. The default iOS/macOS bundle ID is com.muhammadzain.ilmloop. Set ILMLOOP_GOOGLE_CLIENT_ID for web and Apple targets, and ILMLOOP_GOOGLE_SERVER_CLIENT_ID for Android when enabling Google sign-in. Set ILMLOOP_FIREBASE_VAPID_KEY to the public key from Firebase console → Project settings → Cloud Messaging → Web Push certificates when enabling browser push.
Firebase assigns a different app ID to each registered platform. A single firebase.defines.json is convenient for local web development; for multi-platform releases, keep ignored files such as firebase.defines.web.json and firebase.defines.android.json, then pass the file matching the target you are building.
Run the app with your local configuration:
flutter run -d chrome --dart-define-from-file=firebase.defines.jsonWithout the required values, IlmLoop displays a safe setup screen instead of connecting to another Firebase project.
The app initializes Firebase from Dart defines and does not apply the Google Services Gradle plugin, so an Android google-services.json file is not used for core startup. Google sign-in is a separate integration: configure the google_sign_in client for each target, including authorized domains on web and matching Android SHA fingerprints or Apple URL schemes. No OAuth client configuration is bundled in this repository.
Native releases also require platform-owned configuration that cannot be committed generically:
- iOS: register the matching bundle ID, configure signing and provisioning, and add the provider URL scheme for Google sign-in. The photo-library purpose string is included for the legacy image picker. Push delivery additionally requires the Push Notifications capability, Background Modes for remote notifications, and an APNs key or certificate linked in Firebase.
- macOS: register the matching bundle ID and configure signing and provisioning. The sandbox permits outbound networking and user-selected read-only files. Google sign-in may require a Keychain Sharing access group tied to your Apple development team; no team-specific access group is checked in.
- Android: register the application ID and required SHA fingerprints for enabled OAuth providers. Distribution builds must use your own release keystore as described below.
- Web: configure authorized domains and the OAuth client. Browser push requires a Web Push certificate/VAPID key and a Firebase messaging service worker.
Release builds never fall back to Android's debug signing key. Generate and securely back up an upload keystore, then copy the ignored properties template:
keytool -genkeypair -v -keystore android/app/ilmloop-upload-keystore.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias upload
cp android/key.properties.example android/key.propertiesReplace every placeholder in android/key.properties. The storeFile path is resolved relative to the android directory. Both the local properties file and keystore formats are ignored by Git. Debug builds continue using Gradle's normal debug signing behavior; any release task fails with a clear error until all four release-signing properties are provided and the referenced keystore exists.
The Firestore-backed notification inbox works independently of push delivery. The FCM code currently provides client-side permission requests, auth-aware device-token registration, and token-refresh handling; it is not an end-to-end push system. Browser registration is skipped safely when ILMLOOP_FIREBASE_VAPID_KEY is absent. Production push still requires platform credentials and capabilities (including APNs on Apple platforms and VAPID/service-worker setup on web) and a trusted backend such as Cloud Functions or the Firebase Admin SDK to send notifications. Review token storage rules and consent requirements before enabling it.
Linux runner files are retained, but Firebase startup is currently supported only on Android, iOS, macOS, Windows, and web.
The Flutter client and Firebase rules implement one coordinated schema. Treat changes to either side as a versioned data-contract change.
users/{uid}is an authenticated-readable profile document. It may contain profile and presence fields such asname,bio, skill lists,photoURL,isOnline, and timestamps; it must not contain email addresses, messaging tokens, cached rating aggregates, or arbitrary private fields.users/{uid}/private/accountstores the owner'semailandupdatedAt.users/{uid}/private/messagingstores the owner'sfcmTokenandlastTokenUpdate. Client rules restrict both documents to their owner; a trusted notification backend can use the Admin SDK when appropriate.- Skill documents identify their author with
userIdand display-safeuserNameonly—neveruserEmail. Each exchange has one 20-characterexchangeIdand the deterministic document IDs<exchangeId>_offerand<exchangeId>_request. Creation, pair-consistent edits, and deletion are atomic batch operations so neither half can exist independently. - Chat IDs are canonical: the two participant UIDs are sorted and joined as
<firstUid>_<secondUid>. Chats are created once through a transaction; participant identity and creation metadata remain immutable afterward. Messages must reference the opposite participant and cannot be edited or deleted. - A new session must be in the future and reference an existing offer. Its provider and skill title must match that offer, while the authenticated requester must be the other participant. Only permitted participant-driven status transitions are accepted.
- A review can be written only for a confirmed referenced session by one participant about the other. Its deterministic ID is
<sessionId>_<reviewerUid>, which permits at most one review from each reviewer for that session; reviews are immutable after creation. - Notification writes are relationship-bound to their referenced chat, session, review, or owned skill. The in-app inbox is distinct from the optional FCM delivery scaffolding described above.
New Firebase projects initialized by the current client need no data migration. Existing IlmLoop deployments using older data schemas must be audited and migrated before these strict rules are deployed. The rules do not transform existing data automatically, and incompatible documents can become uneditable after rollout.
Back up an existing project and use trusted Admin SDK or equivalent administrative tooling to complete the migration before switching rules:
- Remove public
email,fcmToken, andaverageRatingfields fromusers/{uid}. Move email and token data into the exact private documents described above; derive rating summaries from the validated review documents instead of migratingaverageRating. - Rename a retained legacy
photoUrlfield to the supportedphotoURLspelling, or remove it if profile photos are not enabled. - Rewrite legacy skill records that contain
userEmail, lackexchangeId, use arbitrary document IDs, or exist as single offer/request documents. Create complete deterministic offer/request pairs in one atomic operation. - Audit older chats, sessions, reviews, and notifications against the current referenced-document and exact-key requirements before allowing writes.
- Validate the migrated dataset in a staging project, then deploy the compatible client and rules as one coordinated release.
Install the pinned rules-test dependencies:
npm ciRun the same Flutter and Firebase validation used in continuous integration:
dart format --output=none --set-exit-if-changed lib test
flutter analyze
flutter test
flutter build web --release
npm run test:rulesThe web build does not need live credentials to compile. Use --dart-define-from-file=firebase.defines.json when producing a connected release.
npm run test:rules starts isolated Firestore, Realtime Database, and Cloud Storage emulators under the reserved demo project ID demo-ilmloop; it requires no Firebase login or production credentials. The emulator suite exercises both allowed and denied operations for paired skills, canonical chats and immutable messages, referenced sessions and deterministic reviews, relationship-bound notifications, private account/token documents, authenticated-readable profiles, Realtime Database presence, and Storage profile-photo ownership and file constraints.
Firebase Hosting serves Flutter's generated build/web directory and rewrites client-side routes to index.html:
flutter build web --release --dart-define-from-file=firebase.defines.json
firebase login
firebase use --add
firebase deploy --only hostingReview the security rules for your environment before deploying Firestore configuration:
firebase deploy --only firestore:rules,firestore:indexes,database,storageIlmLoop can process account details, profile photos, skills, messages, session information, ratings, notification tokens, presence, and activity timestamps. Operators are responsible for consent, access controls, retention, deletion workflows, and compliance for their deployment.
- Use a dedicated non-production Firebase project during development.
- Review Firestore, Realtime Database, and Storage rules before accepting real users.
- Restrict Firebase API keys and OAuth clients to the intended apps and domains.
- Never commit service-account keys, signing keys, local define files, or exported user data.
- Treat repository rules as a starting point and test them against your own threat model.
Please report security concerns privately to the repository owner rather than opening a public issue containing sensitive details.
Contributions are welcome. Read CONTRIBUTING.md for the development and review workflow.