Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions .llmrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@

This file provides essential context for LLMs working on the Simplications project.

## Instruction Priority

- `AGENTS.md` is the authoritative policy file for AI agent behavior.
- Use this `.llmrc` as implementation context and project guidance.
- If `.llmrc` and `AGENTS.md` differ, follow `AGENTS.md`.

## Project Overview

**Simplications** is a Flutter application that helps users evaluate privacy and security risks in their smart home, room-by-room. Users select a room, add devices, answer targeted security questions, and receive actionable recommendations based on BSI (German Federal Office for Information Security) guidelines.

**Language**: German (Deutsch) - all UI text is in German
**Language**: Multi-language UI with German default (`de`, `en`, `cs`, `pl`, `fr`, `nl`, `da`)
**Framework**: Flutter 3.11.5+, Dart
**Platform**: Cross-platform (Android, iOS, Web, macOS, Windows, Linux)
**Target Users**: German-speaking users concerned about smart home privacy
Expand Down Expand Up @@ -114,8 +120,15 @@ lib/

### Data Persistence

- **Current**: Transient (lost on app restart)
- **Planned Enhancement**: SharedPreferences or local SQLite storage
- **Current**: Local persistence via SharedPreferences (`SurveyState`)
- **Planned Enhancement**: Optional richer local storage/migrations if needed

### Build Number Policy (LLM Work)

- Any LLM edit to core app files under `lib/` must bump the build number in `pubspec.yaml`.
- Bump only the integer after `+` in `version` (for example, `1.0.0+2` -> `1.0.0+3`).
- Changes limited to non-core paths like `test/` and platform folders do not require a bump.
- Full policy details are in `AGENTS.md`.

## Important Code Patterns

