PWI Software Documentation Help

Flutter Architecture Standards

Components

Since we are using the MVVM structure (see Flutter Development Standards), we separate our code into individual components or categories that each play a distinct role.

Component Definitions

Core Components

View

The UI layer that displays data and handles user interaction. Each view has a corresponding view model.

View Model

The intermediary between the view and the data layers. Processes user input, manages state, and exposes data to the view.

Repository

Caches data models locally and exposes methods to fetch and write data models. Also provides a space for business logic such as data validation, preventing duplicates, and advanced searching beyond simple service data queries.

Data Model

Represents the structure of the data retrieved from repositories.

Service

Handles communication with external systems, such as REST APIs or Firebase.

Optional Components

Controllers

Manage global application state and configurations, such as routing and app-wide settings.

Use Case

Encapsulates specific business logic or operations that can be reused across different view models.

Domain Model

Represents business entities and rules, often used in conjunction with use cases.

Widgets

Reusable UI components that can be shared across different views.

Utils

Static helper functions that provide common functionality used throughout the codebase.

Data Model Extensions

Extensions on data models that provide computed properties.

Component Interactions

Controllers

Utils

ViewModel

View

UseCase

DomainModel

Repository

DataModel

DataModelExtensions

Service

DataSource

StatelessWidgets

Repository Structure

Expected repository structure (i.e., where to place these components) is defined in Flutter Development Standards: Repository Structure.

Deciding Where to Write Code Functionality

When deciding where to write new code, consider the following guidelines:

1. External Data Access

  • Never access anything outside the repository (e.g., Firestore, API calls) without using a Service.

2. Allowed Consumption Paths

Think of the standard components as "layers" in the architecture, with the data source at the "bottom" and the views at the "top".

  • Data Flow Rules:

    • Data flows in both directions, but may not "skip" a layer.

  • Component Knowledge Rules:

    • Components may only know information about the layers directly below them.

typical

typical

typical

typical

never allowed

allowed only if no repository

View

ViewModel

Repository

Service

DataSource

  • Services → usually consumed by Repositories and Global Controllers, can be consumed by View Models directly when data caching and validation is not needed.

  • Repositories → only consumed by View Models or Use Cases

    • Repositories may be injected into Use Cases using dependency injection.

    • Use cases using injected repositories should always provide a way to supply repositories in the constructor, so they can be tested with mock repositories.

  • Use Cases → only consumed by View Models

  • View Models → only consumed by Views

3. Business Logic Rules

  • Repositories, Models, Services, and Viewsno business logic

  • View Models, Controllers, and Use Cases → may contain business logic

    • Data Model Extensions → may contain small business logic implemented as getter functions (e.g., isAdmin, isDeveloper, isSoldThisYear).

4. Domain Model Rules

  • Domain models may only be created by Use Cases.

  • Utils may process domain models, but may never create them.

5. Use Case Organization

  • Group Use Cases by their related Domain Model. Naming should reflect the relationship if possible.

  • There should only be one use case per domain model.

  • Use abstract use cases only when working with abstract domain models. Avoid overly complex abstractions.

6. Utility Rules

  • Utils must be:

    • Static

    • Fully independent

    • Fully testable

7. Views + Model Access Rules

  • Non-stateless views (views with a View Model) should avoid directly accessing data from models to prevent tight coupling.

When to Break These Rules

On rare occasions, these rules may be broken. Whenever the rules are broken, code must be very thoroughly documented explaining the reason for the exception.

17 October 2025