π· Overview
| Section | ||
|---|---|---|
| π | About the Project | Overview |
| β¨ | Core Features | Highlights |
| π¬ | Demo | Walkthrough |
βοΈ Technical
| Section | ||
|---|---|---|
| π | Architecture Overview | Feature-First Β· Cubit |
| π | Project Structure | lib/ tree |
| β | Tech Stack & Dependencies | Packages & Plugins |
| π | Setup Instructions | Getting Started |
| Assumptions & Limitations | Notes |
π¦ Resources
| Section | ||
|---|---|---|
| π | License | All Rights Reserved |
TicketFlow is a mobile Help Desk Ticketing System built as a Flutter technical assessment project. It allows a user to create, browse, search, and manage support tickets from end to end β starting from a dashboard summarizing ticket statistics, down to full detail, edit, and delete operations on individual tickets.
Every ticket carries a subject, description, priority (Low / Medium / High), category (Technical / Billing / General), and status (Open / In Progress / Closed). All data is persisted on-device, so nothing is lost when the app is closed and reopened.
The project was built to demonstrate:
- A scalable, feature-first project structure with clear separation of concerns
- Predictable state management using Cubit
- Type-safe error handling and offline-first local persistence
- A consistent, reusable design system across screens
- Live summary cards: Total, Open, In Progress, and Closed tickets, computed from local storage
- Full ticket list showing ID, subject, priority, status, and created date
- Debounced search by subject
- Filter by status
- Sort by created date
- Required Subject & Description fields with friendly validation errors
- Priority selector: Low / Medium / High
- Category selector: Technical / Billing / General
- Auto-generated ticket number, creation date, and initial status (
Open)
- Full ticket detail view
- Change status (Open β In Progress β Closed)
- Edit subject, description, and priority
- Delete ticket with a confirmation dialog
- Offline-first local storage via Hive CE β data survives app restarts
- Proper loading, empty, and error states (with retry)
- Responsive, consistent Material 3 design system
TicketFlow follows a feature-first folder structure combined with a simplified Clean Architecture, using Cubit (from flutter_bloc) for state management and the Repository Pattern for full data-source abstraction.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β TICKETFLOW (Flutter App) β
β β
β βββββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββ β
β β Feature-First β β Cubit State β β Hive CE Local β β
β β Clean Arch. β β Management β β Storage β β
β βββββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββ β
β β
β βββββββββββββββββββ βββββββββββββββββββββ ββββββββββββββββββββ β
β β go_router β β Dio + Interceptorsβ β GetIt DI β β
β β Declarative Nav β β (wired, not yet β β Service Locator β β
β β β β connected to API)β β β β
β βββββββββββββββββββ βββββββββββββββββββββ ββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββ
β On-Device Hive Boxes β
β ticketsBox Β· settingsBox β
βββββββββββββββββββββββββββββββββββ
Dependency direction: Views β Cubits β Repositories β Data Sources β Storage (Hive) β all dependencies point inward, and concrete implementations are injected via GetIt.
Business logic is fully separated from the UI using Cubit, chosen over full Bloc since the app's actions are simple method calls (getAllTickets(), deleteTicketById(id)) with no need for explicit event classes. Each feature owns its own Cubit, registered as a Factory in GetIt so every route gets a fresh instance β preventing stale state between screens. BlocProviders are attached at the route level inside app_router.dart, not the widget tree.
go_router handles all declarative routing, including passing data (like a selected TicketModel) via state.extra.
get_it manages all bindings: data sources and repositories are registered as LazySingleton (shared, stateless), while Cubits are registered as Factory (fresh per route).
Repositories wrap data-source calls and return Either<String, T> (from dartz), so Cubits never need to know about exception types β they simply fold on Left(error) or Right(data).
lib/
βββ app/ # Root MaterialApp.router widget + sequential app initializer
β
βββ core/ # App-wide shared resources
β βββ common/ # Reusable dialogs, snackbars, debouncer
β βββ constants/ # API endpoints, keys, app constants
β βββ di/ # GetIt service locator setup
β βββ enums/ # Rich enums: TicketPriority, TicketCategory, TicketStatus
β βββ errors/ # Exceptions, handlers, unified ErrorModel
β βββ functions/ # Small utility helpers (date formatting, token building, etc.)
β βββ logging/ # AppLogger + global BlocObserver
β βββ models/ # Core TicketModel (Hive-annotated)
β βββ routes/ # GoRouter configuration + navigation helpers
β βββ services/ # Hive & secure storage services, Dio network layer
β βββ utils/ # Assets, colors, typography, spacing, radius, shadows, theme
β βββ validators/ # Form validators (subject, description, email, password)
β βββ widgets/ # Shared UI: chips, buttons, inputs, loading/empty/error states
β
βββ features/ # Independent, self-contained feature modules
βββ splash/ # Animated splash β navigates to Home
βββ home/ # Dashboard + ticket list entry screen
βββ dashboard/ # Ticket statistics (data/presentation)
βββ tickets/ # Ticket list & ticket details (data/presentation)
βββ ticket_form/ # Create/Edit ticket form (data/presentation)
βββ search/ # Ticket search (data/presentation)
Every feature follows the same internal structure to ensure consistency and discoverability:
feature_name/
βββ data/
β βββ data_sources/ # Abstract interface + implementation (Hive/API)
β βββ models/ # Feature-specific data models (if any)
β βββ repos/ # Abstract repository + implementation (returns Either)
βββ presentation/
βββ view_models/ # Cubits + States (business logic)
βββ views/ # Screens & feature-specific widgets
| Package | Purpose |
|---|---|
flutter_bloc |
State management (Cubit) |
bloc |
Core bloc library required by flutter_bloc |
go_router |
Declarative routing & deep linking |
get_it |
Dependency injection (Service Locator) |
dartz |
Functional programming β Either<L, R> types |
| Package | Purpose |
|---|---|
dio |
HTTP client with interceptors & timeouts β wired for future API use |
| Package | Purpose |
|---|---|
hive_ce / hive_ce_flutter |
Local NoSQL database β offline-first ticket persistence |
flutter_secure_storage |
Encrypted storage reserved for auth tokens |
| Package | Purpose |
|---|---|
google_fonts |
Inter typography |
flutter_svg |
SVG icon rendering |
fl_chart |
Dashboard statistics charts |
lottie |
Loading/empty state animations |
device_preview |
Responsive testing across devices in dev |
| Package | Purpose |
|---|---|
logger |
Color-coded console logging |
intl |
Date formatting |
uuid |
Unique ticket ID generation |
meta |
Static analysis annotations (@immutable) |
cupertino_icons |
iOS-style icon pack |
| Package | Purpose |
|---|---|
flutter_lints |
Lint rules |
build_runner |
Code generation orchestrator |
hive_ce_generator |
Hive type adapter generator |
- Flutter SDK with Dart β₯ 3.12.2
- Android Studio or VS Code with the Flutter & Dart plugins
- An Android/iOS emulator or a physical device
-
Clone the repository
git clone https://github.com/mohamed-dev-404/ticketflow.git cd ticketflow -
Install dependencies
flutter pub get
-
Generate Hive adapters (required β the app depends on generated
*.g.dartfiles)dart run build_runner build --delete-conflicting-outputs
-
Run the app
flutter run
No .env file or backend configuration is required β TicketFlow runs fully offline out of the box.
π₯ Watch the full app walkthrough (Google Drive)
Dashboard, ticket list with search/filter/sort, ticket creation, and full ticket detail/edit/delete flow.
- Offline-first by design: all ticket data is persisted locally via Hive CE. The Dio-based network layer (interceptors, auth handling, endpoints) is fully wired but intentionally not connected to a live backend yet β it's scaffolded for future API integration.
- Light theme only: dark mode is not implemented in the current version; the design system (colors, typography, spacing) is structured to support it later with minimal changes.
- Ticket numbers are generated client-side via
uuid, not by a remote server. - Text scaling is locked to
1.0app-wide so ticket cards and chips stay consistent regardless of the device's system font-size setting. - Single device, no sync: since there's no backend in use, tickets live only in the Hive box on the device the app is installed on.
- No authentication or roles yet: the app currently has no permission system β there's a single implicit role, and the user who opens a ticket is the same one expected to close it themselves. Multi-role permissions (e.g. agent vs. requester) will be introduced once a backend and authentication layer are added.
All Rights Reserved Β© 2026 β Mohamed Ibrahim
This project β including all source code and documentation β was developed as part of a Flutter developer technical assessment and is shared for review and evaluation purposes only.
No part of this project may be copied, modified, redistributed, or reused for academic or commercial purposes without prior written permission from the author.
Made with β€οΈ using Flutter