Files
phone_login/CLAUDE.md
soragui c903430f75 refactor: implement Flutter best practices and proper architecture
- Create proper service layer with AuthService and FirebaseAuthService
- Implement UserModel for proper data representation
- Enhance AuthState with proper loading states and error handling
- Convert stateless widgets to stateful where appropriate
- Add proper form validation and user feedback mechanisms
- Implement comprehensive error handling and loading indicators
- Fix redirect logic in router for proper authentication flow
- Create theme system with light and dark themes
- Add shared components like LoadingIndicator
- Improve code organization following recommended architecture
- Add proper disposal of controllers and focus nodes
- Implement proper null safety handling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 06:35:57 +08:00

12 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

This is a Flutter application for phone number-based authentication. The app demonstrates a complete phone login flow with Firebase authentication, including phone number input, SMS verification, and authenticated user interfaces.

Architecture & Structure

The application follows a layered architecture with the following key components:

  • Authentication: Managed through Firebase Authentication with firebase_auth package. The AuthState class handles authentication state using Provider pattern.
  • Navigation: Implemented with go_router for declarative routing with authentication-aware redirects.
  • State Management: Uses provider package with ChangeNotifierProvider for global state management.
  • UI Components: Built with Flutter's Material Design widgets and enhanced with specialized packages:
    • intl_phone_field for international phone number input
    • pinput for PIN input fields on SMS verification

Directory Structure

lib/
├── main.dart              # App entry point
├── app.dart               # MaterialApp setup, theme, and routing
├── auth/                  # Authentication-related screens and logic
│   ├── auth_state.dart    # Manages authentication state
│   ├── phone_input_screen.dart
│   └── sms_verification_screen.dart
├── home/                  # Home screen
│   └── home_screen.dart
├── profile/               # User profile screen
│   └── profile_screen.dart

Key Dependencies

  • firebase_core: 4.3.0
  • firebase_auth: 6.1.3
  • go_router: ^17.0.1
  • provider: ^6.1.5+1
  • intl_phone_field: ^3.2.0
  • pinput: ^6.0.1

Common Development Commands

# Install dependencies
flutter pub get

# Run the application
flutter run

# Run tests
flutter test

# Analyze code
flutter analyze

# Format code
flutter format lib/

# Run linter
flutter analyze

# Build for Android
flutter build apk

# Build for iOS
flutter build ios

Flutter Development Best Practices (Based on rules.md)

Interaction Guidelines

  • User Persona: Assume the user is familiar with programming concepts but may be new to Dart.
  • Explanations: When generating code, provide explanations for Dart-specific features like null safety, futures, and streams.
  • Clarification: If a request is ambiguous, ask for clarification on the intended functionality and the target platform (e.g., command-line, web, server).
  • Dependencies: When suggesting new dependencies from pub.dev, explain their benefits.
  • Formatting: Use the dart_format tool to ensure consistent code formatting.
  • Fixes: Use the dart_fix tool to automatically fix many common errors, and to help code conform to configured analysis options.
  • Linting: Use the Dart linter with a recommended set of rules to catch common issues. Use the analyze_files tool to run the linter.

Code Style & Architecture

  • SOLID Principles: Apply SOLID principles throughout the codebase.
  • Concise and Declarative: Write concise, modern, technical Dart code. Prefer functional and declarative patterns.
  • Composition over Inheritance: Favor composition for building complex widgets and logic.
  • Immutability: Prefer immutable data structures. Widgets (especially StatelessWidget) should be immutable.
  • State Management: Separate ephemeral state and app state. Use a state management solution for app state to handle the separation of concerns.
  • Widgets are for UI: Everything in Flutter's UI is a widget. Compose complex UIs from smaller, reusable widgets.
  • Navigation: Use a modern routing package like go_router. See the navigation guide for a detailed example using go_router.

Code Quality Standards

  • Code structure: Adhere to maintainable code structure and separation of concerns (e.g., UI logic separate from business logic).
  • Naming conventions: Avoid abbreviations and use meaningful, consistent, descriptive names for variables, functions, and classes.
  • Conciseness: Write code that is as short as it can be while remaining clear.
  • Simplicity: Write straightforward code. Code that is clever or obscure is difficult to maintain.
  • Error Handling: Anticipate and handle potential errors. Don't let your code fail silently.
  • Styling:
    • Line length: Lines should be 80 characters or fewer.
    • Use PascalCase for classes, camelCase for members/variables/functions/enums, and snake_case for files.
  • Functions: Functions should be short and with a single purpose (strive for less than 20 lines).

