Last Edit: 05.2025
Language: Typescript React Capacitor with Vite
CardMaster is a simple app that allows you to store customer cards locally on your phone. It supports both QR codes and barcode customer cards.
Apple App Store: https://apps.apple.com/de/app/card-master-loyalty-cards/id6743057728
| App Store Screen 1 | App Store Screen 2 |
|---|---|
![]() |
![]() |
| App Store Screen 3 | App Store Screen 4 |
|---|---|
![]() |
![]() |
This layered architecture diagram of the Card Master app illustrates a clean separation of concerns across four tiers: Service Layer, Container Components, View Components, and UI Elements. Key development utilities like the Logger, the main App.tsx entry point, feature flags, and the core CustomerCard data model are intentionally omitted for clarity, as they are deeply nested or widely referenced throughout the codebase.
The architecture of the Customer Cards App is designed to ensure modularity, maintainability, and scalability. It is divided into four main layers: UI-Elements, View-Components, Container-Components, and the Service Layer. Each layer has a specific role in the application, and the implementation reflects the actual codebase.
UI-Elements are the smallest building blocks of the user interface. These components are atomic, reusable, and styled to maintain consistency across the app. Examples include:
- Buttons: For actions like saving or deleting a card.
- Input Fields: For entering customer card details.
- Card Display: A visual representation of customer cards.
- QR Code Scanner: A UI component for scanning QR codes.
These elements are designed to be generic and reusable, ensuring that they can be used across multiple screens and features.
The @capacitor-mlkit/barcode-scanning plugin is used within the UI-Elements layer to provide barcode and QR code scanning functionality. It is integrated into components like the ScannerComponent and FileUploadScanner. These components handle user interactions for scanning barcodes either directly from the camera or from uploaded images.
-
Camera-Based Scanning:
- The
ScannerComponentuses theBarcodeScanner.scan()method to initiate a live scan session. - Permissions for camera access are requested using
BarcodeScanner.requestPermissions(). - The scanned barcode data is processed and passed to higher layers for further handling.
- The
-
Image-Based Scanning:
- The
FileUploadScannercomponent allows users to upload an image file. - The image is processed using the
BarcodeScanner.readBarcodesFromImage()method to extract barcode data.
- The
These functionalities ensure that the app can handle both live scanning and static image processing, providing flexibility for users.
View-Components are composed of multiple UI-Elements and represent specific parts of the application's screens. They are responsible for rendering data and handling user interactions. Examples include:
- Home Screen: Displays a list of saved customer cards.
- Card Details Screen: Shows detailed information about a selected card.
- QR Scanner Screen: Allows users to scan and add new cards.
These components interact with Container-Components to fetch or update data dynamically.
Container-Components act as the intermediary between the View-Components and the Service Layer. They handle state management, data fetching, and complex user interactions. Examples include:
- Card Manager: Manages the state of customer cards, including fetching, saving, and deleting cards.
- QR Scanner Controller: Handles the logic for scanning QR codes and validating the data.
These components ensure that the application logic is separated from the UI, making the app easier to maintain and test.
The Service Layer is the backbone of the application, responsible for handling business logic, data storage, and external integrations. Below are the key services used in the app:
The SQLite Service is responsible for managing the local IndexedDB database. It provides methods for saving, retrieving, and deleting customer cards. For example, the saveCard method generates a unique ID for each card using crypto.randomUUID(), adds timestamps (createdAt and updatedAt), and saves the card to the customer_cards object store in IndexedDB. Errors are handled gracefully using the handleIndexedDBError function.
The Logger Service provides a centralized way to log application events. It is used extensively throughout the app to track actions, such as saving a card or handling errors. This ensures better debugging and monitoring during development. This service also makes it possible to export logs locally, among other things, as they are saved locally depending on the feature flags. (The option is only visible in the settings screen with the appropriate feature flag) The entire service is controlled by feature flags from the config file and in the release candidates the logging is always completely off as there is no transfer of the user's data. (Except what Google AdMob is doing)
The Ads Service manages the integration of advertisements in the app. It uses the @capacitor-community/admob plugin to display ads, ensuring compliance with platform guidelines. This service is responsible for loading, displaying, and tracking ads and the ad dialog.
The app uses configuration files to manage static content and settings. For example:
app_texts: Contains the app imprintfeatureFlags: Contains FeatureFlags which control the logger or which setting options are visible. (i.e. classic developer options which make it easier to further develop the app) And for the localized texts we use i18next.
- Modular Design: Each layer is designed to be independent, making it easier to update or replace components.
- Scalability: The architecture supports the addition of new features, such as integrating new ad providers or expanding the database schema.
- Separation of Concerns: By dividing the app into distinct layers, the architecture ensures that UI, logic, and data management are handled separately.
- UI-Elements: Atomic, reusable components like buttons, input fields, and QR scanners.
- View-Components: Screens composed of UI-Elements, such as the Home Screen or QR Scanner Screen.
- Container-Components: Manage state and data flow between the UI and the Service Layer.
- Service Layer: Handles business logic, database operations, logging, and external integrations like ads.
In the project directory, you can run:
Runs the app in the development mode. Open http://localhost:5173 to view it in the browser.
Builds the app for production to the build folder.
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.
Your app is ready to be deployed!
Sync the build app to the android and ios folder. Run it after npm run build.
Generate the JSON with the licenses of the NPM packages used. This can then replace the existing license json under /legal/usedLibs.
According to the command npm list You can see the deeper NPM modules used and which of these are used in the licenses.json.
├── @capacitor-community/[email protected]
├── @capacitor-mlkit/[email protected]
├── @capacitor/[email protected]
├── @capacitor/[email protected]
├── @capacitor/[email protected]
├── @capacitor/[email protected]
├── @capacitor/[email protected]
├── @capacitor/[email protected]
├── @capacitor/[email protected]
├── @emotion/[email protected]
├── @emotion/[email protected]
├── @eslint/[email protected]
├── @mui/[email protected]
├── @mui/[email protected]
├── @testing-library/[email protected]
├── @types/[email protected]
├── @types/[email protected]
├── @types/[email protected]
├── @vitejs/[email protected]
├── @zxing/[email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]




