eutopic/LEARNING-SPEC.md

215 lines
9 KiB
Markdown
Raw Normal View History

# LEARNING-SPEC.md
context for any agent writing flutter code for eutopic.
## who is reading this code
a junior developer. no flutter or dart experience. basic understanding of frontend concepts (html/css level). goal: understand the code well enough to write business logic, modify screens, and eventually own the codebase. not a throwaway learning exercise — this is the real app.
## annotation requirements
every file must include three layers of annotation. this is non-negotiable.
### 1. file-top architecture comment
a short paragraph (36 sentences) at the top of every file, inside a block comment. must explain:
- what this file is and what it does
- why it exists as a separate file (not just "it's a widget")
- how it connects to the rest of the app (what calls it, what it calls)
example format:
```dart
/*
* feed_screen.dart
*
* the main home feed. this is what the user sees after login — a chronological
* list of photo posts from people they follow. it lives at the '/' route and is
* the first tab in the bottom nav bar.
*
* this screen owns fetching the post list from the api and passing individual
* posts down to PostCard widgets. it does not know how to render a post — that
* is PostCard's job. separation of concerns: screen = data, widget = display.
*/
```
### 2. boilerplate explanation comments
every structural/architectural decision in the boilerplate must have a comment explaining *why*, not just *what*. target: someone who has never seen flutter before can read this file and understand the pattern.
things that always need explanation:
- `StatelessWidget` vs `StatefulWidget` — explain the difference and why this file uses one over the other
- `BuildContext context` — what it is and why it's passed everywhere
- `const` constructors — why they exist, what they do for performance
- `@override` — what it means in dart
- `super.key` — what keys are and why the constructor takes one
- `Widget build(BuildContext context)` — what this method is and when flutter calls it
- any `initState` / `dispose` usage — explain the lifecycle
- any `setState(() {})` — explain what it triggers and why it's needed
- named parameters with `{}` braces vs positional — explain the difference
- `required` keyword — explain what it enforces
- `?` nullable types — explain dart's null safety model briefly on first use per file
### 3. logic TODO blocks
for every section the developer will fill in themselves, write a TODO comment that includes:
- a plain-english description of what needs to happen
- a complete dart syntax example showing the pattern to use (as a comment)
- any gotchas or things to watch out for
format:
```dart
// TODO: [plain english description]
//
// example:
// [complete working dart code snippet]
//
// note: [any gotcha or important thing to know]
```
the example must be real, working dart — not pseudocode. it should be close enough to the actual task that the developer can adapt it directly.
## hard sections — write fully, annotate heavily
these three areas are too complex for a junior developer to implement from a TODO. write them completely, but annotate every non-obvious line as if explaining to someone who has never seen async dart or flutter internals:
1. **tus resumable upload** (`shared/services/upload_service.dart`)
- background isolates, tus_client package usage, progress callbacks
- explain what an isolate is, why uploads need one, what happens without it
2. **go_router deep-link invite handling** (`shared/router/app_router.dart`)
- the `redirect` callback, how deep links arrive, how the invite code is extracted from the uri
- explain what a deep link is and the ios/android app link mechanism briefly
3. **story auto-advance timer + gesture layer** (`features/stories/story_viewer_screen.dart`)
- `Timer.periodic`, `AnimationController` for the progress bar, `GestureDetector` for tap-left/tap-right and swipe-down-to-exit
- explain the animation controller lifecycle and why dispose() matters here
## dart syntax reference (include in every file)
every file must include this block, verbatim, near the top after the file-top architecture comment. it is a standing reference so the developer never needs to leave the file to look up basic syntax.
```dart
/*
* dart syntax reference — patterns used in this file
*
* variables
* final String name = 'ada'; // runtime constant — set once, never reassigned
*
* const int max = 10; // compile-time constant — value must be known at build time
*
* String? bio; // nullable — this variable can be null (dart null safety)
*
* late String token; // late — will be assigned before first use, not at declaration
*
* functions
* String greet(String name) { return 'hi $name'; } // regular function
*
* String greet(String name) => 'hi $name'; // arrow shorthand — same as above, one expression only
*
* void log({required String msg}) { ... } // named parameter — caller writes: log(msg: 'x')
*
* void log({String msg = 'hello'}) { ... } // named parameter with default value
*
* void log(String msg) { ... } // positional parameter — caller writes: log('x')
*
* async
* Future<String> fetchName() async { // async function — returns a Future (like a JS Promise)
* final result = await apiCall(); // await pauses here until the Future resolves
* return result;
* }
*
* lists & maps
* final items = <String>['a', 'b']; // typed list
*
* final map = <String, int>{'apples': 3}; // typed map (like a JS object/dict)
*
* for (final item in items) { print(item); } // for-in loop over a list
*
* items.map((x) => x.toUpperCase()).toList() // transform every item (like JS .map())
*
* items.where((x) => x != 'a').toList() // keep items matching condition (like JS .filter())
*
* classes
* class Post {
* final String id;
* final String? caption; // optional field — may be null
* const Post({required this.id, this.caption}); // const constructor, named params
* }
*
* null safety
* bio?.length // safe access — returns null if bio is null, not an error
*
* bio ?? 'no bio' // fallback — use 'no bio' if bio is null
*
* bio! // force-unwrap — crashes if null. avoid unless certain.
*
* control flow
* if (x != null) { ... } else { ... }
*
* final label = isOwn ? 'you' : user.name; // ternary — shorthand if/else (same as JS)
*
* switch (tag) {
* case 'event': ... break;
* default: ...
* }
*
* string interpolation
* 'hello $name' // insert a variable directly
*
* 'count: ${list.length}' // insert an expression — use braces when it's more than a variable
*/
```
this block should appear in every file. agents must not remove or shorten it — the developer is learning dart as they go and will refer to it repeatedly.
## style rules
- use lowercase prose in comments (matches the project's communication style)
- no marketing language or enthusiasm ("great!", "easy!", "simply")
- be direct. if something is genuinely complex, say so — don't oversimplify
- prefer short sentences over long ones
- comment *why* over *what* — the code shows what, the comment shows why
## file order
write files in this order so concepts build on each other:
1. `lib/main.dart`
2. `lib/app.dart`
3. `lib/core/theme/app_colors.dart`
4. `lib/core/theme/app_theme.dart`
5. `lib/shared/models/` — all model files
6. `lib/core/router/app_router.dart` — hard section
7. `lib/shared/services/api_client.dart`
8. `lib/shared/services/auth_service.dart`
9. `lib/shared/services/upload_service.dart` — hard section
10. `lib/core/widgets/bottom_nav_bar.dart`
11. `lib/shared/widgets/` — shared widgets (photo_viewer, emoji_picker_sheet, loading_indicator, error_view)
12. `lib/features/feed/` — full feature, end to end (reference pattern for all other features)
13. `lib/features/onboarding/`
14. `lib/features/compose/`
15. `lib/features/posters/`
16. `lib/features/stories/` — hard section (story_viewer_screen.dart)
17. `lib/features/profile/`
18. `lib/features/settings/`
19. `lib/features/feedback/`
## project context
- app: eutopic — photo-first social app, invite-only, no notifications, no DMs, no algorithm
- stack: flutter (dart), go_router, tus_client, lottie animations
- folder structure: feature-first (see `docs/ARCHITECTURE.md` — frontend section)
- full concept: `docs/CONCEPT.md`
- screen/navigation spec: `model-tests/02-flutter-folder-structure.md`
- no notification-related code anywhere — this is a hard constraint
- no push alerts, no unread badges, no FCM/APNs
## what counts as done
a file is complete when:
- it compiles without errors
- all three annotation layers are present
- every TODO block has a working dart example
- hard sections are fully implemented with line-level annotation
- no notification-related imports or widgets exist anywhere