NoteSync is a production-grade, offline-first notes application with cloud synchronization built using Flutter, Riverpod, Isar, Firebase, and Cloudinary. Local data is encrypted at rest using AES-256, and Cloudinary media uploads are proxy-signed server-side via a Cloudflare Worker to protect secrets.
- Offline-First CRUD: All note writes immediately hit Isar local DB and update the UI reactively.
- Background Sync: Automatic two-way cloud syncing triggered on app resume, connection recovery, or via a 2-minute periodic timer.
- Conflict Resolution: Timestamps within 5 seconds trigger a conflict copy (older note appended with
(conflict copy)); otherwise, Last-Write-Wins (LWW) applies. - Media Upload Proxy: Images and videos are directly uploaded to Cloudinary via secure signed parameters from a Cloudflare Worker.
- At-Rest Encryption: Note bodies are encrypted locally in Isar using AES-256 (via the
encryptpackage) with keys stored inFlutterSecureStorage. - Biometric Application Lock: Optional FaceID/Fingerprint/PIN lock via
local_auth. - Account Data Purge: Deleting an account triggers a secure worker endpoint to delete all Firestore documents and associated Cloudinary assets before signing out.
lib/
├── core/
│ ├── di/ # Dependency injection (GetIt container)
│ ├── errors/ # Sealed Result type and Failure representations
│ ├── security/ # AES-256 Encryption Service
│ ├── theme/ # Modern Slate/Indigo design system theme tokens
│ └── utils/ # Quill JSON delta parser
├── data/
│ ├── local/ # Isar Note collections and DAOs
│ ├── remote/ # Firestore & Cloudinary media client sources
│ ├── repository/ # NoteRepositoryImpl coordinating local & remote sync
│ └── models/ # DTO converters (FirestoreNoteModel, IsarNoteModel)
├── domain/
│ ├── entities/ # Pure Dart domain classes (NoteEntity)
│ ├── repository/ # Abstract repository interfaces
│ └── usecases/ # Clean architecture business actions (CreateNote, SyncNotes)
├── presentation/
│ ├── screens/ # UI (Login, SignUp, Home Dashboard, Note Editor, Trash, Settings)
│ ├── widgets/ # Shared presentation widgets
│ └── providers/ # State management (Riverpod notifiers)
└── main.dart # Main application setup and lifecycle observers
- Create a Firebase project in the Firebase Console.
- Enable Authentication (Email/Password & Google Sign-in providers).
- Enable Cloud Firestore and select a server location.
- Copy firestore.rules into your Firebase Console Rules tab or deploy using Firebase CLI.
- Register your Flutter app by running
flutterfire configure(requires Firebase CLI installed).
- Register for a free account at Cloudinary.
- Note down your Cloud Name, API Key, and API Secret.
- In the Settings dashboard, configure an Upload Preset:
- Mode: Signed (Do not use Unsigned uploads).
- Enforce constraints like max file size or specific allowed formats (e.g.
jpg, png, webp, mp4).
The backend proxy manages credentials security, Cloudinary uploads, and account purging.
- Navigate to the
cloudflare_workerfolder. - Initialize wrangler:
npm install -g wrangler wrangler login
- Create a KV namespace for rate limiting:
Add the returned
wrangler kv:namespace create RATE_LIMIT_KV
idto yourwrangler.tomlfile underkv_namespaces. - Deploy the worker:
wrangler deploy
- Set worker secret environment variables in Cloudflare dashboard or via Wrangler:
wrangler secret put CLOUDINARY_API_KEY wrangler secret put CLOUDINARY_API_SECRET wrangler secret put CLOUDINARY_CLOUD_NAME wrangler secret put FIREBASE_PROJECT_ID
- Copy the
.env.exampleto.envin the root directory:cp .env.example .env
- Configure the variables inside
.env:CLOUDFLARE_WORKER_URL: The URL of your deployed Cloudflare Worker.CLOUDINARY_CLOUD_NAME: Your Cloudinary Cloud Name.FIREBASE_PROJECT_ID: Your Firebase Project ID.
- Install dependencies:
flutter pub get
- Run the code generator to generate database adapters:
dart run build_runner build --delete-conflicting-outputs
- Run the app:
flutter run
Run the full suite of unit tests verifying Note encryption/decryption, sync conflict LWW resolution, and offline repository merge behaviors:
flutter test