# 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 (3–6 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 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 = ['a', 'b']; // typed list * * final map = {'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