Dart Best Practices

  • Effective Dart: Follow the official Effective Dart guidelines (https://dart.dev/effective-dart)
  • Null Safety: Write code that is soundly null-safe. Leverage Dart's null safety features. Avoid ! unless the value is guaranteed to be non-null.
  • Async/Await: Ensure proper use of async/await for asynchronous operations with robust error handling.
    • Use Futures, async, and await for asynchronous operations.
    • Use Streams for sequences of asynchronous events.
  • Pattern Matching: Use pattern matching features where they simplify the code.
  • Records: Use records to return multiple types in situations where defining an entire class is cumbersome.
  • Switch Statements: Prefer using exhaustive switch statements or expressions, which don't require break statements.
  • Exception Handling: Use try-catch blocks for handling exceptions, and use exceptions appropriate for the type of exception. Use custom exceptions for situations specific to your code.
  • Arrow Functions: Use arrow syntax for simple one-line functions.

Flutter Best Practices

  • Immutability: Widgets (especially StatelessWidget) are immutable; when the UI needs to change, Flutter rebuilds the widget tree.
  • Composition: Prefer composing smaller widgets over extending existing ones. Use this to avoid deep widget nesting.
  • Private Widgets: Use small, private Widget classes instead of private helper methods that return a Widget.
  • Build Methods: Break down large build() methods into smaller, reusable private Widget classes.
  • List Performance: Use ListView.builder or SliverList for long lists to create lazy-loaded lists for performance.
  • Isolates: Use compute() to run expensive calculations in a separate isolate to avoid blocking the UI thread, such as JSON parsing.
  • Const Constructors: Use const constructors for widgets and in build() methods whenever possible to reduce rebuilds.
  • Build Method Performance: Avoid performing expensive operations, like network calls or complex computations, directly within build() methods.

Application Architecture

  • Separation of Concerns: Aim for separation of concerns similar to MVC/MVVM, with defined Model, View, and ViewModel/Controller roles.
  • Logical Layers: Organize the project into logical layers:
    • Presentation (widgets, screens)
    • Domain (business logic classes)
    • Data (model classes, API clients)
    • Core (shared classes, utilities, and extension types)
  • Feature-based Organization: For larger projects, organize code by feature, where each feature has its own presentation, domain, and data subfolders. This improves navigability and scalability.

State Management

  • Built-in Solutions: Prefer Flutter's built-in state management solutions. Do not use a third-party package unless explicitly requested.
  • Streams: Use Streams and StreamBuilder for handling a sequence of asynchronous events.
  • Futures: Use Futures and FutureBuilder for handling a single asynchronous operation that will complete in the future.
  • ValueNotifier: Use ValueNotifier with ValueListenableBuilder for simple, local state that involves a single value.
  • ChangeNotifier: For state that is more complex or shared across multiple widgets, use ChangeNotifier.
  • ListenableBuilder: Use ListenableBuilder to listen to changes from a ChangeNotifier or other Listenable.
  • MVVM: When a more robust solution is needed, structure the app using the Model-View-ViewModel (MVVM) pattern.
  • Dependency Injection: Use simple manual constructor dependency injection to make a class's dependencies explicit in its API, and to manage dependencies between different layers of the application.
  • Provider: If a dependency injection solution beyond manual constructor injection is explicitly requested, provider can be used to make services, repositories, or complex state objects available to the UI layer without tight coupling.

Lint Rules

Include the package in the analysis_options.yaml file. Use the following analysis_options.yaml file as a starting point:

include: package:flutter_lints/flutter.yaml

linter:
  rules:
    # Add additional lint rules here:
    # avoid_print: false
    # prefer_single_quotes: true

Testing

  • Running Tests: To run tests, use the run_tests tool if it is available, otherwise use flutter test.
  • Unit Tests: Use package:test for unit tests.
  • Widget Tests: Use package:flutter_test for widget tests.
  • Integration Tests: Use package:integration_test for integration tests.
  • Assertions: Prefer using package:checks for more expressive and readable assertions over the default matchers.

Testing Best practices

  • Convention: Follow the Arrange-Act-Assert (or Given-When-Then) pattern.
  • Unit Tests: Write unit tests for domain logic, data layer, and state management.
  • Widget Tests: Write widget tests for UI components.
  • Integration Tests: For broader application validation, use integration tests to verify end-to-end user flows.
  • integration_test package: Use the integration_test package from the Flutter SDK for integration tests. Add it as a dev_dependency in pubspec.yaml by specifying sdk: flutter.
  • Mocks: Prefer fakes or stubs over mocks. If mocks are absolutely necessary, use mockito or mocktail to create mocks for dependencies. While code generation is common for state management (e.g., with freezed), try to avoid it for mocks.
  • Coverage: Aim for high test coverage.

Visual Design & Theming

  • UI Design: Build beautiful and intuitive user interfaces that follow modern design guidelines.
  • Responsiveness: Ensure the app is mobile responsive and adapts to different screen sizes, working perfectly on mobile and web.
  • Navigation: If there are multiple pages for the user to interact with, provide an intuitive and easy navigation bar or controls.
  • Typography: Stress and emphasize font sizes to ease understanding, e.g., hero text, section headlines, list headlines, keywords in paragraphs.
  • Theming: Implement support for both light and dark themes, ideal for a user-facing theme toggle (ThemeMode.light, ThemeMode.dark, ThemeMode.system).

Code Generation

  • Build Runner: If the project uses code generation, ensure that build_runner is listed as a dev dependency in pubspec.yaml.
  • Code Generation Tasks: Use build_runner for all code generation tasks, such as for json_serializable.
  • Running Build Runner: After modifying files that require code generation, run the build command:
dart run build_runner build --delete-conflicting-outputs

Important Notes

  • Authentication flow is implemented using Firebase phone authentication
  • The router includes redirect logic based on authentication state
  • UI adapts based on login status (logged in/out views)
  • Phone input includes international country codes
  • SMS verification screen accepts 6-digit PIN codes