Skip to content

Coding Standards Document Demo 4

Megan235 edited this page Sep 30, 2026 · 3 revisions

Coding Standards Document

Overview

This document defines the coding conventions, architectural standards, and repository structure for Mealchemy. Compliance with these standards promotes consistency, clarity, maintainability, reliability, security, and efficiency across the codebase.

Table of Contents

Core Engineering Principles

DRY - Don't Repeat Yourself

Avoid duplicating logic. Shared behaviour should be extracted into reusable components, services, utilities, repositories, or widgets where appropriate.

DRY supports maintainability by ensuring that a change generally needs to be made in one place.

KISS - Keep It Simple

Prefer the simplest implementation that correctly meets the requirement. Simple solutions are easier to understand, test, review, maintain, and extend.

Unnecessary abstractions and complexity should be avoided.

Repository Structure

Mealchemy is maintained as a monorepo under the COS301-SE-2026 organisation.

The top-level repository structure is:

Mealchemy/
├── .github/
│   ├── workflows/                      ← CI/CD workflows
│   ├── codecov.yml                     ← Codecov configuration
│   ├── labeler.yml                     ← Pull request labelling
│   └── pull_request_template.md
├── .vscode/
│   └── settings.json
├── backend/
│   ├── src/main/java/com/mealchemy/
│   │   ├── allergens/
│   │   ├── auth/
│   │   ├── category/
│   │   ├── config/
│   │   ├── cuisinetype/
│   │   ├── dietaryrestrictions/
│   │   ├── engine/
│   │   ├── equipment/
│   │   ├── externallinks/
│   │   ├── ingredient/
│   │   ├── mealprep/
│   │   ├── moderation/
│   │   ├── nutritionalcalculator/
│   │   ├── nutritionalgoals/
│   │   ├── pantry/
│   │   ├── preference/
│   │   ├── profile/
│   │   ├── recipe/
│   │   ├── shared/
│   │   ├── shoppinglist/
│   │   ├── swipes/
│   │   ├── tags/
│   │   ├── unit/
│   │   ├── vault/
│   │   └── MealchemyApplication.java
│   ├── src/main/resources/
│   ├── src/test/                       ← Backend automated tests
│   ├── pom.xml
│   ├── mvnw
│   └── mvnw.cmd
├── database/                           ← Flyway SQL migrations
├── design-spec/                        ← Brand guide and wireframes
├── diagrams/
├── docs/
├── e2e/                                ← Maestro end-to-end flows
├── engine/                             ← Python recommendation engine
├── frontend/
│   ├── lib/
│   │   ├── core/
│   │   │   ├── connectivity/
│   │   │   ├── constants/
│   │   │   ├── providers/
│   │   │   ├── routes/
│   │   │   ├── services/
│   │   │   ├── shared_widgets/
│   │   │   ├── theme/
│   │   │   └── utils/
│   │   ├── features/
│   │   │   ├── admin/
│   │   │   ├── auth/
│   │   │   ├── cook_mode/
│   │   │   ├── dashboard/
│   │   │   ├── discovery/
│   │   │   ├── external_links/
│   │   │   ├── favourites/
│   │   │   ├── guided_discovery/
│   │   │   ├── help/
│   │   │   ├── ingredients/
│   │   │   ├── meal_plan/
│   │   │   ├── notifications/
│   │   │   ├── offline/
│   │   │   ├── pantry/
│   │   │   ├── preference/
│   │   │   ├── profile/
│   │   │   ├── recipe/
│   │   │   ├── shopping_lists/
│   │   │   ├── sizzles/
│   │   │   └── vault/
│   │   └── main.dart
│   ├── test/
│   ├── android/
│   ├── ios/
│   ├── macos/
│   └── pubspec.yaml
├── infrastructure/                     ← Docker and Compose configuration
├── landing-page/
├── nfr-tests/                           ← Non-functional test assets and scripts
├── wiki/                                ← Project standards and technical guidance
├── .env.example
├── .gitleaks.toml
├── .secrets.example
├── firebase.json
├── README.md
└── sonar-project.properties

