eutopic/LEARNING-SPEC.md

9 KiB
Raw Permalink Blame 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:

/*
 * 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:

// 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 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