emotico
2026 · MVP

Developer Guide

Tài liệu này dành cho developer mới join dự án Emotico. Đọc từ đầu đến cuối mất khoảng 15 phút.


Tech Stack

LayerTechnologyVersion
Mobile frameworkFlutter3.44.0
LanguageDart3.12.0
State managementflutter_riverpod^3.3.1
Modelsfreezed^3.0.0
Serializationjson_serializablelatest
Navigationgo_router^17.2.3
Backendsupabase_flutter^2.9.1
Monorepo toolMelos7.7.0

Cấu trúc Monorepo

emotico-2026/
├── packages/
│   ├── emotico_core/         ← Domain models + abstract repo interfaces (pure Dart)
│   ├── emotico_ui/           ← Design system: colors, typography, shared widgets
│   ├── emotico_data/         ← Supabase implementations of emotico_core interfaces
│   └── emotico_sdk/          ← Future: SSO OAuth2 bridge for school apps (skeleton)
├── apps/
│   ├── emotico_app/          ← Main student app
│   └── white_label_template/ ← Future: school white-label (skeleton)
├── supabase/
│   └── migrations/           ← SQL migration files
└── docs/
    ├── wiki/                 ← This wiki
    └── superpowers/          ← Internal specs and implementation plans

Nguyên tắc phân tách:

  • emotico_core — không import bất kỳ Flutter/Supabase package nào. Pure Dart.
  • emotico_data ��� implement các interface từ emotico_core bằng Supabase
  • apps/emotico_app — inject implementations qua ProviderScope.overrides

Setup

1. Flutter SDK

# Flutter SDK được pin tại path cố định trên máy dev
export PATH="$PATH:/Volumes/My Passport/Claude Pro/.flutter-sdk/flutter-stable/bin"
flutter --version
# Flutter 3.44.0 • Dart 3.12.0

2. Melos (monorepo tool)

dart pub global activate melos
melos bootstrap
# Installs all dependencies và links local packages với nhau

3. Code generation

melos run generate
# Chạy build_runner trên tất cả packages (freezed + json_serializable)

Chạy App

Credentials được inject qua --dart-define. Không bao giờ hardcode vào code.

flutter run \
  --dart-define=SUPABASE_URL=https://<project-ref>.supabase.co \
  --dart-define=SUPABASE_ANON_KEY=<anon-key>

Xin credentials từ lead dev. Không có credentials thì app crash khi khởi động.


Key Patterns

1. Freezed Models ��� dùng sealed class

// ✅ ĐÚNG — Freezed v3 yêu cầu 'sealed class'
@freezed
sealed class User with _$User {
  const factory User({
    required String id,
    required String email,
    @Default('student') String role,
    @Default('vi') String languagePref,
  }) = _User;
  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}

// ❌ SAI — compile error với Freezed v3
class User with _$User { ... }

2. Repository Pattern

// emotico_core — chỉ định nghĩa interface, không import Supabase
abstract interface class AuthRepository {
  User? get currentUser;
  Future<User> signIn({required String email, required String password});
  Future<void> signOut();
}

// emotico_data — implement với Supabase
class SupabaseAuthRepository implements AuthRepository {
  final SupabaseClient _client;
  SupabaseAuthRepository(this._client);

  @override
  Future<User> signIn({required String email, required String password}) async {
    final res = await _client.auth.signInWithPassword(email: email, password: password);
    return _fetchProfile(res.user!.id, email);
  }
}

// apps/emotico_app/lib/main.dart — inject
ProviderScope(
  overrides: [
    authRepositoryProvider.overrideWithValue(
      SupabaseAuthRepository(Supabase.instance.client),
    ),
  ],
  child: const EmoticoApp(),
)

3. Snake-to-Camel cho Enums từ DB

// packages/emotico_data/lib/src/util/snake_to_camel.dart
String snakeToCamel(String snake) {
  final parts = snake.split('_');
  return parts.first +
      parts.skip(1).map((p) => p[0].toUpperCase() + p.substring(1)).join();
}

// Dùng khi parse DB enum string:
// 'single_choice' → 'singleChoice' → QuizQuestionType.singleChoice
final type = QuizQuestionType.values.byName(snakeToCamel(row['question_type']));

4. JsonEnum cho Enum Serialization

@JsonEnum(fieldRename: FieldRename.snake)
enum EmotionElement { wood, fire, earth, metal, water }
// DB 'wood' → EmotionElement.wood, serialize ngược lại đúng tự động

Test Commands

# Core models + providers (pure Dart, nhanh)
dart test packages/emotico_core

# Data layer (cần flutter runner vì supabase_flutter có Flutter deps)
flutter test packages/emotico_data

# Widget tests cho app
flutter test apps/emotico_app

# Analyze toàn bộ monorepo
melos run analyze

Database & Migrations

# Apply migrations lên Supabase cloud
supabase db push --project-ref <project-ref>

# Migration files:
supabase/migrations/
  20260523000001_initial_schema.sql     ← profiles, emotions, emotion_entries, quizzes, quests
  20260523000002_seed_emotions.sql      ← 10 sample emotions (5 positive, 5 negative)
  20260523000003_add_schools_and_tenant_fields.sql  ← multi-tenancy fields

Lưu ý quan trọng khi viết migrations:

  • Dùng gen_random_uuid()không dùng uuid_generate_v4() (không tương thích PG15)
  • Mọi bảng đều có RLS enabled — luôn test với authenticated user
  • emotion_entries chỉ owner mới đọc/ghi được (owner-only RLS)

Design System

// packages/emotico_ui/lib/src/theme/colors.dart
EmoticoColors.primary    // #FFB223 (cam vàng)
EmoticoColors.secondary  // #23AEFF (xanh dương)
EmoticoColors.wood       // Mộc — xanh lá
EmoticoColors.fire       // Hỏa — đỏ cam
EmoticoColors.earth      // Thổ — vàng nâu
EmoticoColors.metal      // Kim — xám bạc
EmoticoColors.water      // Thủy — xanh dương

// Fonts
// MomoTrustDisplay — display/headline
// PlusJakartaSans — body/label (Regular 400, Medium 500, SemiBold 600, Bold 700)

Navigation Map

/                     → redirect based on auth state
/onboarding           → OnboardingScreen (first launch)
/login                → LoginScreen
/signup               → SignupScreen
/forgot-password      → ForgotPasswordScreen
/checkin              → CheckinScreen (standalone, no bottom nav)
/shell                → MainShell (5-tab bottom nav)
  /home               → HomeScreen
  /dictionary         → DictionaryListScreen
    /dictionary/:id   → DictionaryDetailScreen
  /quiz               → QuizListScreen
    /quiz/:id         → QuizPlayScreen
    /quiz/:id/result  → QuizResultScreen
  /quest              → QuestScreen
  /profile            → ProfileScreen
    /profile/edit     → EditProfileScreen

Onboarding Checklist

  • Clone repo và setup Flutter SDK path (xem mục Setup)
  • Chạy melos bootstrap
  • Xin Supabase credentials từ lead dev
  • Chạy app: flutter run --dart-define=SUPABASE_URL=... --dart-define=SUPABASE_ANON_KEY=...
  • Đọc packages/emotico_core/lib/src/ — models + repository interfaces
  • Đọc apps/emotico_app/lib/app/router.dart — navigation map
  • Chạy full test suite và đảm bảo pass:
    dart test packages/emotico_core
    flutter test packages/emotico_data
    flutter test apps/emotico_app
    
  • Đọc spec liên quan tại docs/superpowers/specs/ trước khi build tính năng mới