The repository tree must be updated when significant packages, services, or top-level directories are introduced or removed.

Best Practices and Guidelines

  • Consistency: Follow the agreed naming conventions, architecture, module layouts, and style rules throughout the codebase.
  • Clarity: Use names that describe the purpose of classes, variables, methods, files, and components.
  • Separation of concerns: Presentation, business logic, state management, persistence, and external-service integration must remain appropriately separated.
  • Code review: Code must be reviewed before it is merged into a protected shared branch.
  • CI/CD: Required linting, testing, build, and coverage checks must pass before merging.
  • Error handling: Provide clear, user-friendly error messages without exposing implementation details.
  • Documentation: Update relevant technical and user-facing documentation when behaviour or contracts change.
  • Testability: Dependencies should be injectable or replaceable so automated tests do not require live external systems.
  • Scope: Pull requests should contain one coherent change and should avoid unrelated formatting or generated-file changes.

Dependency Management

  • Direct dependencies must be declared explicitly in the appropriate project configuration.
  • Reproducible resolved versions should be retained through approved lockfiles where the ecosystem supports them.
  • Dependency constraints and upgrades must be reviewed rather than changed incidentally.
  • Generated lockfiles must not be edited manually.
  • Unused dependencies should be removed.
  • Security-related dependency updates should be prioritised and tested.
  • A dependency should not be added when the required functionality can reasonably be achieved with an existing approved dependency or platform capability.

Generated Code

  • Generated files must not be edited manually.
  • Generated files must be recreated using the project-approved generation command after their source definitions change.
  • Generated database bindings, platform registrants, and lockfiles should not be modified by unrelated work.
  • Generated files should be committed only where required by the repository’s established policy.
  • Developers must inspect generated changes before committing them to ensure that no unrelated output has been introduced.

Git and Pull Request Standards

  • Branches use an agreed prefix such as feature/, fix/, docs/, test/, or refactor/.
  • Feature branches use the singular feature/ prefix rather than features/.
  • Branch names should identify the work clearly and may include the developer’s name where required by the team.
  • An example feature branch is feature/NutritionApiIntegration/SofiaFinlayson.
  • Commits should represent one coherent change.
  • Commit messages should be concise, descriptive, and use the team’s agreed conventional or imperative format.
  • Feature branches should incorporate the latest dev before final review.
  • Merge conflicts must preserve both the feature’s intended changes and valid changes already merged into dev.
  • Pull requests should explain:
    • what changed;
    • which tests were added or updated;
    • which commands were run;
    • whether manual testing was performed;
    • whether API, database, migration, security, or offline behaviour is affected;
    • any known limitations.
  • No secrets, credentials, personal configuration, or environment files may be committed.
  • No unrelated formatting, dependency, lockfile, generated-file, or platform changes should be included in a pull request.
  • Required CI checks and peer review must be completed before merging.

API and Data Contracts

  • Backend JSON field names use snake_case, for example category_id, recipe_id, created_at, and include_available_pantry_items.
  • Java uses lowerCamelCase component and field names internally.
  • Java DTOs use explicit @JsonProperty annotations where the JSON name differs from the Java name.
  • Dart models use lowerCamelCase fields internally and explicitly map snake_case JSON fields in fromJson methods and request bodies.
  • Frontend code must not assume that JSON integers and decimal values always have the same runtime numeric type.
  • Numeric parsing should safely accept compatible num values.
  • Optional and nullable API fields must be represented honestly.
  • Non-null assertions must not be used unless the API or application contract guarantees that the value exists.
  • Request and response DTOs are public API contracts and must not expose persistence entities directly.
  • API repositories must validate and map response data before exposing it to providers or widgets.
  • Contract changes must update:
    • backend DTOs;
    • controller and service tests;
    • frontend request construction;
    • frontend response mapping;
    • repository tests;
    • relevant technical documentation.
  • Coordinated frontend and backend pull requests should clearly document temporary dependencies or rollout order.
  • The frontend must not duplicate calculations or conversions that the backend contract defines as server responsibilities.

