A lightweight English-only Flutter application that turns any Android phone into an offline-first point-of-sale system. Core focus: real-time & day-end sales entry, automatic stock deduction, receipt/PDF export, and Supabase-backed cloud sync — with per-user data isolation.
| Tier | Free | Premium |
|---|---|---|
| Items & turnover | ≤ 1 000 items / Rs 100 000 mo | Unlimited |
| Real-time & End-of-day modes | ✅ | ✅ |
| Cash / QR / Card tracking | ✅ | ✅ |
| Offline-first + background sync | ✅ | ✅ |
| Automatic stock deduction | ✅ | ✅ |
| Daily / Weekly PDF | ✅ | ✅ |
| Low-stock alerts | ✖️ | ✅ |
| Pie-chart dashboard / custom ranges | ✖️ | ✅ |
| WhatsApp receipt sharing | ✖️ | ✅ |
| Staff log-ins | ✖️ | ✅ |
| SMS end-of-day summaries | ✖️ | ✅ |
| Layer | Choice | Notes |
|---|---|---|
| UI | Flutter 3 | Material 3, Poppins font, Provider state mgmt |
| Local storage | SQLite via sqflite |
Offline queue & cache |
| Cloud | Supabase (PostgreSQL) | Auth, RLS, realtime, storage |
| PDF/Print | pdf, printing pkgs |
Bluetooth printers via SDK placeholder |
| Icons | flutter_launcher_icons |
Uses assets/images/logo-icon.png |
Project structure (partial):
lib/
models/ domain classes (Item, Sale, ...)
providers/ ItemProvider, SaleProvider, ReportsProvider, ...
screens/ auth/, sales/, reports/, …
ui/ design_system.dart (theme + widgets)
assets/
images/logo-icon.png
config/.env ← Supabase keys
- Flutter 3.22+ with Android tool-chain.
- A Supabase project (Free tier is fine).
- Copy
.env.sample→assets/config/.envand fill:
SUPABASE_URL=https://<YOUR-REF>.supabase.co
SUPABASE_ANON_KEY=<public_anon_key>
- Enable Email provider in Supabase Auth. Disable email confirmations only if kiosk build.
- Run the SQL in
database/schema.sqlto create tables & RLS.
-- sales parent
create table public.sales (
id uuid primary key,
user_id uuid references auth.users(id) on delete cascade,
timestamp timestamptz not null default now(),
payment_method text not null,
total numeric not null
);
-- item lines
create table public.sale_items (
id bigint generated by default as identity primary key,
sale_id uuid references public.sales(id) on delete cascade,
item_id text,
item_name text,
qty int not null,
price_each numeric not null
);
-- user profiles for display name
create table public.profiles (
id uuid primary key,
display_name text
);
-- Row-level security
alter table sales enable row level security;
alter table sale_items enable row level security;
alter table profiles enable row level security;
create policy "Sales are private" on sales
for all using (user_id = auth.uid()) with check (user_id = auth.uid());
create policy "Lines inherit parent" on sale_items
for all using (sale_id in (select id from sales where user_id = auth.uid()));
create policy "Users can read/update own profile" on profiles
for all using (id = auth.uid()) with check (id = auth.uid());flutter pub get
flutter pub run flutter_launcher_icons:main # one-time
flutter run # debugRelease APK
flutter build apk --releaseEnsure
android:label="DigitalStock"and<uses-permission android:name="android.permission.INTERNET"/>in AndroidManifest.xml.
SaleProvider.fetchRemote()downloads all sales for current user after login.ReportsProviderlistens toSaleProvider→ reports & PDFs always include fetched history.- Launcher icon generated from
assets/images/logo-icon.pngvia flutter_launcher_icons. - First login auto-creates blank row in
profilestable (maybeSingle + insert). - RLS ensures each Supabase query is already scoped by
auth.uid().
- Low-stock push notifications
- Multi-branch syncing
- Supplier marketplace plug-in
- PayHere / WebXPay subscription billing
- Bluetooth printer integration
- Fork & pull-request from a feature branch.
- Follow Dart
dart format/flutter analyzeclean lint. - Explain the problem & solution clearly in the PR.
MIT © 2025 DigitalStock Team