A Flutter app that uses Google Sheets as a free CMS/database for a product catalog. Create, read, update, and delete products directly from a spreadsheet — no backend server required.
Built as a tutorial project to demonstrate real-world patterns: service account auth, the repository pattern, Riverpod state management, and graceful error handling.
- Product catalog — list products fetched from a Google Sheet
- Add / Edit / Delete — full CRUD with batch delete support
- Offline detection — pre-flight connectivity check before every request
- Retry with backoff — automatic exponential backoff (1 s → 2 s → 4 s) on transient failures
- Skeleton loading — shimmer-style placeholder cards while data loads
- Typed error handling — sealed
Result<T>type, no raw exceptions leaking into the UI
| Layer | Package |
|---|---|
| State management | flutter_riverpod + riverpod_annotation |
| Google Sheets API | googleapis + googleapis_auth |
| Connectivity | connectivity_plus |
| HTTP client | dio |
Create a Google Sheet with the following columns starting at row 2 (row 1 = headers):
| A — ID | B — Name | C — Price | D — Category | E — Description |
|---|---|---|---|---|
| 1 | Blue T-Shirt | 29.99 | Apparel | Soft cotton tee |
Supported categories: Apparel, Accessories, Electronics, Other
- Go to Google Cloud Console and create a project.
- Enable the Google Sheets API.
- Create a Service Account and download its JSON key file.
- Share your spreadsheet with the service account's email address (Editor access).
Place the downloaded JSON key file at:
assets/service_account.json
Never commit this file. Add it to
.gitignore.
Open lib/features/catalog/data/sheets_repository.dart and replace the placeholder:
const _spreadsheetId = 'YOUR_SPREADSHEET_ID_HERE';The ID is the long string in your sheet's URL:
https://docs.google.com/spreadsheets/d/<spreadsheet-id>/edit
flutter pub get
flutter runlib/
├── core/
│ ├── auth/ # Service account authentication
│ ├── connectivity/ # Offline detection
│ ├── result.dart # Sealed Result<T> / SheetsError types
│ └── retry.dart # Exponential backoff helper
└── features/
└── catalog/
├── data/ # SheetsRepository — all API calls
├── domain/ # Product model
└── presentation/ # CatalogScreen, AddProductScreen, EditProductScreen