Frontend: Flutter and Dart

Naming Conventions

  • Classes, enums, extensions, and typedefs: Use UpperCamelCase.
  • Variables, parameters, methods, providers, and functions: Use lowerCamelCase, for example loadPantryItems().
  • Files and directories: Use lowercase_with_underscores, for example guided_discovery_provider.dart.
  • Feature folders: Use lowercase_with_underscores, for example shopping_lists.
  • Feature subfolders: Use lowercase names such as models/, providers/, repositories/, screens/, and widgets/.
  • Private declarations: Begin with an underscore.
  • Boolean names: Describe a true condition, for example isLoading, hasCachedData, and canDeleteShoppingList.
  • Acronyms: Follow normal Dart casing, for example apiService, recipeId, and usdaSourceId.
  • Test files: Mirror the source filename and end with _test.dart. For example, recipe_provider.dart corresponds to recipe_provider_test.dart.
  • Directory names are case-sensitive and must remain lowercase.
  • Existing names such as Molecules/ should be migrated to molecules/ when it is safe to update every reference.

Frontend Architecture

Flutter code uses a feature-first structure under lib/features/<feature>/.

  • Models represent application data.
  • Screens and widgets form the presentation layer.
  • Riverpod providers and notifiers coordinate repositories and expose application state.
  • Repositories provide access to API, mock, cached, or other data sources.
  • Feature-specific components should remain inside their owning feature.
  • Application-wide shared code belongs under lib/core/.
  • Screens and widgets must not construct HTTP requests directly.
  • Screens and widgets must not access local databases directly.
  • Business and data-access logic should not be duplicated across widgets.
  • Models should be immutable where practical.
  • Prefer constructors, final fields, and copyWith methods where state transitions require modified copies.

Repository and Provider Conventions

  • Define a repository interface when a feature supports API, mock, cached, or test implementations.
  • API repositories are responsible for endpoint paths, HTTP methods, request bodies, response validation, and JSON-to-model mapping.
  • Cached repositories should wrap or implement the relevant repository contract rather than introducing unrelated access patterns.
  • Providers are responsible for loading state, mutation state, invalidation, refresh, and updating state after successful operations.
  • Widgets must not instantiate production repositories directly.
  • Repository dependencies must be injectable or overridable.
  • Tests must use provider overrides or injected repository implementations.
  • Mock repositories must not silently replace API repositories in production configuration.
  • Successful mutations must update or invalidate all affected state so backend changes appear without restarting the application.
  • Repository methods should expose domain models rather than raw Dio responses or unvalidated JSON maps.

Asynchronous UI States

Every user-facing asynchronous feature must consider:

  • Loading state.
  • Successful data state.
  • Empty state.
  • Validation failure.
  • API or repository error.
  • Retry behaviour where appropriate.
  • Offline or cached state where applicable.

User-facing errors must be understandable and must not expose stack traces, raw exception messages, database details, secrets, or internal implementation information.

UI Implementation

  • Reuse colours, typography, spacing, components, and controls from the existing design system.
  • Avoid hard-coded colours and duplicate text styles where theme definitions exist.
  • Screens must remain usable on supported mobile screen sizes without overflow.
  • Scrollable content must remain reachable when fixed bottom controls are present.
  • Fixed controls must not permanently obscure page content.
  • Interactive controls should provide meaningful labels, tooltips, or semantics where appropriate.
  • Touch targets should remain large enough for practical mobile use.
  • Disabled controls must clearly communicate unavailable actions, particularly while offline.
  • User-facing wording should remain consistent across screens, tests, Help content, and API feedback.
  • Important user-facing changes should be manually inspected on a supported device or emulator.
  • Platform-specific functionality must be guarded appropriately and must not be called from unsupported platforms.

Frontend Structure

