A cross-platform Point-of-Sale (POS) application built with .NET MAUI and Blazor Hybrid for iPad, Android, and Windows. Designed with Clean Architecture principles, featuring offline-first capabilities, real-time inventory management, and comprehensive reporting.
PosApp is an enterprise-grade POS solution optimized for restaurants and retail businesses. The application works seamlessly offline and synchronizes data when connectivity is restored, ensuring uninterrupted service even in low-connectivity environments.
- Cross-Platform: iPad (primary), Android, Windows support via .NET MAUI
- Offline-First: Full offline capabilities with automatic sync
- Cost Tracking: Price monitoring, profit margin analysis, and inventory costing
- Queue Management: Dual numbering system (order IDs + customer-facing queue numbers)
- Mobile Printing: Integrated receipt and label printing
- Sales Analytics: Daily, monthly, and product-level reporting
- Clean Architecture: Layered design for maintainability and testability
| Layer | Technologies |
|---|---|
| UI | .NET MAUI + Blazor Hybrid (C# with WebView) |
| Business Logic | .NET 10, C# 14 |
| Database | SQLite (offline) |
| Architecture | Clean Architecture (Domain-Driven Design) |
| Async | Task-based async/await throughout |
| Testing | xUnit, Moq |
Target Frameworks: net10.0-ios, net10.0-android, net10.0-maccatalyst, net10.0-windows
PosApp/
├── src/
│ ├── PosApp.Domain/ # Core business entities & rules (no dependencies)
│ │ ├── Entities/ # Order, Product, Payment, AppSettings
│ │ └── Enums/ # OrderStatus, PaymentMethod, SyncStatus, QueueResetPeriod
│ │
│ ├── PosApp.Application/ # Use-cases & orchestration
│ │ ├── Services/ # IOrderService, ICheckoutService, IProductService, etc.
│ │ ├── Repositories/ # Interface definitions (implementation in Infrastructure)
│ │ └── Models/ # DTOs & reports (CategorySalesReport, DailySaleSummary)
│ │
│ ├── PosApp.Infrastructure/ # Implementations (SQLite, HTTP, sync engine)
│ │ ├── Data/
│ │ │ ├── PosAppDbContext.cs # EF Core context
│ │ │ └── Configurations/ # Entity configurations
│ │ ├── Repositories/ # Concrete repository implementations
│ │ ├── Services/ # Service implementations (checkout, orders, sync)
│ │ └── Utilities/ # Helpers, formatters, extensions
│ │
│ └── PosApp.MauiBlazor/ # UI Layer (MAUI host + Blazor components)
│ ├── Components/ # Blazor components (ProductGrid, CartPanel, etc.)
│ ├── Pages/ # Blazor pages (Sales, Orders, Settings)
│ ├── Services/ # Device-specific services
│ ├── Platforms/ # Platform-specific code (iOS, Android, Windows)
│ └── Resources/ # Styles, fonts, images
│
├── tests/
│ └── PosApp.Tests/ # Unit tests (Domain, Application logic)
│ ├── Domain/ # Entity and invariant tests
│ └── Application/ # Use-case and service tests
│
└── docs/ # Feature documentation
├── QUEUE_NUMBER_SYSTEM.md # Dual numbering system for orders
├── PRODUCT_CRUD_IMPLEMENTATION.md # Product management workflows
└── MOBILE_PRINTING.md # Receipt & label printing
- Domain → No dependencies (pure business logic)
- Application → Only Domain + abstractions
- Infrastructure → Implements Application interfaces
- UI (MauiBlazor) → Depends on Application & Infrastructure via DI
- Product selection with real-time pricing
- Shopping cart with quantity management
- Multiple payment methods (Cash, Card, etc.)
- Order status tracking (Pending, Completed, Cancelled)
Dual numbering for orders:
- OrderNumber: Technical ID (e.g.,
ORD-20260223143225) for sync and system integrity - QueueNumber: Customer-facing sequential numbers (e.g.,
12) with configurable reset periods- Daily reset (default)
- Weekly reset (Monday)
- Monthly reset
- Never (continuous)
📖 See docs/QUEUE_NUMBER_SYSTEM.md for detailed implementation.
- All transactions saved locally first (SQLite)
- Automatic background sync when online
- Conflict resolution strategy
- Sync state tracking (PendingUpload, Synced, Failed, Conflict)
- Product cost tracking and profit margin calculation
- Real-time inventory updates
- Category-based organization
- Daily sales summary (total, transaction count, average order value)
- Monthly sales reports
- Product-level sales analysis
- Category-wise breakdown
📖 See docs/PRODUCT_CRUD_IMPLEMENTATION.md for product workflows.
- Receipt printing with order details
- Label/ticket printing for kitchen displays
- Device-specific printer integration
📖 See docs/MOBILE_PRINTING.md for configuration.
- Configurable queue reset period
- Currency & locale formatting
- App-level configuration persistence
- .NET SDK 10.0 or later
- Visual Studio 2022 (v17.10+) or VS Code with C# Dev Kit
- Platform SDKs for target platforms:
- iOS: Xcode (Mac only)
- Android: Android SDK
- Windows: Windows SDK
# Build all projects
dotnet build PosApp.slnx
# Build specific platform
dotnet build -f net10.0-android
dotnet build -f net10.0-ios
dotnet build -f net10.0-windows10.0.19041.0# Run all tests
dotnet test PosApp.slnx
# Run with coverage
dotnet test --collect:"XPlat Code Coverage"# Android
dotnet run -f net10.0-android
# iOS (Mac only)
dotnet run -f net10.0-ios
# Windows
dotnet run -f net10.0-windows10.0.19041.0- Independence: Business logic independent of frameworks and UI
- Testability: Core logic testable without external dependencies
- Flexibility: Easy to swap implementations (e.g., different databases, APIs)
- Always local first: All writes go to SQLite immediately
- Async sync: Background sync when online
- Conflict resolution: Server data takes precedence for master data; local orders preserved unless rejected
- Device identification: DeviceId tracking for multi-device scenarios
- Entities: Order, Product, Payment with business invariants
- Value Objects: Enums (OrderStatus, PaymentMethod, SyncStatus)
- Repositories: Abstract data access behind interfaces
- Services: Coordinate complex workflows
- Keep Domain classes pure (no infrastructure concerns)
- Use async/await throughout (Task-based)
- Constructor injection for all dependencies
- Nullable reference types enabled
- Interfaces:
IOrderRepository,ICheckoutService - Async methods:
GetOrderAsync(),SaveOrderAsync() - DTOs:
OrderDto,SalesReportModel
- Domain entities enforce invariants in constructors
- Application layer returns
Result<T>for operations that can fail - Structured logging via
ILogger<T> - No exception throwing for normal business validation
- Unit test Domain invariants
- Mock repositories in Application tests
- Minimal UI tests (focus on logic)
See PosApp.Tests for test examples.
| Document | Purpose |
|---|---|
| QUEUE_NUMBER_SYSTEM.md | Queue numbering architecture & implementation |
| PRODUCT_CRUD_IMPLEMENTATION.md | Product management workflows |
| MOBILE_PRINTING.md | Printing service configuration |
The application uses an offline-first sync strategy:
- Upload Phase: Send local PendingUpload changes to server
- Download Phase: Fetch remote updates (Products, Prices, Settings)
- Conflict Resolution: Merge strategy based on entity type
- Master data (Products): Server wins
- Transactions (Orders): Local wins unless server rejects
Sync state tracked per record:
PendingUpload- Not yet syncedSynced- Successfully syncedFailed- Sync failed (retry needed)Conflict- Conflicting changes detected
The application uses Blazor Hybrid with a modern component library for responsive, touch-friendly interfaces:
- ProductGrid: Browse and select items
- CartPanel: View and modify shopping cart
- CheckoutDialog: Payment processing
- OrderList: View order history
- ReportsPage: Analytics and sales data
- SettingsPage: Configuration management
Components are thin; business logic lives in Application services.
- Order: Customer transactions with status and queue numbers
- OrderItem: Line items within orders
- Product: Inventory items with pricing and cost
- Payment: Payment records with method tracking
- AppSettings: Configuration storage
All entities include:
SyncStatusfor offline-first supportUpdatedAttimestamp (UTC) for sync reconciliationDeviceIdfor multi-device trackingServerIdfor server reference (when synced)
- No secrets stored in repository (use configuration)
- Async data access prevents blocking
- Input validation in Application layer
- Structured logging (no sensitive data in logs)
When implementing features, follow:
- Place code in correct layer (Domain/Application/Infrastructure/UI)
- Use constructor injection (no service locators)
- Maintain async APIs (no blocking calls)
- Write unit tests for Domain/Application logic
- Document public APIs with XML comments
✅ Completed
- Core POS functionality (Sales, Orders, Payments)
- Queue number system with configurable reset periods
- Offline-first architecture with SQLite
- Sales analytics and reporting
🚧 In Progress
- Mobile printing integration
- Advanced reporting features
- Multi-location support
📋 Planned
- Real-time sync with backend API
- Customer loyalty programs
- Inventory forecasting
- Multi-currency support
[Add your license here]
Happy coding! 🚀 For questions or issues, refer to the documentation in docs/ folder or create an issue.