-
Notifications
You must be signed in to change notification settings - Fork 1
328-스케줄-겹침-경고: 일정 겹침 경고 기능 추가 #331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jjoonleo
wants to merge
28
commits into
main
Choose a base branch
from
328-스케줄-겹침-경고
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
The head ref may contain hidden characters: "328-\uC2A4\uCF00\uC904-\uACB9\uCE68-\uACBD\uACE0"
Open
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
4023df4
feat: add LoggingTransformer for request payload logging
jjoonleo 7c17811
feat: add finishSchedule functionality to manage schedule completion
jjoonleo 87ceaa2
feat: implement ScheduleFinished event to handle schedule completion
jjoonleo 3d50539
feat: add doneStatus to schedule models for completion tracking
jjoonleo 72c5a4f
fix: remove unnecessary elapsedTime assignment in PreparationWithTime…
jjoonleo 6def5cc
fix: update finishSchedule method to use PUT request for schedule com…
jjoonleo e64381d
feat: enhance AlarmScreen navigation and state management for prepara…
jjoonleo e71d9fd
feat: conditionally display edit action in schedule detail based on s…
jjoonleo 8b37cc4
feat: add coverage reports and assets for improved testing visibility
jjoonleo b1885a0
feat: add copyWith method to ScheduleEntity for improved immutability
jjoonleo 0643250
feat: enhance schedule completion handling in ScheduleRepositoryImpl
jjoonleo b70d4b5
feat: implement LoadSchedulesByDateUseCase and refactor schedule load…
jjoonleo a0e5102
feat: add preparation stream functionality to PreparationRepositoryImpl
jjoonleo 66d267b
feat: integrate LoadPreparationByScheduleIdUseCase and enhance GetNea…
jjoonleo 7b417dd
feat: implement GetNextScheduleWithPreparationUseCase and LoadNextSch…
jjoonleo 5982d4f
feat: refactor LoadNextScheduleWithPreparationUseCase to load prepara…
jjoonleo 50cdf38
feat: enhance schedule overlap handling and localization updates
jjoonleo 1b3bf53
Merge remote-tracking branch 'origin' into 328-스케줄-겹침-경고
jjoonleo 194acf0
feat: add nextScheduleName to schedule form state and events
jjoonleo 76265cc
docs: add AI coding agent instructions and project architecture overview
jjoonleo 1cd7297
refactor(domain): rename and update schedule preparation use cases
jjoonleo 7b3ab4c
feat(l10n): update schedule overlap error messages
jjoonleo cca733e
feat(schedule-create): implement adjacent schedule overlap detection
jjoonleo c919729
feat(schedule-create): update moving and spare time steps for overlap…
jjoonleo 8e677a2
feat(schedule-create): inject AuthBloc into ScheduleFormBloc
jjoonleo 4290bbc
feat(schedule-overlap): introduce schedule overlap warning threshold …
jjoonleo e68a8b5
feat(schedule-create): initialize cubits after submitting each page a…
jjoonleo d2eb115
feat(schedule-overlap): implement schedule overlap checks in Schedule…
jjoonleo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,268 @@ | ||
| # OnTime Flutter Project - AI Coding Agent Instructions | ||
|
|
||
| ## Architecture Overview | ||
|
|
||
| This is a **Flutter app** following **Clean Architecture** with three layers: | ||
|
|
||
| - **Presentation** (`lib/presentation/`): Screens, widgets, BLoC/Cubit state management | ||
| - **Domain** (`lib/domain/`): Business logic, entities, use cases, repository interfaces | ||
| - **Data** (`lib/data/`): Repository implementations, data sources (remote/local), DAOs, database tables | ||
|
|
||
| Data flows: UI → BLoC → UseCase → Repository → DataSource → API/DB | ||
|
|
||
| ## Critical Build Commands | ||
|
|
||
| ```bash | ||
| # ALWAYS run after pulling or modifying data models, entities, or DI | ||
| dart run build_runner build --delete-conflicting-outputs | ||
|
|
||
| # Watch mode for development | ||
| dart run build_runner watch | ||
|
|
||
| # Run tests | ||
| flutter test | ||
|
|
||
| # Run app | ||
| flutter run | ||
| ``` | ||
|
|
||
| ## Dependency Injection Pattern | ||
|
|
||
| - Uses **Injectable** + **GetIt** for DI | ||
| - All repositories, use cases, BLoCs, and data sources must be annotated: | ||
| - `@Injectable()` for standard dependencies | ||
| - `@Singleton()` for app-wide singletons (e.g., `ScheduleBloc`, `AppDatabase`) | ||
| - `@LazySingleton()` for lazy-initialized singletons | ||
| - After adding `@Injectable()`, run `dart run build_runner build` | ||
| - Register as interface: `@Injectable(as: InterfaceName)` | ||
|
|
||
| Example: | ||
|
|
||
| ```dart | ||
| @Injectable() | ||
| class UpdateScheduleUseCase { | ||
| final ScheduleRepository _repository; | ||
| UpdateScheduleUseCase(this._repository); | ||
| } | ||
|
|
||
| @Singleton(as: ScheduleRepository) | ||
| class ScheduleRepositoryImpl implements ScheduleRepository { ... } | ||
| ``` | ||
|
|
||
| ## State Management with BLoC | ||
|
|
||
| - Use **BLoC** for complex state, **Cubit** for simpler scenarios | ||
| - BLoCs live in `lib/presentation/*/bloc/` directories | ||
| - Pattern: `on<EventName>(_onEventName)` event handlers | ||
| - **Critical**: `ScheduleBloc` is a `@Singleton()` that manages automatic timer system for schedule start notifications (see `docs/Schedule-Timer-System.md`) | ||
| - Keep business logic in **use cases**, not BLoCs | ||
| - BLoCs coordinate between use cases and UI | ||
|
|
||
| Example structure: | ||
|
|
||
| ```dart | ||
| @Injectable() | ||
| class MyBloc extends Bloc<MyEvent, MyState> { | ||
| MyBloc(this._useCase) : super(MyState.initial()) { | ||
| on<MyEventHappened>(_onMyEventHappened); | ||
| } | ||
|
|
||
| Future<void> _onMyEventHappened(MyEventHappened event, Emitter<MyState> emit) async { | ||
| final result = await _useCase(); | ||
| emit(state.copyWith(data: result)); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Data Layer Patterns | ||
|
|
||
| ### Entities (Domain) | ||
|
|
||
| - Use **Equatable** for value equality (most entities) | ||
| - Or **Freezed** for advanced immutability (e.g., `UserEntity`) | ||
| - Live in `lib/domain/entities/` | ||
| - Example: `ScheduleEntity`, `PreparationEntity` | ||
|
|
||
| ### Data Models (Data Layer) | ||
|
|
||
| - Use **json_serializable** for API models | ||
| - Live in `lib/data/models/` | ||
| - Must have `toEntity()` method to convert to domain entities | ||
| - Repository boundary: models → entities when leaving data layer | ||
|
|
||
| ### Database (Drift) | ||
|
|
||
| - Tables defined in `lib/data/tables/` | ||
| - DAOs in `lib/data/daos/` | ||
| - Database: `lib/core/database/database.dart` with `@Singleton()` annotation | ||
| - Schema version tracked, migrations in `MigrationStrategy` | ||
|
|
||
| ### Data Sources | ||
|
|
||
| - Abstract interface + implementation pattern | ||
| // ...existing code... | ||
| - Remote sources use Dio client (`lib/core/dio/app_dio.dart`) | ||
| - Local sources use Drift DAOs or SharedPreferences | ||
| - Example: `ScheduleRemoteDataSource` + `ScheduleRemoteDataSourceImpl` | ||
|
|
||
| ## Reactive Data Fetching Pattern | ||
|
|
||
| The app uses a **reactive repository pattern** where UI updates automatically when data changes. | ||
|
|
||
| 1. **Repository**: Holds a `BehaviorSubject` (Stream) of data. | ||
|
|
||
| - Methods like `getSchedulesByDate` fetch from API/DB and **add the result to the stream**. | ||
| - `scheduleStream` exposes this subject as a broadcast stream. | ||
|
|
||
| 2. **UseCase**: Transforms the repository stream. | ||
|
|
||
| - Can use `async*` to yield transformed states. | ||
| - Combines multiple data sources if needed. | ||
|
|
||
| 3. **BLoC**: Subscribes to the UseCase stream. | ||
| // ...existing code... | ||
| - `listen()` to the stream in event handlers. | ||
| - `add()` new events to the BLoC when stream emits. | ||
|
|
||
| Example `ScheduleRepositoryImpl`: | ||
|
|
||
| ```dart | ||
| @Singleton(as: ScheduleRepository) | ||
| class ScheduleRepositoryImpl implements ScheduleRepository { | ||
| late final _scheduleStreamController = BehaviorSubject<Set<ScheduleEntity>>.seeded({}); | ||
|
|
||
| @override | ||
| Stream<Set<ScheduleEntity>> get scheduleStream => _scheduleStreamController.asBroadcastStream(); | ||
|
|
||
| @override | ||
| Future<List<ScheduleEntity>> getSchedulesByDate(...) async { | ||
| final schedules = await remoteDataSource.getSchedulesByDate(...); | ||
| // Update the stream with new data | ||
| _scheduleStreamController.add(Set.from(_scheduleStreamController.value)..addAll(schedules)); | ||
| return schedules; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Form Management & Validation | ||
|
|
||
| The app uses a **Multi-Step Form Pattern** (e.g., `ScheduleMultiPageForm`): | ||
|
|
||
| 1. **Parent BLoC**: `ScheduleFormBloc` manages the overall form state and final submission. | ||
| 2. **Step Cubits**: Each form step has its own Cubit (e.g., `ScheduleNameCubit`) that: | ||
| - Manages local UI state for that step. | ||
| - Communicates updates to the parent `ScheduleFormBloc`. | ||
| 3. **Validation**: | ||
| - `ScheduleFormState` tracks `isValid` status. | ||
| - `TopBar` enables navigation buttons based on validity. | ||
| - `GlobalKey<FormState>` is used for per-page field validation. | ||
|
|
||
| ## Data Transfer & Navigation | ||
|
|
||
| - **Route Arguments**: Pass IDs (e.g., `scheduleId`) via `GoRouter` path parameters or `extra` object. | ||
| - **Screen Initialization**: | ||
| - Screens receive arguments in their constructor. | ||
| - BLoCs are initialized with these arguments (e.g., `ScheduleFormEditRequested(scheduleId)`). | ||
| - BLoCs fetch full data from Repositories/UseCases using the ID. | ||
| - **Avoid** passing full entity objects between screens; pass IDs and refetch/stream data. | ||
|
|
||
| ## Navigation (GoRouter) | ||
|
|
||
| // ...existing code...Example `ScheduleRepositoryImpl`: | ||
|
|
||
| ```dart | ||
| @Singleton(as: ScheduleRepository) | ||
| class ScheduleRepositoryImpl implements ScheduleRepository { | ||
| late final _scheduleStreamController = BehaviorSubject<Set<ScheduleEntity>>.seeded({}); | ||
|
|
||
| @override | ||
| Stream<Set<ScheduleEntity>> get scheduleStream => _scheduleStreamController.asBroadcastStream(); | ||
|
|
||
| @override | ||
| Future<List<ScheduleEntity>> getSchedulesByDate(...) async { | ||
| final schedules = await remoteDataSource.getSchedulesByDate(...); | ||
| // Update the stream with new data | ||
| _scheduleStreamController.add(Set.from(_scheduleStreamController.value)..addAll(schedules)); | ||
| return schedules; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Navigation (GoRouter) | ||
|
|
||
| // ...existing code...## Navigation (GoRouter) | ||
|
|
||
| - Configured in `lib/presentation/shared/router/go_router.dart` | ||
| - Uses declarative routing with redirect logic based on `AuthBloc` and `ScheduleBloc` state | ||
| - Routes defined with path and builder | ||
| - NavigationService (`lib/core/services/navigation_service.dart`) provides programmatic navigation | ||
|
|
||
| ## Code Generation Files | ||
|
|
||
| **Never manually edit** generated files (`.g.dart`, `.freezed.dart`, `di_setup.config.dart`). These are created by: | ||
|
|
||
| - `build_runner` for JSON serialization, Freezed, Injectable, Drift | ||
| - Regenerate after modifying annotated classes | ||
|
|
||
| ## Testing | ||
|
|
||
| - Tests in `test/` mirror `lib/` structure | ||
| - Use Mockito for mocking dependencies | ||
| - Test helpers in `test/helpers/` | ||
| - Run coverage: `flutter test --coverage` | ||
|
|
||
| ## Commit Message Convention | ||
|
|
||
| Follow **Conventional Commits** (enforced by commitlint): | ||
|
|
||
| - Format: `<type>(<optional scope>): <description>` | ||
| - Types: `feat`, `fix`, `refactor`, `perf`, `style`, `test`, `docs`, `build`, `ops`, `chore` | ||
| - Breaking changes: Add `!` before `:` (e.g., `feat(api)!: remove endpoint`) | ||
| - See `docs/Git.md` for detailed examples | ||
|
|
||
| ## Key Project Files | ||
|
|
||
| - `lib/main.dart`: App entry point, Firebase initialization, DI setup | ||
| - `lib/presentation/app/screens/app.dart`: Root app widget | ||
| - `lib/core/di/di_setup.dart`: DI configuration | ||
| - `lib/core/database/database.dart`: Drift database setup | ||
| - `docs/Architecture.md`: Comprehensive architecture documentation | ||
| - `docs/Schedule-Timer-System.md`: Timer system details for ScheduleBloc | ||
|
|
||
| ## Common Patterns | ||
|
|
||
| 1. **Creating a new feature**: | ||
|
|
||
| - Add entity in `domain/entities/` | ||
| - Create repository interface in `domain/repositories/` | ||
| - Add use cases in `domain/use-cases/` | ||
| - Implement repository in `data/repositories/` | ||
| - Add data sources (remote/local) in `data/data_sources/` | ||
| - Build UI with BLoC in `presentation/<feature>/` | ||
| - Annotate all with `@Injectable()` and run build_runner | ||
|
|
||
| 2. **Adding API endpoint**: | ||
|
|
||
| - Create request/response models in `data/models/` with `@JsonSerializable()` | ||
| - Add method to RemoteDataSource interface and implementation | ||
| - Update repository to use new data source method | ||
| - Run `dart run build_runner build` | ||
|
|
||
| 3. **Adding database table**: | ||
| - Define table in `data/tables/` | ||
| - Create DAO in `data/daos/` | ||
| - Add to `@DriftDatabase` annotation in `database.dart` | ||
| - Increment `schemaVersion` and add migration if needed | ||
| - Run `dart run build_runner build` | ||
|
|
||
| ## Environment & Configuration | ||
|
|
||
| - Environment variables in `lib/core/constants/environment_variable.dart` | ||
| - Firebase configuration in `firebase_options.dart` | ||
| - Analysis options in `analysis_options.yaml` | ||
|
|
||
| ## Widgetbook | ||
|
|
||
| - Component showcase at `widgetbook/` (separate sub-project) | ||
| - Hosted at: https://on-time-front-widgetbook.web.app/ | ||
| - Use for UI component development and testing |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| genhtml coverage/lcov.info -o coverage/html | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Coverage HTML files accidentally committed
Generated coverage HTML files and reports have been committed to the repository. These are build artifacts that should be excluded from version control via
.gitignore. Coverage reports are typically generated locally or in CI/CD pipelines and shouldn't be tracked in git as they change with every test run and bloat the repository.Additional Locations (2)
coverage/html/core/constants/endpoint.dart.gcov.html#L1-L130coverage/html/core/database/database.dart.gcov.html#L1-L143