Each feature may contain:

lib/features/<feature>/
├── models/
├── providers/
├── repositories/
├── screens/
├── widgets/
└── utils/              ← Only where feature-specific utilities are required

Not every feature is required to contain every subfolder. Empty structural folders should not be created unnecessarily.

Style and Static Analysis

  • The project uses the configured rules in analysis_options.yaml.
  • flutter analyze must pass without errors or warnings before a pull request is submitted.
  • Analyzer warnings should be corrected rather than suppressed unless there is a documented technical reason.
  • Dart code should be formatted using the project-approved Dart formatter.
  • Unused imports, fields, parameters, and dependencies must be removed.
  • Non-null assertions should be avoided where proper null handling is possible.

Frontend Testing

  • Use flutter test for automated model, repository, provider, widget, and screen tests.
  • Use flutter test --coverage when generating LCOV coverage reports.
  • Tests should mirror the relevant feature structure under frontend/test/.
  • Focused tests should be run during implementation.
  • The complete affected feature suite must pass before a pull request is opened.
  • Tests must not require a live backend unless they are explicitly defined as integration or end-to-end tests.
  • API repository tests should use mocked Dio responses or interceptors.
  • Riverpod tests should use ProviderContainer, dependency overrides, or repository fakes.
  • Widget tests should cover important loading, success, empty, validation, error, retry, and offline states where relevant.
  • User-facing bug fixes should include regression tests where practical.
  • Required CI and configured coverage checks must pass before merging.

Common frontend commands include:

flutter pub get
flutter analyze
flutter test
flutter test --coverage
flutter test test/features/<feature>
flutter test test/features/<feature>/<test_file>.dart

Backend: Spring Boot and Java

Naming Conventions

  • Classes, records, interfaces, and enums: Use UpperCamelCase.
  • Variables, parameters, fields, and methods: Use lowerCamelCase, for example getPantryIngredientById().
  • Packages: Use lowercase names without underscores, for example shoppinglist and cuisinetype.
  • Constants: Use UPPER_SNAKE_CASE.
  • Incoming DTOs: Filenames end with Request.java.
  • Outgoing DTOs: Filenames end with Response.java.
  • Test files: Mirror the source class name and end with Test.java. For example, PantryService.java corresponds to PantryServiceTest.java.
  • Integration tests: Mirror the relevant class name and end with IntegrationTest.java, for example PantryControllerIntegrationTest.java.

Backend Structure

Feature packages under com.mealchemy separate controllers, DTOs, models, repositories, services, external adapters, and utilities where required.

Dependencies should generally flow:

Controller → Service → Repository
                     → External provider or adapter

A feature may use the following structure:

com/mealchemy/<feature>/
├── controller/
├── dto/
├── external/
├── model/
├── repository/
├── service/
└── util/

Only folders required by the feature should be created.

Non-feature-specific shared code, such as common enums, configuration, exception handling, and shared security behaviour, belongs in config/ or shared/.

Database migrations live in the top-level database/ directory.

Backend Implementation

  • Controllers handle HTTP concerns, request validation, authentication principals, response status codes, and delegation to services.
  • Controllers must not contain persistence or domain business logic.
  • Services contain business rules and transaction boundaries.
  • Repositories contain database-access operations and queries.
  • External-service access must use an approved provider, client, or adapter abstraction.
  • JPA entities represent persistence and must not be returned directly as public API responses.
  • Request and response DTOs should use Java records where immutability and framework compatibility allow.
  • Constructor injection is required.
  • Field injection must not be used.
  • Validation failures and domain errors should be translated through the shared exception-handling mechanism.
  • Transactions that modify an aggregate should either complete fully or roll back fully.
  • Nullable values must be handled explicitly.
  • Logging must provide useful diagnostic context without exposing secrets or personal data.

