---
description: "Core Flutter conventions for TaskFlow — always applied"
alwaysApply: true
---

# Flutter Core Standards — TaskFlow

## Const and performance
- Use `const` constructors wherever possible — compile-time guarantee of no rebuild
- Prefer `const` widgets at the leaf level: `const SizedBox.shrink()`, `const Padding(...)`
- Never use `const` with mutable values; lint: `prefer_const_constructors` is enabled

## Null safety
- Never use `!` (bang operator) unless you have a 100% safe runtime guarantee with a comment
- Prefer `??`, `?.`, and `if (x != null)` guards
- Use `required` for all non-nullable named parameters
- Never use `late` without a guarantee of initialisation before first access

## Widget lifecycle
- Override `dispose()` in every `StatefulWidget` that uses controllers, streams, or timers
- Cancel `StreamSubscription` in `dispose()`, not in `didUpdateWidget`
- Use `WidgetsBinding.instance.addPostFrameCallback` for post-build logic, not `Future.delayed(Duration.zero)`

## Naming conventions
- Files: `snake_case.dart`
- Classes: `PascalCase`
- Variables/functions: `camelCase`
- Constants: `kCamelCase` or `SCREAMING_SNAKE` for true compile-time constants
- Private members: `_camelCase`

## Imports
- Order: dart: → package: → relative
- Use relative imports within a feature; absolute for cross-feature
- Never import a feature's internal files from outside that feature

## Code quality
- Max function length: 40 lines. Extract widgets and helpers aggressively
- No `print()` in production code — use a logging package
- All `TODO:` comments must include a ticket number: `// TODO: PROJ-123 — fix this`
- Run `dart format` before every commit