Expand All @@ -138,7 +151,7 @@ lib/
- Material Design 3
- Primary color: Teal (#00695C)
- Theme accessed via `Theme.of(context).colorScheme`
- All text in German - search for `const Text` to find strings for localization
- Keep German-first UX, but preserve and maintain all supported locales in `lib/l10n/app_localizations.dart`

### Screen Navigation

Expand Down Expand Up @@ -180,7 +193,7 @@ lib/

## Naming Conventions

### German Text (All UI)
### German Text (Primary UX)

- Room names: "Wohnzimmer", "Küche", "Schlafzimmer"
- Device names: "Sprachassistent", "Smarte Kamera", "Intelligenter Thermostat"
Expand Down Expand Up @@ -219,7 +232,7 @@ Before submitting changes:
- [ ] Device-specific questions appear for tested device types
- [ ] Risk score updates when questions are answered
- [ ] Device-specific actions appear in evaluation screen
- [ ] UI text is German throughout
- [ ] German UX remains correct and localized keys are preserved across all supported locales
- [ ] Material 3 teal theme is applied consistently

## Troubleshooting
Expand Down Expand Up @@ -260,8 +273,8 @@ Before submitting changes:
- ✅ Added 30+ BSI-based security actions mapped to device types
- ✅ Fixed all lint warnings (0 issues in `flutter analyze`)
- ✅ Added device-specific evaluation logic
- 🟡 Future: Add persistence layer (SharedPreferences/SQLite)
- 🟡 Future: Add multi-language support
- ✅ SharedPreferences-based persistence is active
- ✅ Multi-language support is active

---

Expand Down
132 changes: 132 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Simplications – AI Agent Instructions

This file is the single source of truth for any LLM or AI coding agent
(GitHub Copilot, Codex, Claude, Gemini, etc.) working in this repository.
Read this file before making any changes. Follow these rules strictly.

`.llmrc` may provide additional implementation context, but if there is any
conflict, this file (`AGENTS.md`) takes precedence.

---

## Build Number Policy

**Rule: every LLM edit to a core app file MUST increment the build number
in `pubspec.yaml` before (or as part of) the same commit/change set.**

### What counts as a core file?

Any file under `lib/` (recursively), including:

| File | Description |
|---|---|
| `lib/main.dart` | App entry point |
| `lib/data/catalog_data.dart` | Static catalog: rooms, devices, questions, actions |
| `lib/models/device.dart` | Risk scoring, question logic, action recommendations |
| `lib/models/survey_state.dart` | Assessment state and persistence |
| `lib/models/room.dart` | Room model |
| `lib/l10n/app_localizations.dart` | Localization (all supported languages) |
| `lib/l10n/language_controller.dart` | Language switch persistence |
| `lib/screens/*.dart` | All wizard and result screens |
| `lib/widgets/*.dart` | Reusable UI components |

`test/`, `android/`, `ios/`, `web/`, `windows/`, `linux/`, `macos/` are NOT
core files. Changing only those files does not require a build number bump.

### How to bump

In `pubspec.yaml`, increase the integer after `+` in the `version` line:

```yaml
# Before
version: 1.0.0+3

# After (any LLM change to a core file)
version: 1.0.0+4
```

Never skip numbers. Never decrease the build number.

---

## Project Overview

**Simplications** is a Flutter privacy-assessment app. Users walk through
their smart-home rooms, select devices, answer privacy questions, and receive
a risk score with concrete action recommendations.

- **Platform targets**: Android, iOS, Web, Windows
- **Languages**: Dart / Flutter
- **Supported locales**: `de` (default), `en`, `cs`, `pl`, `fr`, `nl`, `da`
- **State persistence**: `SharedPreferences` via `SurveyState`
- **No backend** – all data stays on-device

---

## Architecture Summary

```
lib/
main.dart — App entry, theming, locale wiring
data/catalog_data.dart — Catalog of rooms, device templates, localisation helpers
models/
device.dart — DeviceTemplate, DeviceInstance, risk engine, actions
survey_state.dart — Central state + SharedPreferences persistence
room.dart — Room model
l10n/
app_localizations.dart — All UI strings for all locales (source of truth)
language_controller.dart — User language preference + persistence
screens/ — Wizard flow: welcome → rooms → devices → questionnaire → summary
widgets/ — Shared UI components (dialogs, language switcher, …)
test/
widget_test.dart — App launch smoke test
icon_serialization_test.dart — Icon persistence + survey state round-trips
device_risk_scoring_test.dart — Risk engine unit tests
app_localizations_test.dart — Localization fallback and interpolation tests
language_controller_test.dart — Language persistence tests
summary_screen_test.dart — Summary screen rendering tests
```

---

## Key Conventions

### Localization
- Never hardcode user-visible strings in widgets.
- All strings live in `lib/l10n/app_localizations.dart` in the
`_localizedValues` map, under every supported locale.
- When adding a string, add it under **all** locales (`de`, `en`, etc.).
- The fallback chain is: requested locale → `en` → `de` → fallback param → key.

### Risk scoring
- Base risk is set per `DeviceTemplate.baseRiskScore` in `catalog_data.dart`.
- Per-question penalties are defined in `DeviceInstance.riskScore` (device.dart).
- Score is clamped to `[0, 100]`.
- Child-bedroom room adds a 10-point bonus.
- Dont-know answers use a reduced penalty (roughly half of the "no" penalty).

### Testing
- Run `flutter test` before finishing any task involving core files.
- Run `flutter analyze` to catch static issues.
- When changing risk scoring logic, update `test/device_risk_scoring_test.dart`
with the new expected values.

### Code style
- 2-space indentation, Dart conventions (PascalCase classes, camelCase members).
- Group imports: dart → flutter → package → relative.
- Zero analyzer errors and warnings required.

### Pull request titles
- Pull request titles should follow this template: `<type>: <short description>`.
- Use a lowercase type prefix such as `feat`, `fix`, `docs`, `refactor`, `test`, or `chore`.
- Examples: `feat: add summary export`, `fix: preserve selected room state`.

---

## Checklist Before Finishing Any Task

- [ ] Build number bumped if any `lib/` file was changed
- [ ] `flutter test` passes (all tests green)
- [ ] `flutter analyze` passes (zero errors/warnings)
- [ ] Localization keys added in all locales if UI text was added/changed
- [ ] No hardcoded user-visible strings in widgets
16 changes: 16 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,22 @@ lib/
- Assessment flow is state-driven via `SurveyState`.
- Progress and selected settings are persisted locally with SharedPreferences.

## Build Number Policy

Every change — by a human contributor or an AI agent — to any **core app file**
(`lib/` and its subdirectories) must include a build number increment in
`pubspec.yaml` as part of the same commit.

```yaml
# Increment the integer after +
version: 1.0.0+3 → version: 1.0.0+4
```

Files outside `lib/` (`test/`, platform directories, `pubspec.yaml` itself
when only bumping the build number, docs) do not require a bump.

> AI agents: this rule is also enforced in `AGENTS.md` at the repo root.

## Workflow

1. Create a feature branch:
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ publish_to: 'none'
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1
version: 1.0.0+2

environment:
sdk: ^3.11.5
Expand Down
57 changes: 57 additions & 0 deletions test/app_localizations_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:simplications/l10n/app_localizations.dart';

void main() {
group('AppLocalizations.translate', () {
test('falls back to English when locale is unsupported', () {
final value = AppLocalizations.translate(
'start',
locale: const Locale('xx'),
);

expect(value, 'Start');
});

test('replaces parameter placeholders', () {
final value = AppLocalizations.translate(
'dontKnowHint',
locale: const Locale('en'),
params: {'count': '2', 'suffix': 's'},
);

expect(value.contains('2 answer'), isTrue);
expect(value.contains('"I don\'t know"'), isTrue);
});

test('uses explicit fallback for unknown keys', () {
final value = AppLocalizations.translate(
'missing_key_example',
locale: const Locale('en'),
fallback: 'fallback-value',
);

expect(value, 'fallback-value');
});

test('returns key when unknown key has no fallback', () {
final value = AppLocalizations.translate(
'missing_key_example',
locale: const Locale('en'),
);

expect(value, 'missing_key_example');
});
});

group('AppLocalizations.activate', () {
test('updates active language code', () {
AppLocalizations.activate(const Locale('pl'));
expect(AppLocalizations.activeLanguageCode, 'pl');

AppLocalizations.activate(const Locale('de'));
expect(AppLocalizations.activeLanguageCode, 'de');
});
});
}
Loading
Loading