Database Migrations

  • Flyway migration filenames use V<number>__description.sql.
  • Existing migrations applied to a shared environment must not be edited.
  • Corrections to applied schemas must use a new migration.
  • Migrations should be reviewed for compatibility and possible data loss.
  • Destructive migrations require explicit review and a documented recovery or backup plan.
  • Database constraints, indexes, defaults, and nullability should match application assumptions.
  • Schema and DTO changes must be coordinated where they affect public API contracts.
  • Local database-volume deletion is a development reset procedure and must not be treated as a normal migration step.

Style and Linting

  • Backend Java follows the configured Google Java Style rules.
  • Style is enforced through the Maven Checkstyle plugin.
  • Required builds must fail when configured style checks fail.
  • Formatting changes unrelated to the feature should be avoided.

Backend Testing

  • JUnit 5 is used for backend automated testing.
  • Mockito is used to isolate service logic where appropriate.
  • Spring Boot Test, MockMvc, and Spring Security Test are used for relevant integration and controller testing.
  • Repository and migration behaviour should be tested against PostgreSQL where integration coverage is required.
  • Backend tests must not depend on uncontrolled personal database records.
  • Required Maven, Checkstyle, JaCoCo, and CI checks must pass before merging.
  • Coverage requirements are defined by the active Maven, JaCoCo, Codecov, and CI configuration.
  • The document must not claim a coverage threshold that is not actively configured and enforced.

Common backend commands include:

./mvnw test
./mvnw verify
./mvnw checkstyle:check

Recommendation Engine: Python

The recommendation-engine standards remain provisional until its linting, type-checking, testing, and CI configuration are finalised.

Naming Conventions

  • Files, functions, and variables use snake_case.
  • Classes use UpperCamelCase.
  • Constants use UPPER_SNAKE_CASE.

Style and Type Checking

  • Ruff should be used for linting and formatting where configured.
  • Mypy should be used for static type checking where configured.
  • Type hints should be added to public functions and important internal boundaries.

Testing

  • pytest and pytest-cov should be used where configured.
  • Recommendation logic should be tested using controlled, repeatable fixtures.
  • Automated tests must not depend on uncontrolled production data.
  • Coverage requirements are defined by the active pytest, Codecov, and CI configuration.

Security and Authentication

  • Secrets and credentials must not be committed to source control.
  • Authentication tokens must be stored only in the approved secure-storage implementation.
  • Tokens, passwords, JWT secrets, database credentials, and external API keys must never be logged or committed.
  • Secrets must be supplied through ignored environment files, deployment configuration, or approved CI secret storage.
  • Persisted user identity and token validity must be treated as separate concerns so cached data can be handled safely after token expiry.
  • Unreadable or invalid secure-storage values must be handled without crashing.
  • Authentication interceptors must avoid infinite refresh or retry loops.
  • A failed request must not clear user-scoped cached data unless the application has confirmed that a different user is signing in.
  • Protected backend endpoints must enforce authentication and authorisation.
  • User-facing errors must not expose tokens, credentials, internal stack traces, database details, or sensitive configuration.
  • Personal and user-specific data must only be accessible to authorised users.
  • Security-sensitive changes require relevant tests and explicit review.

Realtime Communication and WebSockets

  • Realtime communication uses authenticated STOMP over the /ws WebSocket endpoint.
  • JWTs must be supplied in the STOMP CONNECT frame, and subscriptions must remain user-scoped and explicitly allowlisted.
  • WebSocket connection, reconnection, parsing, and disposal logic belongs in a dedicated service rather than widgets.
  • Realtime events supplement persisted REST data; clients must reconcile authoritative state after missed connections.
  • Authentication, permitted destinations, reconnection, malformed payloads, and state updates require automated tests.

Offline and Local Storage

  • Offline application data is read-only unless a feature explicitly implements an approved and tested synchronisation strategy.
  • Mutation requests must be blocked centrally while offline.
  • The UI must disable or otherwise protect matching mutation controls while offline.
  • Cached application data must be scoped by user identity.
  • Signing in as a different user must switch cache namespaces.
  • Cached data must never leak between users.
  • Same-user reauthentication may preserve that user’s valid cache.
  • Partial or failed synchronisation must not replace valid cached aggregates with incomplete data.
  • Aggregates such as recipes and shopping lists with child records should be stored transactionally.
  • Cache freshness must be tracked independently for each collection and scope.
  • Database and image caches must use platform-appropriate cache storage.
  • Cache files should be excluded from cloud backup where supported.
  • Cached-data interfaces must clearly show offline status and freshness.
  • SQLite schemas and generated database files must be updated through the project-approved generation and migration process.
  • Tests must use temporary, isolated, or in-memory storage where practical.
  • Tests must not read or overwrite a developer’s actual secure-storage credentials or user cache.
  • Reconnection must restore online state and mutation controls when backend reachability is confirmed.

External Services

External services, including USDA, must be accessed through an adapter or provider abstraction rather than directly from controllers, screens, or widgets.

  • External response models must be translated into internal Mealchemy models.
  • Timeouts, missing fields, invalid responses, unavailable services, and rate limits must be handled explicitly.
  • External API keys must be supplied through ignored environment files or CI secrets.
  • Unit, provider, repository, and widget tests must mock external services and must not consume live API quotas.
  • External data provenance should be retained where required, for example through source_api and source_id.
  • External search results that require local catalogue information must complete the approved import and category-selection flow.
  • User-facing nutritional information derived from external data must include the approved accuracy disclaimer.
  • External-service failures must not crash the application or expose raw third-party error responses to users.

Recipe Media

  • Recipe photos and optional videos are stored as media URLs; videos currently support MP4 files up to 50 MB.
  • The frontend and backend must validate media type and size, while ownership validation remains a backend responsibility.
  • Media is uploaded directly to approved storage using backend-generated signed URLs, and recipe state is updated only after a successful upload.
  • Replacement, removal, and storage cleanup must preserve transaction integrity and must not delete unowned external media.
  • Media selection, display, and Sizzles playback belong in their feature-specific models, repositories, providers, services, and widgets, with loading, error, poster, playback, and upload behaviour covered by tests.

Nutrition and Measurement Data

  • Canonical quantity normalisation and unit conversion are backend responsibilities.
  • Weight is stored canonically in grams and volume in millilitres where defined by the backend contract.
  • The frontend displays values in the user’s preferred measurement system using values returned by the API.
  • The frontend must not duplicate backend nutritional scaling or unit-conversion logic.
  • General units that do not require conversion must remain consistent with the backend contract.
  • Nutritional calculator values may be displayed per recipe or per serving using the corresponding API response fields.
  • The frontend should render the six currently supported nutritional fields: calories, protein, carbohydrates, fat, fibre, and sodium.
  • Nutritional values should be formatted consistently without altering their underlying model values.
  • Ingredient calorie percentages may be derived from returned ingredient and recipe calorie totals.
  • Percentage calculations must safely handle zero total calories.
  • Nutritional values should be treated as estimates where they depend on external catalogue data or backend conversion assumptions.
  • The Nutrition interface must display the approved USDA accuracy disclaimer.

Maintenance

This is a living document. It must be reviewed and updated as the Mealchemy architecture, supported platforms, development workflow, dependencies, tooling, and CI configuration change.

The document should be updated when:

  • A new feature package or top-level service is introduced.
  • Repository structure changes.
  • API naming or data-contract standards change.
  • A new external service is added.
  • Offline, caching, authentication, or storage behaviour changes.
  • New linting, formatting, testing, coverage, or CI requirements are introduced.
  • Existing documented standards no longer match the implemented codebase.
  • The team agrees on revised naming, branching, review, or deployment practices.

Changes to this document should be reviewed by the team so that the standards remain accurate, practical, and consistently applied.


last updated 30 September 2026

Mealchemy

Team PUL5E · COS 301


Documentation

Demo 4
Demo 3
Demo 2
Demo 1

Setup Guides


Quick Links


Updated: 13 September 2026

Clone this wiki locally