LibraRex
📖 Project Overview
LibraRex is a cross-platform personal book collection tracker built with Flutter, targeting web, iOS, and Android from a single codebase. It uses Google Sheets as a cloud backend, giving users a human-readable, always-accessible spreadsheet they own — with no subscription fees, no proprietary database lock-in, and full data portability.
The app is designed for avid readers and collectors who want to track books they own, have borrowed, are on their wishlist, or have in digital formats — all in one organised, beautifully branded interface.
Target Platforms
⚙️ Tech Stack
| Layer | Technology | Purpose |
|---|---|---|
| UI Framework | Flutter 3.x / Dart 3 | Cross-platform UI and state management |
| Backend / Storage | Google Sheets API v4 | Persistent cloud data store, user-owned |
| Authentication | Google Sign-In (OAuth 2.0) | Secure identity, per-user sheets |
| State Management | Provider (ChangeNotifier) | App-wide reactive state |
| Fonts | Google Fonts — Inter | UI text throughout the app |
| Image Caching | cached_network_image | Book cover thumbnails with shimmer |
| Import / Export | csv + file_picker | CSV round-trip for data portability |
| Book Lookup | Google Books + OpenLibrary APIs | ISBN / title search for metadata |
| Logo / Artwork | Flutter CustomPainter | Geometric dragon — no SVG dependency |
| Loading States | shimmer package | Skeleton screens while loading |
| Token Storage | flutter_secure_storage | Persists auth across app restarts |
🗄️ Data Schema
Each book is a single row in Google Sheets with 18 columns. The sheet is created automatically on first sign-in with a header row.
| Col | Field | Type | Description |
|---|---|---|---|
| A | id | String | UUID — unique stable identifier |
| B | title | String | Book title (required) |
| C | author | String | Author name (required) |
| D | type | Enum | owned | borrowed | wishlist | digital |
| E | status | Enum | available | lent_out | missing |
| F | read | Boolean | true | false — Read / Unread flag |
| G | lentTo | String | Name of person the book is lent to |
| H | isbn | String | ISBN-10 or ISBN-13 |
| I | coverUrl | String | URL to cover thumbnail image |
| J | rating | Double | 0.5–5.0 in 0.5 increments (half-star support) |
| K | notes | String | Free-text annotations |
| L | genre | String | Genre label |
| M | publisher | String | Publisher name |
| N | year | Integer | Publication year |
| O | blurb | String | Book synopsis / description |
| P | updatedAt | String | ISO 8601 timestamp of last edit |
| Q | format | String | Hardcover · Paperback · Large Print · eBook · Audiobook |
| R | location | String | Shelf / room (physical) or service name (digital, e.g. Kindle) |
🔐 Authentication
OAuth 2.0 via google_sign_in. Session persists across reloads via flutter_secure_storage.
Each Google account gets its own isolated spreadsheet. No data is shared between users.
Confirmation dialog before sign-out. Clears session and returns to the auth screen.
Branded auth screen with LibraRex dragon logo, wordmark, and "Your book kingdom" tagline.
📚 Book Collection Management
Owned, Borrowed, Wishlist, and Digital — each with appropriate icon and colour treatment.
Available, Lent Out (with borrower name), or Missing. Status is filterable independent of type.
Simple read flag displayed as a badge in grid cards and list items.
0.5 increments from 0.5 to 5.0 (e.g. 4.5 ★). Tap left half of a star for a half-star.
Notes, genre, publisher, publication year, ISBN, cover URL, and full blurb storage.
Record who you've lent a book to. Shown prominently in card and list views.
🖥️ Library UI
Card layout with cover art, title, author, and contextual status info at the bottom.
Compact rows with thumbnail, title, author, rating, and type badge overlay on the cover.
Search bar slides in/out with ClipRect animation. Searches title, author, and ISBN.
Two popup filter buttons — Type and Status. Status is always active regardless of type filter.
Swipe down to re-sync the latest data from Google Sheets.
Animated loading placeholders for grid and list views during the initial data fetch.
✏️ Add / Edit & Detail
Dedicated entry point via the library FAB. Search tab with live results (cover, series chip, author) or ISBN tab for direct entry. Tap any result to pre-fill the full form instantly.
Full 18-field form with type picker, status selector, read toggle, format chip picker, location field, and half-star rating.
Search by ISBN or title via Google Books / OpenLibrary. Auto-fills cover, publisher, year, series, and blurb.
Full read-only view with large cover. Inline editable rating and location. Series chip links directly to the Series Detail screen.
Confirmation dialog before removing a book from the library and Google Sheets.
Scans all books to fetch/update cover artwork and blurbs. Progress dialog with per-book status.
🔖 Series Intelligence
LibraRex can discover, display, and track book series — showing you what you own, what's missing, and making it easy to fill the gaps.
Rich view of all books in a series in reading order. Owned books show with cover art; missing books appear as ghost slots with their order number and title.
4-tier API lookup: Google Books → WikiData SPARQL (exact + fuzzy) → OpenLibrary by series name → OL author + keyword supplement. Catches partial coverage across all sources.
Missing series books shown as dim placeholders. One-tap "Add to Wishlist" CTA turns any gap into a tracked wishlist entry.
Series name editable directly from the Series Detail screen. Changes save to all owned books in the series at once.
Each book slot shows its reading order number. Owned books without a stored order are matched to slots by normalised title comparison.
Filter bar inside the Series Detail screen to quickly find a specific book when a series spans many entries.
↕️ Import / Export
Downloads the full library as a CSV file. Smart decimal formatting (writes "4.5" not "4.5000").
Maps CSV columns to book fields with row-level validation. Reports errors for malformed rows.
Native file picker on web and mobile via file_picker. Platform download utility handles save correctly per platform.
🎨 Brand & Themes
Geometric wyvern drawn entirely with Flutter CustomPainter. No external SVG package needed.
Primary #B5621E (warm cognac), accent #D4943A (gold). Inspired by aged leather and parchment.
Parchment background (#FDF5EC) with white card surfaces. Warm and readable.
Deep brown background (#191410) with warm dark surfaces (#271D15). Easy on the eyes at night.
Follows the device OS preference. Switches automatically between light and dark.
Overflow menu (⋮) cycles System → Light → Dark → System. Updates the whole app instantly.
🗺️ Roadmap
The following are potential enhancements, not yet prioritised or scheduled. They are grouped by theme to aid planning conversations.
☁️ Alternative Backends & Sync
- OneDrive / SharePoint — store the library as an Excel file in a user's OneDrive account, enabling Microsoft 365 users to use LibraRex without a Google account
- Dropbox / iCloud Drive — JSON or CSV file sync for Apple-ecosystem users
- Firebase Firestore — real-time multi-device sync, potential for social / sharing features
- Supabase (PostgreSQL) — open-source Firebase alternative for self-hosters
- Local-only mode — full offline use with no cloud backend required
📶 Offline & Performance
- Hive / SQLite local cache — persist books locally so the app loads instantly and works without connectivity
- Background sync — push local changes to the backend when connectivity is restored
- Optimistic UI updates — reflect edits instantly without waiting for the API round-trip
- Pagination — load books in pages for very large libraries (1,000+ books)
🔍 Book Discovery & Metadata
- Camera barcode scanner — use device camera (vs. manual ISBN entry) to scan a physical book's barcode for instant add
- Author pages — aggregate all books by an author, with bio from Open Library
- Richer metadata — page count, language, subjects, awards
- Book recommendations — suggest similar books based on genres and ratings in the library
📊 Reading Tracking
- Reading progress — track current page or percentage complete per book
- Reading dates — log when a book was started and finished
- Annual reading goals — set a target number of books for the year
- Statistics dashboard — charts for books read per month/year, genre breakdown, average rating, reading pace
- Reading streaks — gamified daily reading habit tracking
📦 Collections & Organisation
- Multiple shelves — custom named collections (e.g. "Holiday Reads", "Book Club")
- Tagging system — flexible user-defined tags in addition to type/status
- Bulk actions — select multiple books to move, tag, or delete at once
- Custom sort orders — sort by title, author, rating, date added, year published
📥 Import from Other Services
- Goodreads CSV import — map Goodreads export columns to LibraRex fields
- Apple Books — import reading history
- Kindle / Amazon — import purchased and read book lists
- LibraryThing — support the LibraryThing export format
🔗 Export & Integrations
- Notion export — push library as a Notion database
- Airtable sync — two-way sync with an Airtable base
- Push notifications — remind user when a lent book is overdue for return
- Webhook support — trigger external automations on book events
👥 Social & Sharing
- Public profile / shelf — opt-in shareable reading list URL
- Book club mode — shared libraries for a group with per-member read status
- Lend notifications — notify a friend via link when a book is lent
- Book reviews — longer-form review text separate from the notes field
📱 Platform & UX
- iPad / tablet layout — master-detail split view with sidebar navigation
- macOS & Windows desktop — Flutter desktop targets with keyboard shortcuts
- Apple Watch / Wear OS — quick "Mark as read" and lend/return companion actions
- Home-screen widgets — iOS and Android widgets showing current read or recently added
- Accessibility — full screen-reader support, dynamic text size, high-contrast mode
- Internationalisation — multi-language UI (Spanish, French, German, Japanese)
📋 Change Log
All notable changes to LibraRex. Format inspired by Keep a Changelog.
quickSearch() method in BookLookupService — detects name-like queries and uses inauthor: prefix for better author results; single smart query with fallback only when primary returns empty, preserving API quotaprefill: BookLookupResult? parameter on AddEditBookScreen — pre-populates all fields from a lookup result without requiring a second manual lookupauthor:"name" seriesTitle syntaxseries field are now accepted when returned by the combined keyword query (trust the query filtering, not just the metadata field)_normTitle strips leading "Series: " prefix)🚀 Getting Started
Prerequisites
- Flutter SDK ≥ 3.10.0 and Dart ≥ 3.0.0
- Google Cloud project with Sheets API and Google Sign-In enabled
- OAuth 2.0 Web Client ID configured in
google_sign_in - Add
http://localhostandhttp://localhost:3000to Authorized JavaScript Origins in Google Cloud Console
Run locally
flutter pub get flutter run -d chrome --web-port 3000
--web-port 3000 to match the registered OAuth origin. Using a different port will trigger a Google origin_mismatch (Error 400).
Key Packages
| Package | Version | Purpose |
|---|---|---|
google_sign_in | ^6.2.1 | OAuth authentication |
googleapis | ^13.2.0 | Sheets API client |
provider | ^6.1.2 | State management |
google_fonts | ^6.2.1 | Inter font family |
cached_network_image | ^3.3.1 | Cover image caching |
shimmer | ^3.0.0 | Loading skeleton effect |
file_picker | ^8.0.3 | CSV import file dialog |
csv | ^6.0.0 | CSV parse & serialise |
flutter_secure_storage | ^9.2.2 | Token persistence |
☁️ Deployment & Google Drive Setup
One of the most common questions is: "If I share this app with someone, what do they have to set up with Google Drive?" The short answer is nothing — end users just sign in with their Google account and the app does everything else automatically. The only one-time setup is done by the developer (you) when configuring the Google Cloud project.
👤 What end users do
From a user's perspective the setup is completely invisible:
- Open the app URL in their browser (or install the mobile app).
- Tap Sign in with Google and complete the standard OAuth consent screen.
- The app automatically creates a Google Sheet called LibraRex Library in their Google Drive.
- They can start adding books immediately — no spreadsheet configuration needed.
Sheets (read/write) and Drive (file metadata to locate the sheet).
🛠️ One-time developer / operator setup
Before the app can be shared, a developer needs to configure a Google Cloud project once. This is a ~15-minute process:
| Step | Action | Where |
|---|---|---|
| 1 | Create a Google Cloud project | console.cloud.google.com |
| 2 | Enable Google Sheets API | APIs & Services → Enable APIs |
| 3 | Enable Google Drive API | APIs & Services → Enable APIs |
| 4 | Create an OAuth 2.0 Web Client ID | APIs & Services → Credentials |
| 5 | Add your deployment URL to Authorised JavaScript Origins | Edit the OAuth client |
| 6 | Paste the Client ID into web/index.html | Flutter project source |
| 7 | (Optional) Create a Google Books API key and add it to the project | APIs & Services → Credentials |
lib/services/book_lookup_service.dart.
🌐 Self-hosting (web)
flutter build web --release # Upload the build/web/ directory to any static host # (Firebase Hosting, Netlify, Vercel, GitHub Pages, etc.)
Add your production URL (e.g. https://librarex.example.com) to the OAuth client's Authorised JavaScript Origins. That's it — no server-side component needed.
📱 Mobile (iOS / Android)
For native mobile builds, replace the web OAuth client ID with a platform-specific one (iOS client ID for iOS, Android client ID for Android) in the corresponding configuration files (ios/Runner/Info.plist, android/app/google-services.json). The Sheets and Drive API usage is identical; only the auth credential type differs.
🔒 OAuth consent screen & app verification
While in development, add test users to the OAuth consent screen so they can sign in without Google's verification process. For a wider public release, Google requires an app verification review (typically free, takes a few days) to remove the "unverified app" warning from the consent screen. The review verifies that the app only requests the scopes it actually uses.