Skip to content

Latest commit

 

History

481 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Invoice Ninja - Beta

v2 client application for Invoice Ninja.

Desktop Apps

Mobile Apps

Table of Contents


Setting up the app

# 1. Enable the repo's pre-commit hook (formats staged Dart, mirrors CI)
git config core.hooksPath .githooks

# 2. Install dependencies
flutter pub get

# 3. Generate freezed / json_serializable / drift code
dart run build_runner build --delete-conflicting-outputs

# 4. Run (pick a device)
flutter run -d macos      # or -d chrome, or an iOS simulator

Don't have an Invoice Ninja backend? Test against the demo server:

  • URL: demo.invoiceninja.com
  • Email: demo@invoiceninja.com
  • Password: Password0

To avoid retyping credentials, copy dev.json.exampledev.json and run with --dart-define-from-file=dev.json (debug/profile only; release builds tree-shake it). macOS entitlements, platform targets, and the web/WASM assets are documented in docs/setup.md.

Application architecture

Layered MVVM: ChangeNotifier + ListenableBuilder only.

View (StatelessWidget)
  └─ ViewModel (ChangeNotifier)
       └─ Repository (single source of truth per entity)
            ├─ Drift database (local state, watched by streams)
            ├─ Outbox (offline mutation queue)
            └─ Service (HTTP client → /api/v1/...)

Drift is the only thing the UI reads from: the network writes into Drift, the UI watches Drift. Every write goes through the outbox, so the app keeps working offline; mutations reconcile with the server later via a strictly-ordered, idempotent drain loop. Every list is scoped by company_id (multi-company), and on native platforms Drift sits on SQLCipher (encrypted at rest).

Project structure

lib/
├── main.dart         boot sequence (DI, restore, runApp)
├── app/              DI bag, router, theme, design tokens, env
├── data/
│   ├── models/       freezed domain models + API DTOs
│   ├── services/     HTTP clients (one per entity + shared ApiClient)
│   ├── repositories/ single source of truth per entity
│   └── db/           Drift database, DAOs, tables
├── domain/           entity types, registry, sync dispatchers
├── ui/
│   ├── core/         generic list/detail/edit scaffolds + shared widgets
│   └── features/     feature folders (auth, clients, products, …)
├── l10n/             localization delegate + supported locales
└── utils/            Formatter, parsing helpers, etc.

Every entity follows the same shape under data/ and ui/features/. When in doubt, mirror Client.

Documentation

Code generation

Regenerate freezed models, JSON serializers, and Drift code after editing any annotated source:

dart run build_runner build --delete-conflicting-outputs

Tests

flutter analyze              # static analysis
flutter test                # unit + widget + repository-contract suite
flutter build web --wasm    # the authoritative web compile gate

Integration tests (integration_test/) boot the real app and take over the foreground. Let CI run them; don't run them during a focused session. The on-request procedure is in docs/integration-tests.md.

Screenshots

The images at the top are generated, not hand-captured, produced by integration_test/screenshots_test.dart, which boots the real app (web) against the demo server and captures each marketing screen. This is a local, on-demand task (needs chromedriver):

bash tools/capture_screenshots.sh   # writes PNGs into samples/screenshots/

Credits

https://github.com/invoiceninja/invoiceninja/tree/v5-develop#credits

Contributions

We gladly accept contributions! To get involved, join our Slack group or Discord server.

License

See LICENSE.txt.

About

Invoice Ninja: Desktop/mobile admin portal built with Flutter

Resources

Stars

27 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages