diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..92ba521 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + +# Blocks commits that do not meet the repository's formatting, analyzer, +# documentation, or SPDX/REUSE metadata gates. +set -euo pipefail + +root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$root_dir" + +dart format --set-exit-if-changed packages apps scripts tool test +dart analyze +dart run tool/check_reuse.dart +dart run tool/check_docs.dart --skip-dartdoc diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 22d7f96..723d4a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + # Runs analyzer, tests, coverage, docs, and tagged desktop packaging. name: CI diff --git a/REUSE.toml b/REUSE.toml new file mode 100644 index 0000000..4e5f09f --- /dev/null +++ b/REUSE.toml @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + +version = 1 + +# The project license text is intentionally kept in the repository root as +# LICENSE.md. These annotations cover package and app files that cannot safely +# carry inline SPDX comments, such as generated platform files, binary icons, +# JSON manifests, Xcode project files, and XML/plist resources. +[[annotations]] +path = [ + "packages/**", + "apps/focus_flow_flutter/**", +] +precedence = "aggregate" +SPDX-FileCopyrightText = "2026 FocusFlow contributors" +SPDX-License-Identifier = "AGPL-3.0-only" diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..1654f9e --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + +include: package:lints/recommended.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +linter: + rules: + public_member_api_docs: true + prefer_final_locals: true + prefer_final_fields: true + avoid_print: true diff --git a/apps/focus_flow_flutter/LICENSE.md b/apps/focus_flow_flutter/LICENSE.md new file mode 100644 index 0000000..c21e851 --- /dev/null +++ b/apps/focus_flow_flutter/LICENSE.md @@ -0,0 +1,6 @@ + + + +# License + +This app uses the repository-level license at [../../LICENSE.md](../../LICENSE.md). diff --git a/apps/focus_flow_flutter/README.md b/apps/focus_flow_flutter/README.md index eb08250..4d618a8 100644 --- a/apps/focus_flow_flutter/README.md +++ b/apps/focus_flow_flutter/README.md @@ -1,3 +1,6 @@ + + + # FocusFlow Flutter Flutter desktop app target for the FocusFlow UI work. diff --git a/apps/focus_flow_flutter/analysis_options.yaml b/apps/focus_flow_flutter/analysis_options.yaml index 74a6706..f28b8dc 100644 --- a/apps/focus_flow_flutter/analysis_options.yaml +++ b/apps/focus_flow_flutter/analysis_options.yaml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + # This file configures the analyzer, which statically analyzes Dart code to # check for errors, warnings, and lints. # @@ -9,6 +12,12 @@ # packages, and plugins designed to encourage good coding practices. include: package:flutter_lints/flutter.yaml +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + linter: # The lint rules applied to this project can be customized in the # section below to disable rules from the `package:flutter_lints/flutter.yaml` @@ -22,6 +31,9 @@ linter: # producing the lint. rules: public_member_api_docs: true + prefer_final_locals: true + prefer_final_fields: true + avoid_print: true # avoid_print: false # Uncomment to disable the `avoid_print` rule # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule diff --git a/apps/focus_flow_flutter/lib/app.dart b/apps/focus_flow_flutter/lib/app.dart index 364b815..14cdb0d 100644 --- a/apps/focus_flow_flutter/lib/app.dart +++ b/apps/focus_flow_flutter/lib/app.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Exports the FocusFlow Flutter application entry points. library; diff --git a/apps/focus_flow_flutter/lib/app/demo/demo_date_formatter.dart b/apps/focus_flow_flutter/lib/app/demo/demo_date_formatter.dart index 58d2025..c78bdc1 100644 --- a/apps/focus_flow_flutter/lib/app/demo/demo_date_formatter.dart +++ b/apps/focus_flow_flutter/lib/app/demo/demo_date_formatter.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../demo_scheduler_composition.dart'; /// Formats a civil date as a long month/day/year label. @@ -19,6 +22,8 @@ String _formatDateLabel(CivilDate date) { return '${months[date.month - 1]} ${date.day}, ${date.year}'; } +/// Top-level helper that performs the `_instant` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. DateTime _instant(CivilDate date, int hour, [int minute = 0]) { return DateTime.utc(date.year, date.month, date.day, hour, minute); } diff --git a/apps/focus_flow_flutter/lib/app/demo/demo_seed_tasks.dart b/apps/focus_flow_flutter/lib/app/demo/demo_seed_tasks.dart index e5d117e..6aadc5d 100644 --- a/apps/focus_flow_flutter/lib/app/demo/demo_seed_tasks.dart +++ b/apps/focus_flow_flutter/lib/app/demo/demo_seed_tasks.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../demo_scheduler_composition.dart'; +/// Top-level helper that performs the `_todaySeedTasks` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _todaySeedTasks(CivilDate date, DateTime createdAt) { return [ _seedTask( @@ -118,6 +123,8 @@ List _todaySeedTasks(CivilDate date, DateTime createdAt) { ]; } +/// Top-level helper that performs the `_seedTask` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Task _seedTask({ required String id, required String title, diff --git a/apps/focus_flow_flutter/lib/app/demo_scheduler_composition.dart b/apps/focus_flow_flutter/lib/app/demo_scheduler_composition.dart index a4a28d5..a614426 100644 --- a/apps/focus_flow_flutter/lib/app/demo_scheduler_composition.dart +++ b/apps/focus_flow_flutter/lib/app/demo_scheduler_composition.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Composes the FocusFlow Flutter application around Demo Scheduler Composition. library; @@ -12,6 +15,8 @@ part 'demo/demo_seed_tasks.dart'; /// Wires the Flutter demo UI to in-memory scheduler application use cases. class DemoSchedulerComposition { + /// Creates a `DemoSchedulerComposition._` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. DemoSchedulerComposition._({ required this.store, required this.todayQuery, diff --git a/apps/focus_flow_flutter/lib/app/focus_flow_app.dart b/apps/focus_flow_flutter/lib/app/focus_flow_app.dart index 0912db6..f9be60f 100644 --- a/apps/focus_flow_flutter/lib/app/focus_flow_app.dart +++ b/apps/focus_flow_flutter/lib/app/focus_flow_app.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Composes the FocusFlow Flutter application around Focus Flow App. library; @@ -30,6 +33,8 @@ class FocusFlowApp extends StatelessWidget { /// Factory and controller bundle used by the app tree. final DemoSchedulerComposition composition; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return MaterialApp( diff --git a/apps/focus_flow_flutter/lib/app/home/focus_flow_home.dart b/apps/focus_flow_flutter/lib/app/home/focus_flow_home.dart index bf4788f..eb92ebc 100644 --- a/apps/focus_flow_flutter/lib/app/home/focus_flow_home.dart +++ b/apps/focus_flow_flutter/lib/app/home/focus_flow_home.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../focus_flow_app.dart'; /// Stateful home screen that owns the Today controller lifecycle. @@ -8,6 +11,8 @@ class FocusFlowHome extends StatefulWidget { /// Factory and controller bundle used by the home screen. final DemoSchedulerComposition composition; + /// Creates the mutable state object used by this stateful widget. + /// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin. @override State createState() => _FocusFlowHomeState(); } diff --git a/apps/focus_flow_flutter/lib/app/home/focus_flow_home_state.dart b/apps/focus_flow_flutter/lib/app/home/focus_flow_home_state.dart index 82d70e8..11eaa7a 100644 --- a/apps/focus_flow_flutter/lib/app/home/focus_flow_home_state.dart +++ b/apps/focus_flow_flutter/lib/app/home/focus_flow_home_state.dart @@ -1,9 +1,21 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../focus_flow_app.dart'; +/// Private implementation type for `_FocusFlowHomeState` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _FocusFlowHomeState extends State { + /// Stores the `controller` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. late final TodayScreenController controller; + + /// Stores the `commandController` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. late final SchedulerCommandController commandController; + /// Initializes state owned by this object before the first build. + /// Use this lifecycle point for controller setup, initial reads, and listener wiring that must happen once per mounted instance. @override void initState() { super.initState(); @@ -14,6 +26,8 @@ class _FocusFlowHomeState extends State { controller.load(); } + /// Releases resources owned by this object before it leaves the tree. + /// Controllers, listeners, and other disposable collaborators should be cleaned up here to avoid stale callbacks. @override void dispose() { commandController.dispose(); @@ -21,6 +35,8 @@ class _FocusFlowHomeState extends State { super.dispose(); } + /// Runs the `_toggleCardCompletion` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _toggleCardCompletion(TimelineCardModel card) async { if (!card.canToggleCompletion) { return; @@ -35,6 +51,8 @@ class _FocusFlowHomeState extends State { } } + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return Scaffold( diff --git a/apps/focus_flow_flutter/lib/app/home/plan_issue.dart b/apps/focus_flow_flutter/lib/app/home/plan_issue.dart index 4508e4a..45173ef 100644 --- a/apps/focus_flow_flutter/lib/app/home/plan_issue.dart +++ b/apps/focus_flow_flutter/lib/app/home/plan_issue.dart @@ -1,10 +1,21 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../focus_flow_app.dart'; +/// Private implementation type for `_PlanIssue` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _PlanIssue extends StatelessWidget { + /// Creates a `_PlanIssue` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _PlanIssue({required this.message}); + /// Stores the `message` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String message; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return Center( diff --git a/apps/focus_flow_flutter/lib/app/home/today_screen_scaffold.dart b/apps/focus_flow_flutter/lib/app/home/today_screen_scaffold.dart index 96a4d98..8f28211 100644 --- a/apps/focus_flow_flutter/lib/app/home/today_screen_scaffold.dart +++ b/apps/focus_flow_flutter/lib/app/home/today_screen_scaffold.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../focus_flow_app.dart'; +/// Private implementation type for `_TodayScreenScaffold` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _TodayScreenScaffold extends StatefulWidget { + /// Creates a `_TodayScreenScaffold` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _TodayScreenScaffold({ required this.data, required this.selectedCard, @@ -9,12 +16,28 @@ class _TodayScreenScaffold extends StatefulWidget { required this.onClearSelection, }); + /// Stores the `data` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final TodayScreenData data; + + /// Stores the `selectedCard` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final TimelineCardModel? selectedCard; + + /// Stores the `onSelectCard` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ValueChanged onSelectCard; + + /// Stores the `onCompleteCard` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Future Function(TimelineCardModel card) onCompleteCard; + + /// Stores the `onClearSelection` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final VoidCallback onClearSelection; + /// Creates the mutable state object used by this stateful widget. + /// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin. @override State<_TodayScreenScaffold> createState() => _TodayScreenScaffoldState(); } diff --git a/apps/focus_flow_flutter/lib/app/home/today_screen_scaffold_state.dart b/apps/focus_flow_flutter/lib/app/home/today_screen_scaffold_state.dart index 02fa25c..5fd50bf 100644 --- a/apps/focus_flow_flutter/lib/app/home/today_screen_scaffold_state.dart +++ b/apps/focus_flow_flutter/lib/app/home/today_screen_scaffold_state.dart @@ -1,9 +1,21 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../focus_flow_app.dart'; +/// Private implementation type for `_TodayScreenScaffoldState` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _TodayScreenScaffoldState extends State<_TodayScreenScaffold> { + /// Private state stored as `_timelineScrollTargetCardId` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. String? _timelineScrollTargetCardId; + + /// Private state stored as `_timelineScrollRequest` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. var _timelineScrollRequest = 0; + /// Runs the `_showUpcomingRequiredTask` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. void _showUpcomingRequiredTask() { final targetCardId = widget.data.requiredBanner?.timelineCardId; if (targetCardId == null) { @@ -15,6 +27,8 @@ class _TodayScreenScaffoldState extends State<_TodayScreenScaffold> { }); } + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return Stack( diff --git a/apps/focus_flow_flutter/lib/composition/demo_scheduler_composition.dart b/apps/focus_flow_flutter/lib/composition/demo_scheduler_composition.dart index db00ab7..cf2bb6a 100644 --- a/apps/focus_flow_flutter/lib/composition/demo_scheduler_composition.dart +++ b/apps/focus_flow_flutter/lib/composition/demo_scheduler_composition.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Provides compatibility composition exports for FocusFlow Flutter. library; diff --git a/apps/focus_flow_flutter/lib/controllers/command/scheduler_command_callbacks.dart b/apps/focus_flow_flutter/lib/controllers/command/scheduler_command_callbacks.dart index 2a4d532..275fd9b 100644 --- a/apps/focus_flow_flutter/lib/controllers/command/scheduler_command_callbacks.dart +++ b/apps/focus_flow_flutter/lib/controllers/command/scheduler_command_callbacks.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../scheduler_command_controller.dart'; /// Builds an application operation context for a UI command operation. diff --git a/apps/focus_flow_flutter/lib/controllers/command/scheduler_command_controller_impl.dart b/apps/focus_flow_flutter/lib/controllers/command/scheduler_command_controller_impl.dart index 802398a..1d3d5fa 100644 --- a/apps/focus_flow_flutter/lib/controllers/command/scheduler_command_controller_impl.dart +++ b/apps/focus_flow_flutter/lib/controllers/command/scheduler_command_controller_impl.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../scheduler_command_controller.dart'; /// Runs scheduler write commands and exposes command state to widgets. @@ -25,7 +28,13 @@ class SchedulerCommandController extends ChangeNotifier { /// Clock used by direct UI commands such as marking a task complete. final DateTime Function() now; + + /// Private state stored as `_sequence` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. var _sequence = 0; + + /// Private state stored as `_state` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. SchedulerCommandState _state = const SchedulerCommandIdle(); /// Current command execution state. @@ -146,6 +155,8 @@ class SchedulerCommandController extends ChangeNotifier { ); } + /// Runs the `_run` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _run({ required String label, required String successMessage, @@ -173,15 +184,21 @@ class SchedulerCommandController extends ChangeNotifier { } } + /// Runs the `_nextOperationId` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. String _nextOperationId() { _sequence += 1; return 'ui-command-$_sequence'; } + /// Runs the `_setState` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. void _setState(SchedulerCommandState next) { _state = next; notifyListeners(); } + /// Runs the `_utcNow` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static DateTime _utcNow() => DateTime.now().toUtc(); } diff --git a/apps/focus_flow_flutter/lib/controllers/command/scheduler_command_state.dart b/apps/focus_flow_flutter/lib/controllers/command/scheduler_command_state.dart index 8f814f0..2c15d88 100644 --- a/apps/focus_flow_flutter/lib/controllers/command/scheduler_command_state.dart +++ b/apps/focus_flow_flutter/lib/controllers/command/scheduler_command_state.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../scheduler_command_controller.dart'; /// Base state for scheduler command execution in the UI. diff --git a/apps/focus_flow_flutter/lib/controllers/scheduler_command_controller.dart b/apps/focus_flow_flutter/lib/controllers/scheduler_command_controller.dart index 417af9e..6be3f52 100644 --- a/apps/focus_flow_flutter/lib/controllers/scheduler_command_controller.dart +++ b/apps/focus_flow_flutter/lib/controllers/scheduler_command_controller.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Coordinates Scheduler Command Controller state for the FocusFlow Flutter UI. library; diff --git a/apps/focus_flow_flutter/lib/controllers/scheduler_read_controller.dart b/apps/focus_flow_flutter/lib/controllers/scheduler_read_controller.dart index f6e5d38..b446e31 100644 --- a/apps/focus_flow_flutter/lib/controllers/scheduler_read_controller.dart +++ b/apps/focus_flow_flutter/lib/controllers/scheduler_read_controller.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Coordinates Scheduler Read Controller state for the FocusFlow Flutter UI. library; @@ -84,6 +87,8 @@ class ApplicationReadController extends UiReadController { /// Predicate used to classify a successful value as empty or populated. final EmptyPredicate isEmpty; + /// Private state stored as `_state` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. SchedulerReadState _state = SchedulerReadLoading(); /// Current read state. @@ -116,6 +121,8 @@ class ApplicationReadController extends UiReadController { @override Future retry() => load(); + /// Runs the `_setState` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. void _setState(SchedulerReadState next) { _state = next; notifyListeners(); diff --git a/apps/focus_flow_flutter/lib/controllers/today_screen_controller.dart b/apps/focus_flow_flutter/lib/controllers/today_screen_controller.dart index a7e2953..6994850 100644 --- a/apps/focus_flow_flutter/lib/controllers/today_screen_controller.dart +++ b/apps/focus_flow_flutter/lib/controllers/today_screen_controller.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Coordinates Today Screen Controller state for the FocusFlow Flutter UI. library; @@ -53,7 +56,12 @@ class TodayScreenController extends ChangeNotifier { /// Callback used to read Today state. final TodayStateReader read; + /// Private state stored as `_state` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. TodayScreenState _state = const TodayScreenLoading(); + + /// Private state stored as `_selectedCard` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. TimelineCardModel? _selectedCard; /// Current Today screen loading/data/failure state. @@ -105,6 +113,8 @@ class TodayScreenController extends ChangeNotifier { notifyListeners(); } + /// Runs the `_syncSelectedCard` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. void _syncSelectedCard(TodayScreenData data) { final selected = _selectedCard; if (selected == null) { diff --git a/apps/focus_flow_flutter/lib/main.dart b/apps/focus_flow_flutter/lib/main.dart index 1532609..20c19ae 100644 --- a/apps/focus_flow_flutter/lib/main.dart +++ b/apps/focus_flow_flutter/lib/main.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Launches the FocusFlow Flutter desktop application. library; diff --git a/apps/focus_flow_flutter/lib/models/today/required_banner_model.dart b/apps/focus_flow_flutter/lib/models/today/required_banner_model.dart index 53ffc08..5e6166a 100644 --- a/apps/focus_flow_flutter/lib/models/today/required_banner_model.dart +++ b/apps/focus_flow_flutter/lib/models/today/required_banner_model.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../today_screen_models.dart'; /// Presentation model for the next-required-task banner. diff --git a/apps/focus_flow_flutter/lib/models/today/task_visual_kind.dart b/apps/focus_flow_flutter/lib/models/today/task_visual_kind.dart index 8a8a6f9..bc2d7fe 100644 --- a/apps/focus_flow_flutter/lib/models/today/task_visual_kind.dart +++ b/apps/focus_flow_flutter/lib/models/today/task_visual_kind.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../today_screen_models.dart'; /// Visual category used to style timeline cards. diff --git a/apps/focus_flow_flutter/lib/models/today/time/time_string_formatter.dart b/apps/focus_flow_flutter/lib/models/today/time/time_string_formatter.dart index 722542e..1ed136d 100644 --- a/apps/focus_flow_flutter/lib/models/today/time/time_string_formatter.dart +++ b/apps/focus_flow_flutter/lib/models/today/time/time_string_formatter.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../today_screen_models.dart'; +/// Top-level helper that performs the `_dateLabel` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _dateLabel(CivilDate date) { const months = [ 'January', @@ -18,6 +23,8 @@ String _dateLabel(CivilDate date) { return '${months[date.month - 1]} ${date.day}, ${date.year}'; } +/// Top-level helper that performs the `_minutesSinceMidnight` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _minutesSinceMidnight(DateTime? value) { if (value == null) { return 0; @@ -25,6 +32,8 @@ int _minutesSinceMidnight(DateTime? value) { return value.hour * 60 + value.minute; } +/// Top-level helper that performs the `_formatTime` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _formatTime(DateTime? value) { if (value == null) { return ''; diff --git a/apps/focus_flow_flutter/lib/models/today/timeline_card_model.dart b/apps/focus_flow_flutter/lib/models/today/timeline_card_model.dart index 4aa6d82..bf1baa1 100644 --- a/apps/focus_flow_flutter/lib/models/today/timeline_card_model.dart +++ b/apps/focus_flow_flutter/lib/models/today/timeline_card_model.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../today_screen_models.dart'; /// Presentation model for a single compact timeline card. diff --git a/apps/focus_flow_flutter/lib/models/today/timeline_item_presentation_mapper.dart b/apps/focus_flow_flutter/lib/models/today/timeline_item_presentation_mapper.dart index 3697b4a..edb96c4 100644 --- a/apps/focus_flow_flutter/lib/models/today/timeline_item_presentation_mapper.dart +++ b/apps/focus_flow_flutter/lib/models/today/timeline_item_presentation_mapper.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../today_screen_models.dart'; +/// Top-level helper that performs the `_visualKindFor` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TaskVisualKind _visualKindFor(TodayTimelineItem item) { if (item.taskStatus == TaskStatus.completed || (item.taskType == TaskType.surprise && @@ -16,6 +21,8 @@ TaskVisualKind _visualKindFor(TodayTimelineItem item) { }; } +/// Top-level helper that performs the `_typeLabelFor` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _typeLabelFor(TaskType taskType, TaskVisualKind visualKind) { if (visualKind == TaskVisualKind.completedSurprise) { return 'Completed'; @@ -30,6 +37,8 @@ String _typeLabelFor(TaskType taskType, TaskVisualKind visualKind) { }; } +/// Top-level helper that performs the `_subtitleFor` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _subtitleFor( TodayTimelineItem item, TaskVisualKind visualKind, diff --git a/apps/focus_flow_flutter/lib/models/today/timeline_range_model.dart b/apps/focus_flow_flutter/lib/models/today/timeline_range_model.dart index 2b48a20..059d236 100644 --- a/apps/focus_flow_flutter/lib/models/today/timeline_range_model.dart +++ b/apps/focus_flow_flutter/lib/models/today/timeline_range_model.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../today_screen_models.dart'; /// Visible timeline range expressed as minutes since midnight. diff --git a/apps/focus_flow_flutter/lib/models/today/today_screen_data.dart b/apps/focus_flow_flutter/lib/models/today/today_screen_data.dart index 4e35ca8..4455c8e 100644 --- a/apps/focus_flow_flutter/lib/models/today/today_screen_data.dart +++ b/apps/focus_flow_flutter/lib/models/today/today_screen_data.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../today_screen_models.dart'; /// Presentation model for the compact Today screen. diff --git a/apps/focus_flow_flutter/lib/models/today_screen_models.dart b/apps/focus_flow_flutter/lib/models/today_screen_models.dart index ac68893..2555b73 100644 --- a/apps/focus_flow_flutter/lib/models/today_screen_models.dart +++ b/apps/focus_flow_flutter/lib/models/today_screen_models.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Defines Today Screen Models models for the FocusFlow Flutter UI. library; diff --git a/apps/focus_flow_flutter/lib/theme/focus_flow_theme.dart b/apps/focus_flow_flutter/lib/theme/focus_flow_theme.dart index 57ed6de..3c519c4 100644 --- a/apps/focus_flow_flutter/lib/theme/focus_flow_theme.dart +++ b/apps/focus_flow_flutter/lib/theme/focus_flow_theme.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Defines Focus Flow Theme styling for the FocusFlow Flutter UI. library; diff --git a/apps/focus_flow_flutter/lib/theme/focus_flow_tokens.dart b/apps/focus_flow_flutter/lib/theme/focus_flow_tokens.dart index 616f985..53d4ab7 100644 --- a/apps/focus_flow_flutter/lib/theme/focus_flow_tokens.dart +++ b/apps/focus_flow_flutter/lib/theme/focus_flow_tokens.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Defines Focus Flow Tokens styling for the FocusFlow Flutter UI. library; diff --git a/apps/focus_flow_flutter/lib/theme/scheduler_visual_tokens.dart b/apps/focus_flow_flutter/lib/theme/scheduler_visual_tokens.dart index 00a8b97..175d94c 100644 --- a/apps/focus_flow_flutter/lib/theme/scheduler_visual_tokens.dart +++ b/apps/focus_flow_flutter/lib/theme/scheduler_visual_tokens.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Defines Scheduler Visual Tokens styling for the FocusFlow Flutter UI. library; diff --git a/apps/focus_flow_flutter/lib/widgets/app_shell.dart b/apps/focus_flow_flutter/lib/widgets/app_shell.dart index 6c94d90..d9ced50 100644 --- a/apps/focus_flow_flutter/lib/widgets/app_shell.dart +++ b/apps/focus_flow_flutter/lib/widgets/app_shell.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders the App Shell widget for the FocusFlow Flutter UI. library; @@ -16,6 +19,8 @@ class AppShell extends StatelessWidget { /// Primary content widget displayed beside the sidebar. final Widget child; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return ColoredBox( diff --git a/apps/focus_flow_flutter/lib/widgets/backlog_pane.dart b/apps/focus_flow_flutter/lib/widgets/backlog_pane.dart index 9d56f95..b951467 100644 --- a/apps/focus_flow_flutter/lib/widgets/backlog_pane.dart +++ b/apps/focus_flow_flutter/lib/widgets/backlog_pane.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders the Backlog Pane widget for the FocusFlow Flutter UI. library; @@ -24,6 +27,8 @@ class BacklogPane extends StatelessWidget { /// Optional command controller for mutating backlog items. final SchedulerCommandController? commandController; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return ReadStateView( @@ -52,6 +57,8 @@ class BacklogContent extends StatelessWidget { /// Optional command controller for capture and scheduling actions. final SchedulerCommandController? commandController; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return ListView( @@ -91,19 +98,29 @@ class QuickCaptureForm extends StatefulWidget { /// Command controller used to submit captured task titles. final SchedulerCommandController commandController; + /// Creates the mutable state object used by this stateful widget. + /// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin. @override State createState() => _QuickCaptureFormState(); } +/// Private implementation type for `_QuickCaptureFormState` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _QuickCaptureFormState extends State { + /// Stores the `titleController` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final titleController = TextEditingController(); + /// Releases resources owned by this object before it leaves the tree. + /// Controllers, listeners, and other disposable collaborators should be cleaned up here to avoid stale callbacks. @override void dispose() { titleController.dispose(); super.dispose(); } + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return Row( @@ -142,6 +159,8 @@ class CommandStatusBanner extends StatelessWidget { /// Command controller whose state should be rendered. final SchedulerCommandController controller; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return AnimatedBuilder( diff --git a/apps/focus_flow_flutter/lib/widgets/read_state_view.dart b/apps/focus_flow_flutter/lib/widgets/read_state_view.dart index 8ffd8ec..7463f47 100644 --- a/apps/focus_flow_flutter/lib/widgets/read_state_view.dart +++ b/apps/focus_flow_flutter/lib/widgets/read_state_view.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders the Read State View widget for the FocusFlow Flutter UI. library; @@ -32,6 +35,8 @@ class ReadStateView extends StatelessWidget { /// Builds the populated content for a read value. final Widget Function(BuildContext context, T value) dataBuilder; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return AnimatedBuilder( @@ -82,6 +87,8 @@ class EmptyStatePanel extends StatelessWidget { /// Optional content shown alongside the empty-state panel. final Widget? child; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { final panel = Padding( @@ -138,6 +145,8 @@ class FailureStatePanel extends StatelessWidget { /// Callback invoked when the user retries the read. final Future Function() onRetry; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return Center( diff --git a/apps/focus_flow_flutter/lib/widgets/required_banner.dart b/apps/focus_flow_flutter/lib/widgets/required_banner.dart index 99cd71d..a3a9897 100644 --- a/apps/focus_flow_flutter/lib/widgets/required_banner.dart +++ b/apps/focus_flow_flutter/lib/widgets/required_banner.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders the Required Banner widget for the FocusFlow Flutter UI. library; @@ -17,6 +20,8 @@ class RequiredBanner extends StatelessWidget { /// Callback invoked when the highlighted required task should be shown. final VoidCallback? onShowUpcoming; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { final banner = model; @@ -97,44 +102,115 @@ class RequiredBanner extends StatelessWidget { } } +/// Private implementation type for `_RequiredBannerMetrics` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _RequiredBannerMetrics { + /// Creates a `_RequiredBannerMetrics` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _RequiredBannerMetrics(this.scale); + /// Shared constant value for `referenceHeight`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const referenceHeight = 72.0; + + /// Shared constant value for `_referenceWidth`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const _referenceWidth = 760.0; + + /// Shared constant value for `_minimumScale`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const _minimumScale = 0.5; + /// Creates a `_RequiredBannerMetrics.fromWidth` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. factory _RequiredBannerMetrics.fromWidth(double width) { final safeWidth = width.isFinite ? width : _referenceWidth; final scale = (safeWidth / _referenceWidth).clamp(_minimumScale, 1.0); return _RequiredBannerMetrics(scale.toDouble()); } + /// Stores the `scale` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final double scale; + /// Returns the derived `horizontalPadding` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get horizontalPadding => 18 * scale; + + /// Returns the derived `bannerRadius` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get bannerRadius => FocusFlowTokens.bannerRadius * scale; + + /// Returns the derived `borderWidth` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get borderWidth => scale < 0.7 ? 0.8 : 1; + + /// Returns the derived `iconCircleSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get iconCircleSize => 48 * scale; + + /// Returns the derived `iconSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get iconSize => 24 * scale; + + /// Returns the derived `iconGap` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get iconGap => 26 * scale; + + /// Returns the derived `buttonGap` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get buttonGap => 20 * scale; + + /// Returns the derived `textSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get textSize => (19 * scale).clamp(13.0, 14.0).toDouble(); + + /// Returns the derived `buttonWidth` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get buttonWidth => 176 * scale; + + /// Returns the derived `buttonHeight` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get buttonHeight => 46 * scale; + + /// Returns the derived `buttonRadius` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get buttonRadius => FocusFlowTokens.smallButtonRadius * scale; + + /// Returns the derived `buttonTextSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get buttonTextSize => (16 * scale).clamp(11.0, 12.5).toDouble(); + + /// Returns the derived `buttonIconSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get buttonIconSize => 20 * scale; + + /// Returns the derived `buttonTextGap` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get buttonTextGap => 6 * scale; + + /// Returns the derived `buttonPadding` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. EdgeInsets get buttonPadding => EdgeInsets.symmetric(horizontal: 12 * scale); } +/// Private implementation type for `_UpcomingButton` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _UpcomingButton extends StatelessWidget { + /// Creates a `_UpcomingButton` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _UpcomingButton({required this.metrics, required this.onPressed}); + /// Stores the `metrics` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final _RequiredBannerMetrics metrics; + + /// Stores the `onPressed` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final VoidCallback? onPressed; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return OutlinedButton( diff --git a/apps/focus_flow_flutter/lib/widgets/schedule_components.dart b/apps/focus_flow_flutter/lib/widgets/schedule_components.dart index 1aae2db..37d9bc8 100644 --- a/apps/focus_flow_flutter/lib/widgets/schedule_components.dart +++ b/apps/focus_flow_flutter/lib/widgets/schedule_components.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders the Schedule Components widget for the FocusFlow Flutter UI. library; @@ -14,6 +17,8 @@ class CompactPanel extends StatelessWidget { /// Timeline items to display in compact form. final List items; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { if (items.isEmpty) { @@ -42,6 +47,8 @@ class TimelineRow extends StatelessWidget { /// Optional completion callback for eligible tasks. final Future Function()? onDone; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; @@ -104,19 +111,29 @@ class BacklogRow extends StatefulWidget { /// Optional callback that schedules the item for a duration in minutes. final Future Function(int durationMinutes)? onSchedule; + /// Creates the mutable state object used by this stateful widget. + /// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin. @override State createState() => _BacklogRowState(); } +/// Private implementation type for `_BacklogRowState` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _BacklogRowState extends State { + /// Stores the `durationController` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final durationController = TextEditingController(); + /// Releases resources owned by this object before it leaves the tree. + /// Controllers, listeners, and other disposable collaborators should be cleaned up here to avoid stale callbacks. @override void dispose() { durationController.dispose(); super.dispose(); } + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; @@ -175,6 +192,8 @@ class StalenessMarker extends StatelessWidget { /// Staleness marker value to render. final BacklogStalenessMarker marker; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return Icon( @@ -192,6 +211,8 @@ class NoticeBanner extends StatelessWidget { /// Notice message to display. final String message; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return Container( @@ -216,6 +237,8 @@ String timeText(TimelineItem item) { return '${_clockText(start)}-${_clockText(end)}'; } +/// Top-level helper that performs the `_clockText` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _clockText(DateTime value) { final hour = value.hour.toString().padLeft(2, '0'); final minute = value.minute.toString().padLeft(2, '0'); diff --git a/apps/focus_flow_flutter/lib/widgets/sidebar.dart b/apps/focus_flow_flutter/lib/widgets/sidebar.dart index fce3bbd..4c4c74e 100644 --- a/apps/focus_flow_flutter/lib/widgets/sidebar.dart +++ b/apps/focus_flow_flutter/lib/widgets/sidebar.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders the Sidebar widget for the FocusFlow Flutter UI. library; @@ -10,6 +13,8 @@ class Sidebar extends StatelessWidget { /// Creates the FocusFlow sidebar. const Sidebar({super.key}); + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return DecoratedBox( @@ -46,9 +51,15 @@ class Sidebar extends StatelessWidget { } } +/// Private implementation type for `_WindowControls` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _WindowControls extends StatelessWidget { + /// Creates a `_WindowControls` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _WindowControls(); + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return const Row( @@ -63,11 +74,19 @@ class _WindowControls extends StatelessWidget { } } +/// Private implementation type for `_WindowDot` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _WindowDot extends StatelessWidget { + /// Creates a `_WindowDot` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _WindowDot({required this.color}); + /// Stores the `color` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color color; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return DecoratedBox( @@ -77,9 +96,15 @@ class _WindowDot extends StatelessWidget { } } +/// Private implementation type for `_BrandRow` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _BrandRow extends StatelessWidget { + /// Creates a `_BrandRow` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _BrandRow(); + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return Row( @@ -111,7 +136,11 @@ class _BrandRow extends StatelessWidget { } } +/// Private implementation type for `_NavItem` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _NavItem extends StatelessWidget { + /// Creates a `_NavItem` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _NavItem({ required this.label, required this.icon, @@ -119,11 +148,24 @@ class _NavItem extends StatelessWidget { this.active = false, }); + /// Stores the `label` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String label; + + /// Stores the `icon` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final IconData icon; + + /// Stores the `onTap` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final VoidCallback onTap; + + /// Stores the `active` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool active; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { final color = active diff --git a/apps/focus_flow_flutter/lib/widgets/task_selection/action_button.dart b/apps/focus_flow_flutter/lib/widgets/task_selection/action_button.dart index 7e75afd..b2562a3 100644 --- a/apps/focus_flow_flutter/lib/widgets/task_selection/action_button.dart +++ b/apps/focus_flow_flutter/lib/widgets/task_selection/action_button.dart @@ -1,11 +1,25 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_selection_modal.dart'; +/// Private implementation type for `_ActionButton` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _ActionButton extends StatelessWidget { + /// Creates a `_ActionButton` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _ActionButton({required this.icon, required this.label}); + /// Stores the `icon` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final IconData icon; + + /// Stores the `label` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String label; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return OutlinedButton.icon( diff --git a/apps/focus_flow_flutter/lib/widgets/task_selection/header_metadata.dart b/apps/focus_flow_flutter/lib/widgets/task_selection/header_metadata.dart index 2a5c5c2..ec6a2c3 100644 --- a/apps/focus_flow_flutter/lib/widgets/task_selection/header_metadata.dart +++ b/apps/focus_flow_flutter/lib/widgets/task_selection/header_metadata.dart @@ -1,10 +1,21 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_selection_modal.dart'; +/// Private implementation type for `_HeaderMetadata` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _HeaderMetadata extends StatelessWidget { + /// Creates a `_HeaderMetadata` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _HeaderMetadata({required this.card}); + /// Stores the `card` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final TimelineCardModel card; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { const metadataStyle = TextStyle( diff --git a/apps/focus_flow_flutter/lib/widgets/task_selection/info_tile.dart b/apps/focus_flow_flutter/lib/widgets/task_selection/info_tile.dart index 9314e7a..84ac17d 100644 --- a/apps/focus_flow_flutter/lib/widgets/task_selection/info_tile.dart +++ b/apps/focus_flow_flutter/lib/widgets/task_selection/info_tile.dart @@ -1,11 +1,25 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_selection_modal.dart'; +/// Private implementation type for `_InfoTile` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _InfoTile extends StatelessWidget { + /// Creates a `_InfoTile` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _InfoTile({required this.child, required this.label}); + /// Stores the `child` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Widget child; + + /// Stores the `label` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String label; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return Container( diff --git a/apps/focus_flow_flutter/lib/widgets/task_selection/modal_accent.dart b/apps/focus_flow_flutter/lib/widgets/task_selection/modal_accent.dart index 29e7c5e..8fe6fb0 100644 --- a/apps/focus_flow_flutter/lib/widgets/task_selection/modal_accent.dart +++ b/apps/focus_flow_flutter/lib/widgets/task_selection/modal_accent.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_selection_modal.dart'; +/// Top-level helper that performs the `_accentFor` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Color _accentFor(TaskVisualKind kind) { return switch (kind) { TaskVisualKind.flexible => FocusFlowTokens.flexibleGreen, diff --git a/apps/focus_flow_flutter/lib/widgets/task_selection/modal_status_button.dart b/apps/focus_flow_flutter/lib/widgets/task_selection/modal_status_button.dart index 78b6a03..aed36b8 100644 --- a/apps/focus_flow_flutter/lib/widgets/task_selection/modal_status_button.dart +++ b/apps/focus_flow_flutter/lib/widgets/task_selection/modal_status_button.dart @@ -1,16 +1,33 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_selection_modal.dart'; +/// Private implementation type for `_ModalStatusButton` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _ModalStatusButton extends StatelessWidget { + /// Creates a `_ModalStatusButton` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _ModalStatusButton({ required this.card, required this.color, required this.onPressed, }); + /// Stores the `card` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final TimelineCardModel card; + + /// Stores the `color` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color color; + + /// Stores the `onPressed` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final VoidCallback? onPressed; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { final ring = Container( diff --git a/apps/focus_flow_flutter/lib/widgets/task_selection_modal.dart b/apps/focus_flow_flutter/lib/widgets/task_selection_modal.dart index b26aee9..e2e7f5c 100644 --- a/apps/focus_flow_flutter/lib/widgets/task_selection_modal.dart +++ b/apps/focus_flow_flutter/lib/widgets/task_selection_modal.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders the Task Selection Modal widget for the FocusFlow Flutter UI. library; @@ -33,6 +36,8 @@ class TaskSelectionModal extends StatelessWidget { /// Callback invoked when the status circle should toggle completion. final VoidCallback? onStatusPressed; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { final accent = _accentFor(card.visualKind); diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/axis/timeline_grid.dart b/apps/focus_flow_flutter/lib/widgets/timeline/axis/timeline_grid.dart index 748c9b3..e83fdcb 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/axis/timeline_grid.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/axis/timeline_grid.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../timeline_axis.dart'; /// Background grid aligned to timeline tick marks. @@ -11,6 +14,8 @@ class TimelineGrid extends StatelessWidget { /// Vertical inset before the first timeline tick. final double topInset; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return CustomPaint( diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/axis/timeline_grid_painter.dart b/apps/focus_flow_flutter/lib/widgets/timeline/axis/timeline_grid_painter.dart index f9b31e1..ee3833d 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/axis/timeline_grid_painter.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/axis/timeline_grid_painter.dart @@ -1,11 +1,25 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../timeline_axis.dart'; +/// Private implementation type for `_TimelineGridPainter` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _TimelineGridPainter extends CustomPainter { + /// Creates a `_TimelineGridPainter` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _TimelineGridPainter({required this.geometry, required this.topInset}); + /// Stores the `geometry` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final TimelineGeometry geometry; + + /// Stores the `topInset` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final double topInset; + /// Performs the `paint` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override void paint(Canvas canvas, Size size) { final paint = Paint() @@ -23,6 +37,8 @@ class _TimelineGridPainter extends CustomPainter { } } + /// Performs the `shouldRepaint` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override bool shouldRepaint(covariant _TimelineGridPainter oldDelegate) { return oldDelegate.geometry != geometry || oldDelegate.topInset != topInset; diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/difficulty_bars.dart b/apps/focus_flow_flutter/lib/widgets/timeline/difficulty_bars.dart index aa9926b..3580a23 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/difficulty_bars.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/difficulty_bars.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders Difficulty Bars pieces for the FocusFlow Flutter timeline. library; @@ -49,6 +52,8 @@ class DifficultyBars extends StatelessWidget { }; } + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return CustomPaint( @@ -61,15 +66,26 @@ class DifficultyBars extends StatelessWidget { } } +/// Private implementation type for `_DifficultyBarsPainter` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _DifficultyBarsPainter extends CustomPainter { + /// Creates a `_DifficultyBarsPainter` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _DifficultyBarsPainter({ required this.filledCount, required this.color, }); + /// Stores the `filledCount` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int filledCount; + + /// Stores the `color` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color color; + /// Performs the `paint` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override void paint(Canvas canvas, Size size) { final gap = size.width * 0.08; @@ -98,6 +114,8 @@ class _DifficultyBarsPainter extends CustomPainter { } } + /// Performs the `shouldRepaint` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override bool shouldRepaint(covariant _DifficultyBarsPainter oldDelegate) { return oldDelegate.filledCount != filledCount || oldDelegate.color != color; diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/reward_icon.dart b/apps/focus_flow_flutter/lib/widgets/timeline/reward_icon.dart index 2586f53..7f97f57 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/reward_icon.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/reward_icon.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders Reward Icon pieces for the FocusFlow Flutter timeline. library; @@ -20,6 +23,8 @@ class RewardIcon extends StatelessWidget { /// Square size of the painted icon. final double size; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return CustomPaint( @@ -29,11 +34,19 @@ class RewardIcon extends StatelessWidget { } } +/// Private implementation type for `_RewardIconPainter` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _RewardIconPainter extends CustomPainter { + /// Creates a `_RewardIconPainter` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _RewardIconPainter(this.color); + /// Stores the `color` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color color; + /// Performs the `paint` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override void paint(Canvas canvas, Size size) { final paint = Paint() @@ -59,6 +72,8 @@ class _RewardIconPainter extends CustomPainter { ); } + /// Runs the `_drawSparkle` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. void _drawSparkle(Canvas canvas, Paint paint, Offset center, double radius) { final path = Path() ..moveTo(center.dx, center.dy - radius) @@ -73,6 +88,8 @@ class _RewardIconPainter extends CustomPainter { canvas.drawPath(path, paint); } + /// Performs the `shouldRepaint` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override bool shouldRepaint(covariant _RewardIconPainter oldDelegate) { return oldDelegate.color != color; diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/card_colors.dart b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/card_colors.dart index 98447b1..5fe1fd7 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/card_colors.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/card_colors.dart @@ -1,16 +1,33 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_timeline_card.dart'; +/// Private implementation type for `_CardColors` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _CardColors { + /// Creates a `_CardColors` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _CardColors({ required this.accent, required this.background, required this.reward, }); + /// Stores the `accent` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color accent; + + /// Stores the `background` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color background; + + /// Stores the `reward` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color reward; + /// Creates a `_CardColors.forKind` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. factory _CardColors.forKind(TaskVisualKind kind) { return switch (kind) { TaskVisualKind.flexible => const _CardColors( diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/card_metrics.dart b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/card_metrics.dart index 2fa9a45..1e3a927 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/card_metrics.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/card_metrics.dart @@ -1,14 +1,37 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_timeline_card.dart'; +/// Private implementation type for `_CardMetrics` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _CardMetrics { + /// Creates a `_CardMetrics` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _CardMetrics({required this.scale, required this.height}); + /// Shared constant value for `_referenceWidth`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const _referenceWidth = 640.0; + + /// Shared constant value for `_referenceHeight`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const _referenceHeight = 88.0; + + /// Shared constant value for `_freeSlotReferenceHeight`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const _freeSlotReferenceHeight = 108.0; + + /// Shared constant value for `_compactHeightThreshold`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const _compactHeightThreshold = 56.0; + + /// Shared constant value for `_minimumScale`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const _minimumScale = 0.16; + /// Creates a `_CardMetrics.fromConstraints` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. factory _CardMetrics.fromConstraints( BoxConstraints constraints, { required TaskVisualKind kind, @@ -29,42 +52,122 @@ class _CardMetrics { return _CardMetrics(scale: scale.toDouble(), height: height); } + /// Stores the `scale` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final double scale; + + /// Stores the `height` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final double height; + /// Returns the derived `isCompact` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. bool get isCompact => height < _compactHeightThreshold; + /// Returns the derived `cardRadius` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get cardRadius => math.min(FocusFlowTokens.cardRadius * scale, height / 2); + + /// Returns the derived `borderWidth` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get borderWidth => math.max(0.75, 1.2 * scale); + + /// Returns the derived `shadowBlur` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get shadowBlur => isCompact ? 0 : 18 * scale; + + /// Returns the derived `shadowSpread` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get shadowSpread => isCompact ? 0 : scale; + + /// Returns the derived `statusRingSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get statusRingSize { final availableHeight = math.max(8, height - padding.vertical); return math.min(24, availableHeight * 0.78).toDouble(); } + /// Returns the derived `statusBorderWidth` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get statusBorderWidth => math.max(1.4, statusRingSize * 0.08); + + /// Returns the derived `statusIconSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get statusIconSize => statusRingSize * 0.58; + + /// Returns the derived `statusGap` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get statusGap => isCompact ? 7 : 22 * scale; + + /// Returns the derived `actionButtonSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get actionButtonSize => (30 * scale).clamp(14.0, 22.0).toDouble(); + + /// Returns the derived `actionIconSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get actionIconSize => (16 * scale).clamp(9.0, 13.0).toDouble(); + + /// Returns the derived `actionGap` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get actionGap => math.max(3, 5 * scale); + + /// Returns the derived `actionsWidth` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get actionsWidth => actionButtonSize * 4 + actionGap; + + /// Returns the derived `indicatorTop` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get indicatorTop => isCompact ? 0 : math.max(1, 2 * scale); + + /// Returns the derived `indicatorGap` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get indicatorGap => math.max(3, 5 * scale); + + /// Returns the derived `rewardIconSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get rewardIconSize => 14; + + /// Returns the derived `titleSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get titleSize => 10; + + /// Returns the derived `metaSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get metaSize => 7; + + /// Returns the derived `titleMetaGap` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get titleMetaGap => 4 * scale; + + /// Returns the derived `freeSlotTimeGap` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get freeSlotTimeGap => 10 * scale; + + /// Returns the derived `compactTextGap` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get compactTextGap => math.max(3, 8 * scale); + + /// Returns the derived `indicatorWidth` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get indicatorWidth => rewardIconSize + indicatorGap + difficultySize.width; + + /// Returns the derived `expandedTrailingReserve` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get expandedTrailingReserve => indicatorWidth + math.max(8, 12 * scale); + + /// Returns the derived `compactTrailingReserve` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get compactTrailingReserve => indicatorWidth + math.max(6, 8 * scale); + + /// Returns the derived `difficultySize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. Size get difficultySize => Size(26, 14); + + /// Returns the derived `padding` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. EdgeInsets get padding { if (isCompact) { return EdgeInsets.symmetric( diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/card_text.dart b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/card_text.dart index 8a579c2..7c147ec 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/card_text.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/card_text.dart @@ -1,16 +1,33 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_timeline_card.dart'; +/// Private implementation type for `_CardText` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _CardText extends StatelessWidget { + /// Creates a `_CardText` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _CardText({ required this.card, required this.color, required this.metrics, }); + /// Stores the `card` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final TimelineCardModel card; + + /// Stores the `color` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color color; + + /// Stores the `metrics` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final _CardMetrics metrics; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { final titleStyle = TextStyle( diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/compact_card_text.dart b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/compact_card_text.dart index dbc906b..e9a7f58 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/compact_card_text.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/compact_card_text.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_timeline_card.dart'; +/// Private implementation type for `_CompactCardText` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _CompactCardText extends StatelessWidget { + /// Creates a `_CompactCardText` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _CompactCardText({ required this.card, required this.color, @@ -8,11 +15,24 @@ class _CompactCardText extends StatelessWidget { required this.onStatusPressed, }); + /// Stores the `card` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final TimelineCardModel card; + + /// Stores the `color` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color color; + + /// Stores the `metrics` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final _CardMetrics metrics; + + /// Stores the `onStatusPressed` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final VoidCallback? onStatusPressed; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { final metaText = _compactMetaText(card); @@ -83,6 +103,8 @@ class _CompactCardText extends StatelessWidget { ); } + /// Runs the `_compactMetaText` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. String _compactMetaText(TimelineCardModel card) { if (card.visualKind == TaskVisualKind.freeSlot && card.timeText.isNotEmpty) { diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/expanded_card_content.dart b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/expanded_card_content.dart index 21740aa..4dede80 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/expanded_card_content.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/expanded_card_content.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_timeline_card.dart'; +/// Private implementation type for `_ExpandedCardContent` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _ExpandedCardContent extends StatelessWidget { + /// Creates a `_ExpandedCardContent` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _ExpandedCardContent({ required this.card, required this.colors, @@ -8,11 +15,24 @@ class _ExpandedCardContent extends StatelessWidget { required this.onStatusPressed, }); + /// Stores the `card` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final TimelineCardModel card; + + /// Stores the `colors` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final _CardColors colors; + + /// Stores the `metrics` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final _CardMetrics metrics; + + /// Stores the `onStatusPressed` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final VoidCallback? onStatusPressed; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return Row( diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/no_op_icon.dart b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/no_op_icon.dart index 983c6ea..0ad674e 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/no_op_icon.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/no_op_icon.dart @@ -1,16 +1,33 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_timeline_card.dart'; +/// Private implementation type for `_NoOpIcon` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _NoOpIcon extends StatelessWidget { + /// Creates a `_NoOpIcon` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _NoOpIcon({ required this.icon, required this.color, required this.metrics, }); + /// Stores the `icon` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final IconData icon; + + /// Stores the `color` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color color; + + /// Stores the `metrics` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final _CardMetrics metrics; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return Tooltip( diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/quick_actions.dart b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/quick_actions.dart index b42338d..1f09d0f 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/quick_actions.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/quick_actions.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_timeline_card.dart'; +/// Private implementation type for `_QuickActions` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _QuickActions extends StatelessWidget { + /// Creates a `_QuickActions` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _QuickActions({ required this.color, required this.backgroundColor, @@ -8,11 +15,24 @@ class _QuickActions extends StatelessWidget { required this.visible, }); + /// Stores the `color` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color color; + + /// Stores the `backgroundColor` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color backgroundColor; + + /// Stores the `metrics` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final _CardMetrics metrics; + + /// Stores the `visible` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool visible; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return ExcludeSemantics( diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/status_ring.dart b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/status_ring.dart index 6d31f11..97f0497 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/status_ring.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/status_ring.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_timeline_card.dart'; +/// Private implementation type for `_StatusRing` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _StatusRing extends StatelessWidget { + /// Creates a `_StatusRing` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _StatusRing({ required this.card, required this.color, @@ -8,11 +15,24 @@ class _StatusRing extends StatelessWidget { this.onPressed, }); + /// Stores the `card` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final TimelineCardModel card; + + /// Stores the `color` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color color; + + /// Stores the `metrics` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final _CardMetrics metrics; + + /// Stores the `onPressed` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final VoidCallback? onPressed; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { final border = Border.all(color: color, width: metrics.statusBorderWidth); diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/task_timeline_card_state.dart b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/task_timeline_card_state.dart index 4660beb..dac36c3 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/task_timeline_card_state.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/task_timeline_card_state.dart @@ -1,8 +1,17 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_timeline_card.dart'; +/// Private implementation type for `_TaskTimelineCardState` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _TaskTimelineCardState extends State { + /// Private state stored as `_isHovered` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. bool _isHovered = false; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { final card = widget.card; diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/trailing_controls.dart b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/trailing_controls.dart index a6aff39..79c59d7 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/task_card/trailing_controls.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/task_card/trailing_controls.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../task_timeline_card.dart'; +/// Private implementation type for `_TrailingControls` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _TrailingControls extends StatelessWidget { + /// Creates a `_TrailingControls` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _TrailingControls({ required this.card, required this.colors, @@ -8,11 +15,24 @@ class _TrailingControls extends StatelessWidget { required this.actionsVisible, }); + /// Stores the `card` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final TimelineCardModel card; + + /// Stores the `colors` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final _CardColors colors; + + /// Stores the `metrics` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final _CardMetrics metrics; + + /// Stores the `actionsVisible` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool actionsVisible; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return Row( diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/task_timeline_card.dart b/apps/focus_flow_flutter/lib/widgets/timeline/task_timeline_card.dart index 96b48bf..e75a043 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/task_timeline_card.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/task_timeline_card.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders Task Timeline Card pieces for the FocusFlow Flutter timeline. library; @@ -40,6 +43,8 @@ class TaskTimelineCard extends StatefulWidget { /// Callback invoked when the left status control is clicked. final VoidCallback? onStatusPressed; + /// Creates the mutable state object used by this stateful widget. + /// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin. @override State createState() => _TaskTimelineCardState(); } diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/timeline_axis.dart b/apps/focus_flow_flutter/lib/widgets/timeline/timeline_axis.dart index 8d795f9..0cde142 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/timeline_axis.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/timeline_axis.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders Timeline Axis pieces for the FocusFlow Flutter timeline. library; @@ -20,6 +23,8 @@ class TimelineAxis extends StatelessWidget { /// Vertical inset before the first timeline tick. final double topInset; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { final ticks = geometry.ticks(); diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/timeline_geometry.dart b/apps/focus_flow_flutter/lib/widgets/timeline/timeline_geometry.dart index 1556809..c0407ef 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/timeline_geometry.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/timeline_geometry.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders Timeline Geometry pieces for the FocusFlow Flutter timeline. library; @@ -60,6 +63,8 @@ class TimelineGeometry { ]; } + /// Performs the `operator ==` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override bool operator ==(Object other) { return identical(this, other) || @@ -70,6 +75,8 @@ class TimelineGeometry { other.minCardHeight == minCardHeight; } + /// Returns the derived `hashCode` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override int get hashCode { return Object.hash( @@ -80,6 +87,8 @@ class TimelineGeometry { ); } + /// Runs the `_labelFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static String _labelFor(int minutes) { final hour24 = (minutes ~/ 60) % 24; final minute = minutes % 60; diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view.dart b/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view.dart index e6a0a7a..25e7b19 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders Timeline View pieces for the FocusFlow Flutter timeline. library; @@ -49,6 +52,8 @@ class TimelineView extends StatefulWidget { /// Monotonic request number that allows repeated jumps to the same card. final int scrollRequest; + /// Creates the mutable state object used by this stateful widget. + /// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin. @override State createState() => _TimelineViewState(); } diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view/timeline_card_placement.dart b/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view/timeline_card_placement.dart index aecc8cd..cc1b702 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view/timeline_card_placement.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view/timeline_card_placement.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../timeline_view.dart'; +/// Private implementation type for `_TimelineCardPlacement` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _TimelineCardPlacement { + /// Creates a `_TimelineCardPlacement` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _TimelineCardPlacement({ required this.card, required this.lane, @@ -9,14 +16,32 @@ class _TimelineCardPlacement { required this.height, }); + /// Shared constant value for `_laneGap`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const _laneGap = 8.0; + /// Stores the `card` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final TimelineCardModel card; + + /// Stores the `lane` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int lane; + + /// Stores the `laneCount` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int laneCount; + + /// Stores the `top` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final double top; + + /// Stores the `height` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final double height; + /// Performs the `withCard` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. _TimelineCardPlacement withCard(TimelineCardModel nextCard) { if (identical(card, nextCard)) { return this; @@ -30,6 +55,8 @@ class _TimelineCardPlacement { ); } + /// Performs the `pack` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static List<_TimelineCardPlacement> pack( List cards, { required TimelineGeometry geometry, @@ -74,6 +101,8 @@ class _TimelineCardPlacement { return placements; } + /// Runs the `_packGroup` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static List<_TimelineCardPlacement> _packGroup( List group, { required TimelineGeometry geometry, @@ -113,6 +142,8 @@ class _TimelineCardPlacement { ]; } + /// Runs the `_visualStart` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static double _visualStart( TimelineCardModel card, TimelineGeometry geometry, @@ -120,21 +151,29 @@ class _TimelineCardPlacement { return geometry.yForMinutesSinceMidnight(card.startMinutes); } + /// Runs the `_visualEnd` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static double _visualEnd(TimelineCardModel card, TimelineGeometry geometry) { final duration = card.endMinutes - card.startMinutes; return _visualStart(card, geometry) + geometry.heightForDuration(duration); } + /// Performs the `left` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. double left(double trackWidth) { final laneWidth = _laneWidth(trackWidth); final laneGap = _laneGapForWidth(trackWidth); return FocusFlowTokens.cardHorizontalPadding + lane * (laneWidth + laneGap); } + /// Performs the `width` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. double width(double trackWidth) { return _laneWidth(trackWidth); } + /// Runs the `_availableWidth` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. double _availableWidth(double trackWidth) { final availableWidth = trackWidth - FocusFlowTokens.cardHorizontalPadding; if (availableWidth < 0) { @@ -143,12 +182,16 @@ class _TimelineCardPlacement { return availableWidth; } + /// Runs the `_laneWidth` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. double _laneWidth(double trackWidth) { final availableWidth = _availableWidth(trackWidth); final laneGap = _laneGapForWidth(trackWidth); return (availableWidth - laneGap * (laneCount - 1)) / laneCount; } + /// Runs the `_laneGapForWidth` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. double _laneGapForWidth(double trackWidth) { if (laneCount == 1) { return 0; diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view/timeline_scroll_behavior.dart b/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view/timeline_scroll_behavior.dart index 46472e1..581ee38 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view/timeline_scroll_behavior.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view/timeline_scroll_behavior.dart @@ -1,8 +1,17 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../timeline_view.dart'; +/// Private implementation type for `_TimelineScrollBehavior` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _TimelineScrollBehavior extends MaterialScrollBehavior { + /// Creates a `_TimelineScrollBehavior` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _TimelineScrollBehavior(); + /// Returns the derived `dragDevices` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override Set get dragDevices { return {...super.dragDevices, PointerDeviceKind.mouse}; diff --git a/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view/timeline_view_state.dart b/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view/timeline_view_state.dart index e2eca0c..c07a94b 100644 --- a/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view/timeline_view_state.dart +++ b/apps/focus_flow_flutter/lib/widgets/timeline/timeline_view/timeline_view_state.dart @@ -1,22 +1,53 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../timeline_view.dart'; +/// Private implementation type for `_TimelineViewState` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _TimelineViewState extends State { + /// Shared constant value for `_topInset`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const _topInset = 12.0; + /// Private state stored as `_scrollController` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final _scrollController = ScrollController(); + + /// Private state stored as `_didSetInitialScroll` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. bool _didSetInitialScroll = false; + + /// Private state stored as `_handledScrollRequest` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. var _handledScrollRequest = 0; + + /// Private state stored as `_geometry` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. late TimelineGeometry _geometry; + + /// Private state stored as `_contentHeight` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. late double _contentHeight; + + /// Private state stored as `_placements` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. late List<_TimelineCardPlacement> _placements; + + /// Private state stored as `_cardsLayoutHash` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. late int _cardsLayoutHash; + /// Initializes state owned by this object before the first build. + /// Use this lifecycle point for controller setup, initial reads, and listener wiring that must happen once per mounted instance. @override void initState() { super.initState(); _updateLayoutCache(); } + /// Performs the `didUpdateWidget` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override void didUpdateWidget(covariant TimelineView oldWidget) { super.didUpdateWidget(oldWidget); @@ -34,12 +65,16 @@ class _TimelineViewState extends State { } } + /// Releases resources owned by this object before it leaves the tree. + /// Controllers, listeners, and other disposable collaborators should be cleaned up here to avoid stale callbacks. @override void dispose() { _scrollController.dispose(); super.dispose(); } + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return LayoutBuilder( @@ -111,6 +146,8 @@ class _TimelineViewState extends State { ); } + /// Runs the `_updateLayoutCache` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. void _updateLayoutCache() { _geometry = TimelineGeometry( startMinutes: widget.range.startMinutes, @@ -125,6 +162,8 @@ class _TimelineViewState extends State { _cardsLayoutHash = _layoutHashFor(widget.cards); } + /// Runs the `_layoutHashFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. int _layoutHashFor(List cards) { return Object.hashAll( cards.map( @@ -133,6 +172,8 @@ class _TimelineViewState extends State { ); } + /// Runs the `_refreshPlacementCards` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. void _refreshPlacementCards() { final cardsById = {for (final card in widget.cards) card.id: card}; _placements = [ @@ -141,6 +182,8 @@ class _TimelineViewState extends State { ]; } + /// Runs the `_scheduleInitialScroll` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. void _scheduleInitialScroll( TimelineGeometry geometry, double viewportHeight, @@ -168,6 +211,8 @@ class _TimelineViewState extends State { }); } + /// Runs the `_scheduleTargetScroll` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. void _scheduleTargetScroll(TimelineGeometry geometry) { final targetCardId = widget.scrollTargetCardId; if (targetCardId == null || widget.scrollRequest == _handledScrollRequest) { diff --git a/apps/focus_flow_flutter/lib/widgets/today_pane.dart b/apps/focus_flow_flutter/lib/widgets/today_pane.dart index de0ec10..720adb9 100644 --- a/apps/focus_flow_flutter/lib/widgets/today_pane.dart +++ b/apps/focus_flow_flutter/lib/widgets/today_pane.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders the Today Pane widget for the FocusFlow Flutter UI. library; @@ -24,6 +27,8 @@ class TodayPane extends StatelessWidget { /// Optional command controller for Today actions. final SchedulerCommandController? commandController; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return ReadStateView( @@ -48,6 +53,8 @@ class TodayContent extends StatelessWidget { /// Optional command controller for completing tasks. final SchedulerCommandController? commandController; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return ListView( @@ -75,6 +82,8 @@ class TodayContent extends StatelessWidget { ); } + /// Runs the `_canComplete` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. bool _canComplete(TodayTimelineItem item) { return item.taskType == TaskType.flexible && item.taskStatus == TaskStatus.planned && diff --git a/apps/focus_flow_flutter/lib/widgets/top_bar.dart b/apps/focus_flow_flutter/lib/widgets/top_bar.dart index 98c5059..cf852bd 100644 --- a/apps/focus_flow_flutter/lib/widgets/top_bar.dart +++ b/apps/focus_flow_flutter/lib/widgets/top_bar.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Renders the Top Bar widget for the FocusFlow Flutter UI. library; @@ -18,6 +21,8 @@ class TopBar extends StatelessWidget { /// Date label shown beside the date navigation controls. final String dateLabel; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return LayoutBuilder( diff --git a/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_icon_button.dart b/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_icon_button.dart index f0bf92c..2a6d6cd 100644 --- a/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_icon_button.dart +++ b/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_icon_button.dart @@ -1,16 +1,33 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../top_bar.dart'; +/// Private implementation type for `_IconButton` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _IconButton extends StatelessWidget { + /// Creates a `_IconButton` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _IconButton({ required this.icon, required this.metrics, required this.onPressed, }); + /// Stores the `icon` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final IconData icon; + + /// Stores the `metrics` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final _TopBarMetrics metrics; + + /// Stores the `onPressed` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final VoidCallback onPressed; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return IconButton( diff --git a/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_metrics.dart b/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_metrics.dart index 37afaf9..d42e0a9 100644 --- a/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_metrics.dart +++ b/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_metrics.dart @@ -1,38 +1,116 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../top_bar.dart'; +/// Private implementation type for `_TopBarMetrics` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _TopBarMetrics { + /// Creates a `_TopBarMetrics` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _TopBarMetrics(this.scale); + /// Shared constant value for `referenceHeight`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const referenceHeight = 48.0; + + /// Shared constant value for `_referenceWidth`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const _referenceWidth = 900.0; + + /// Shared constant value for `_minimumScale`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const _minimumScale = 0.44; + /// Creates a `_TopBarMetrics.fromWidth` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. factory _TopBarMetrics.fromWidth(double width) { final safeWidth = width.isFinite ? width : _referenceWidth; final scale = (safeWidth / _referenceWidth).clamp(_minimumScale, 1.0); return _TopBarMetrics(scale.toDouble()); } + /// Stores the `scale` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final double scale; + /// Returns the derived `titleWidth` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get titleWidth => 112 * scale; + + /// Returns the derived `titleSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get titleSize => FocusFlowTokens.pageTitleSize * scale; + + /// Returns the derived `titleGap` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get titleGap => 30 * scale; + + /// Returns the derived `controlHeight` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get controlHeight => referenceHeight * scale; + + /// Returns the derived `iconButtonSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get iconButtonSize => referenceHeight * scale; + + /// Returns the derived `iconSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get iconSize => 24 * scale; + + /// Returns the derived `dateWidth` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get dateWidth => 144 * scale; + + /// Returns the derived `dateSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get dateSize => 17 * scale; + + /// Returns the derived `modeWidth` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get modeWidth => 220 * scale; + + /// Returns the derived `modeHeight` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get modeHeight => referenceHeight * scale; + + /// Returns the derived `modeLabelSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get modeLabelSize => 17 * scale; + + /// Returns the derived `settingsGap` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get settingsGap => 28 * scale; + + /// Returns the derived `settingsWidth` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get settingsWidth => 136 * scale; + + /// Returns the derived `settingsHeight` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get settingsHeight => referenceHeight * scale; + + /// Returns the derived `settingsIconSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get settingsIconSize => 20 * scale; + + /// Returns the derived `settingsTextSize` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get settingsTextSize => 15 * scale; + + /// Returns the derived `settingsTextGap` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get settingsTextGap => 8 * scale; + + /// Returns the derived `borderRadius` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get borderRadius => FocusFlowTokens.smallButtonRadius * scale; + + /// Returns the derived `borderWidth` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. double get borderWidth => scale < 0.7 ? 0.8 : 1; + + /// Returns the derived `buttonPadding` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. EdgeInsets get buttonPadding => EdgeInsets.symmetric(horizontal: 12 * scale); } diff --git a/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_mode_toggle.dart b/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_mode_toggle.dart index a5def8d..304e679 100644 --- a/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_mode_toggle.dart +++ b/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_mode_toggle.dart @@ -1,10 +1,21 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../top_bar.dart'; +/// Private implementation type for `_ModeToggle` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _ModeToggle extends StatelessWidget { + /// Creates a `_ModeToggle` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _ModeToggle({required this.metrics}); + /// Stores the `metrics` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final _TopBarMetrics metrics; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return Container( diff --git a/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_settings_button.dart b/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_settings_button.dart index 2a3166a..c356dcb 100644 --- a/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_settings_button.dart +++ b/apps/focus_flow_flutter/lib/widgets/top_bar/top_bar_settings_button.dart @@ -1,10 +1,21 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../top_bar.dart'; +/// Private implementation type for `_SettingsButton` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _SettingsButton extends StatelessWidget { + /// Creates a `_SettingsButton` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _SettingsButton({required this.metrics}); + /// Stores the `metrics` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final _TopBarMetrics metrics; + /// Builds the widget subtree for this component. + /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return OutlinedButton( diff --git a/apps/focus_flow_flutter/pubspec.yaml b/apps/focus_flow_flutter/pubspec.yaml index 9c43a91..6e6cf68 100644 --- a/apps/focus_flow_flutter/pubspec.yaml +++ b/apps/focus_flow_flutter/pubspec.yaml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + name: focus_flow_flutter description: Provisional Flutter UI foundation for FocusFlow. publish_to: 'none' diff --git a/apps/focus_flow_flutter/test/forbidden_imports_test.dart b/apps/focus_flow_flutter/test/forbidden_imports_test.dart index 2aaeaa6..02ead75 100644 --- a/apps/focus_flow_flutter/test/forbidden_imports_test.dart +++ b/apps/focus_flow_flutter/test/forbidden_imports_test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Forbidden Imports behavior in the FocusFlow Flutter app. library; @@ -33,6 +36,8 @@ void main() { }); } +/// Top-level helper that performs the `_dartFiles` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Iterable _dartFiles(Directory directory) { if (!directory.existsSync()) { return const []; @@ -43,6 +48,8 @@ Iterable _dartFiles(Directory directory) { .where((file) => file.path.endsWith('.dart')); } +/// Top-level helper that performs the `_forbiddenImportsFor` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List<_ForbiddenImport> _forbiddenImportsFor(String relativePath) { return [ const _ForbiddenImport( @@ -69,12 +76,23 @@ List<_ForbiddenImport> _forbiddenImportsFor(String relativePath) { ]; } +/// Private implementation type for `_ForbiddenImport` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _ForbiddenImport { + /// Creates a `_ForbiddenImport` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _ForbiddenImport(this.pattern, this.label); + /// Stores the `pattern` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String pattern; + + /// Stores the `label` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String label; + /// Performs the `matches` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. bool matches(String contents) { return RegExp( r'''import\s+['"]''' + RegExp.escape(pattern), diff --git a/apps/focus_flow_flutter/test/widget_test.dart b/apps/focus_flow_flutter/test/widget_test.dart index 00c6893..fb84af7 100644 --- a/apps/focus_flow_flutter/test/widget_test.dart +++ b/apps/focus_flow_flutter/test/widget_test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Widget behavior in the FocusFlow Flutter app. library; @@ -625,6 +628,8 @@ void main() { }); } +/// Top-level helper that performs the `_pumpPlanApp` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _pumpPlanApp( WidgetTester tester, { DemoSchedulerComposition? composition, @@ -637,10 +642,14 @@ Future _pumpPlanApp( await tester.pumpAndSettle(); } +/// Top-level helper that performs the `_composition` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. DemoSchedulerComposition _composition() { return DemoSchedulerComposition.seeded(selectedDate: CivilDate(2025, 5, 20)); } +/// Top-level helper that performs the `_readSeededToday` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _readSeededToday() async { final composition = _composition(); final result = await composition.todayQuery.execute( @@ -652,15 +661,21 @@ Future _readSeededToday() async { return result.requireValue; } +/// Top-level helper that performs the `_kindFor` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TaskVisualKind _kindFor(TodayScreenData data, String id) { return data.cards.singleWhere((card) => card.id == id).visualKind; } +/// Top-level helper that performs the `_scrollIntoView` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _scrollIntoView(WidgetTester tester, ValueKey key) async { await tester.ensureVisible(find.byKey(key)); await tester.pumpAndSettle(); } +/// Top-level helper that performs the `_pumpTimelineCard` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _pumpTimelineCard( WidgetTester tester, { required TimelineCardModel card, @@ -688,6 +703,8 @@ Future _pumpTimelineCard( await tester.pumpAndSettle(); } +/// Top-level helper that performs the `_pumpConstrainedWidget` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _pumpConstrainedWidget( WidgetTester tester, { required Size size, @@ -708,6 +725,8 @@ Future _pumpConstrainedWidget( await tester.pumpAndSettle(); } +/// Top-level helper that performs the `_timelineCard` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TimelineCardModel _timelineCard({ required String id, required String title, diff --git a/packages/scheduler_backup/LICENSE.md b/packages/scheduler_backup/LICENSE.md new file mode 100644 index 0000000..16fafd9 --- /dev/null +++ b/packages/scheduler_backup/LICENSE.md @@ -0,0 +1,6 @@ + + + +# License + +This package uses the repository-level license at [../../LICENSE.md](../../LICENSE.md). diff --git a/packages/scheduler_backup/analysis_options.yaml b/packages/scheduler_backup/analysis_options.yaml index 572dd23..7df02e8 100644 --- a/packages/scheduler_backup/analysis_options.yaml +++ b/packages/scheduler_backup/analysis_options.yaml @@ -1 +1,4 @@ -include: package:lints/recommended.yaml +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + +include: ../../analysis_options.yaml diff --git a/packages/scheduler_backup/bin/backup.dart b/packages/scheduler_backup/bin/backup.dart index 189ecc6..271c2e5 100644 --- a/packages/scheduler_backup/bin/backup.dart +++ b/packages/scheduler_backup/bin/backup.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Runs the Backup command for the Scheduler Backup package. library; @@ -5,6 +8,8 @@ import 'dart:io'; import 'package:scheduler_backup/backup.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. Future main(List arguments) async { final passphrase = _option(arguments, '--passphrase') ?? Platform.environment['SCHEDULER_BACKUP_PASSPHRASE']; @@ -25,6 +30,8 @@ Future main(List arguments) async { } } +/// Top-level helper that performs the `_option` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _option(List arguments, String name) { final index = arguments.indexOf(name); if (index == -1 || index + 1 >= arguments.length) { diff --git a/packages/scheduler_backup/lib/backup.dart b/packages/scheduler_backup/lib/backup.dart index d5c4e44..8877a48 100644 --- a/packages/scheduler_backup/lib/backup.dart +++ b/packages/scheduler_backup/lib/backup.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Encrypted SQLite backup helpers. library; diff --git a/packages/scheduler_backup/lib/scheduler_backup.dart b/packages/scheduler_backup/lib/scheduler_backup.dart index 4f65026..de9885e 100644 --- a/packages/scheduler_backup/lib/scheduler_backup.dart +++ b/packages/scheduler_backup/lib/scheduler_backup.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Package-name entry point for scheduler backup helpers. library; diff --git a/packages/scheduler_backup/lib/src/encrypted_backup.dart b/packages/scheduler_backup/lib/src/encrypted_backup.dart index 58d0ef2..1169931 100644 --- a/packages/scheduler_backup/lib/src/encrypted_backup.dart +++ b/packages/scheduler_backup/lib/src/encrypted_backup.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Encrypted Backup behavior for the Scheduler Backup package. library; @@ -23,11 +26,30 @@ const defaultSchedulerDatabaseFileName = 'scheduler.sqlite'; /// Default encrypted backup directory name under the scheduler data directory. const defaultSchedulerBackupDirectoryName = 'backups'; +/// Private file-level value for `_formatMagic`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _formatMagic = 'ADHD_SCHEDULER_BACKUP_V1'; + +/// Private file-level value for `_fileExtension`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _fileExtension = '.db.enc'; + +/// Private file-level value for `_kdfIterations`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _kdfIterations = 200000; + +/// Private file-level value for `_saltLength`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _saltLength = 16; + +/// Private file-level value for `_nonceLength`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _nonceLength = 12; + +/// Private file-level value for `_keyLength`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _keyLength = 32; +/// Private file-level value for `_utf8`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. final _utf8 = utf8.encoder; diff --git a/packages/scheduler_backup/lib/src/encrypted_backup/codec/backup_encryption_codec.dart b/packages/scheduler_backup/lib/src/encrypted_backup/codec/backup_encryption_codec.dart index d983714..00b43ff 100644 --- a/packages/scheduler_backup/lib/src/encrypted_backup/codec/backup_encryption_codec.dart +++ b/packages/scheduler_backup/lib/src/encrypted_backup/codec/backup_encryption_codec.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../encrypted_backup.dart'; +/// Top-level helper that performs the `_encryptBytes` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future> _encryptBytes({ required String passphrase, required List plaintext, @@ -26,6 +31,8 @@ Future> _encryptBytes({ return _utf8.convert(jsonEncode(envelope)); } +/// Top-level helper that performs the `_decryptBytes` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future> _decryptBytes({ required String passphrase, required List encoded, @@ -56,6 +63,8 @@ Future> _decryptBytes({ } } +/// Top-level helper that performs the `_deriveKey` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _deriveKey({ required String passphrase, required List salt, @@ -71,6 +80,8 @@ Future _deriveKey({ ); } +/// Top-level helper that performs the `_randomBytes` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _randomBytes(int length) { final random = Random.secure(); return Uint8List.fromList( diff --git a/packages/scheduler_backup/lib/src/encrypted_backup/errors/backup_decryption_exception.dart b/packages/scheduler_backup/lib/src/encrypted_backup/errors/backup_decryption_exception.dart index 0b53184..6820bb1 100644 --- a/packages/scheduler_backup/lib/src/encrypted_backup/errors/backup_decryption_exception.dart +++ b/packages/scheduler_backup/lib/src/encrypted_backup/errors/backup_decryption_exception.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../encrypted_backup.dart'; /// Thrown when an encrypted backup cannot be decrypted with the passphrase. @@ -10,6 +13,8 @@ final class BackupDecryptionException implements Exception { /// Diagnostic text for logs and tests. final String message; + /// Converts scheduler data for `toString` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. @override String toString() => 'BackupDecryptionException: $message'; } diff --git a/packages/scheduler_backup/lib/src/encrypted_backup/errors/backup_exception.dart b/packages/scheduler_backup/lib/src/encrypted_backup/errors/backup_exception.dart index 8a36df4..7133193 100644 --- a/packages/scheduler_backup/lib/src/encrypted_backup/errors/backup_exception.dart +++ b/packages/scheduler_backup/lib/src/encrypted_backup/errors/backup_exception.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../encrypted_backup.dart'; /// Thrown when backup input paths or file contents are invalid. @@ -8,6 +11,8 @@ final class BackupException implements Exception { /// Diagnostic text for logs and tests. final String message; + /// Converts scheduler data for `toString` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. @override String toString() => 'BackupException: $message'; } diff --git a/packages/scheduler_backup/lib/src/encrypted_backup/operations/encrypted_backup_operations.dart b/packages/scheduler_backup/lib/src/encrypted_backup/operations/encrypted_backup_operations.dart index 80ee099..9174859 100644 --- a/packages/scheduler_backup/lib/src/encrypted_backup/operations/encrypted_backup_operations.dart +++ b/packages/scheduler_backup/lib/src/encrypted_backup/operations/encrypted_backup_operations.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../encrypted_backup.dart'; /// Create an encrypted backup of the scheduler SQLite file. diff --git a/packages/scheduler_backup/lib/src/encrypted_backup/paths/backup_file_names.dart b/packages/scheduler_backup/lib/src/encrypted_backup/paths/backup_file_names.dart index a596959..2c91a8e 100644 --- a/packages/scheduler_backup/lib/src/encrypted_backup/paths/backup_file_names.dart +++ b/packages/scheduler_backup/lib/src/encrypted_backup/paths/backup_file_names.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../encrypted_backup.dart'; +/// Top-level helper that performs the `_nextAvailableBackupFile` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _nextAvailableBackupFile(Directory directory, String name) async { final preferred = File(_joinPath(directory.path, name)); if (!await preferred.exists()) { @@ -19,12 +24,18 @@ Future _nextAvailableBackupFile(Directory directory, String name) async { } } +/// Top-level helper that performs the `_backupTimestamp` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _backupTimestamp(DateTime value) { final local = value.toLocal(); return '${_four(local.year)}${_two(local.month)}${_two(local.day)}_' '${_two(local.hour)}${_two(local.minute)}'; } +/// Top-level helper that performs the `_four` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _four(int value) => value.toString().padLeft(4, '0'); +/// Top-level helper that performs the `_two` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _two(int value) => value.toString().padLeft(2, '0'); diff --git a/packages/scheduler_backup/lib/src/encrypted_backup/paths/backup_paths.dart b/packages/scheduler_backup/lib/src/encrypted_backup/paths/backup_paths.dart index 8cb5cba..2bd5e85 100644 --- a/packages/scheduler_backup/lib/src/encrypted_backup/paths/backup_paths.dart +++ b/packages/scheduler_backup/lib/src/encrypted_backup/paths/backup_paths.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../encrypted_backup.dart'; /// Default scheduler SQLite database path. @@ -18,6 +21,8 @@ Directory defaultSchedulerBackupDirectory() { )); } +/// Top-level helper that performs the `_homeDirectory` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Directory _homeDirectory() { final home = Platform.environment['HOME'] ?? Platform.environment['USERPROFILE'] ?? @@ -28,6 +33,8 @@ Directory _homeDirectory() { return Directory(home); } +/// Top-level helper that performs the `_joinPath` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _joinPath(String first, String second, [String? third]) { final separator = Platform.pathSeparator; final left = first.endsWith(separator) diff --git a/packages/scheduler_backup/pubspec.yaml b/packages/scheduler_backup/pubspec.yaml index 277051a..1c8bf80 100644 --- a/packages/scheduler_backup/pubspec.yaml +++ b/packages/scheduler_backup/pubspec.yaml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + name: scheduler_backup description: Encrypted SQLite backup and restore helpers for the ADHD scheduler. version: 0.1.0 diff --git a/packages/scheduler_backup/test/encrypted_backup_test.dart b/packages/scheduler_backup/test/encrypted_backup_test.dart index ad8b370..3917e92 100644 --- a/packages/scheduler_backup/test/encrypted_backup_test.dart +++ b/packages/scheduler_backup/test/encrypted_backup_test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Encrypted Backup behavior for the Scheduler Backup package. library; @@ -7,6 +10,8 @@ import 'dart:io'; import 'package:scheduler_backup/backup.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { test('encrypted backup round trips a SQLite file using temp paths', () async { final temp = diff --git a/packages/scheduler_core/LICENSE.md b/packages/scheduler_core/LICENSE.md new file mode 100644 index 0000000..16fafd9 --- /dev/null +++ b/packages/scheduler_core/LICENSE.md @@ -0,0 +1,6 @@ + + + +# License + +This package uses the repository-level license at [../../LICENSE.md](../../LICENSE.md). diff --git a/packages/scheduler_core/analysis_options.yaml b/packages/scheduler_core/analysis_options.yaml index bcfdce3..7df02e8 100644 --- a/packages/scheduler_core/analysis_options.yaml +++ b/packages/scheduler_core/analysis_options.yaml @@ -1,13 +1,4 @@ -include: package:lints/recommended.yaml +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only -analyzer: - language: - strict-casts: true - strict-inference: true - strict-raw-types: true - -linter: - rules: - prefer_final_locals: true - prefer_final_fields: true - avoid_print: true +include: ../../analysis_options.yaml diff --git a/packages/scheduler_core/lib/scheduler_core.dart b/packages/scheduler_core/lib/scheduler_core.dart index 3cc60dd..a8eb15a 100644 --- a/packages/scheduler_core/lib/scheduler_core.dart +++ b/packages/scheduler_core/lib/scheduler_core.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Defines the Scheduler Core public library for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/application_commands.dart b/packages/scheduler_core/lib/src/application_commands.dart index cd1762d..657ff56 100644 --- a/packages/scheduler_core/lib/src/application_commands.dart +++ b/packages/scheduler_core/lib/src/application_commands.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Application Commands behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/application_commands/codes/application_command_code.dart b/packages/scheduler_core/lib/src/application_commands/codes/application_command_code.dart index 84b3eeb..4cc4509 100644 --- a/packages/scheduler_core/lib/src/application_commands/codes/application_command_code.dart +++ b/packages/scheduler_core/lib/src/application_commands/codes/application_command_code.dart @@ -1,22 +1,75 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_commands.dart'; /// Stable V1 application command identifiers. enum ApplicationCommandCode { + /// Selects the `quickCaptureToBacklog` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. quickCaptureToBacklog, + + /// Selects the `quickCaptureToNextAvailableSlot` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. quickCaptureToNextAvailableSlot, + + /// Selects the `scheduleBacklogItemToNextAvailableSlot` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. scheduleBacklogItemToNextAvailableSlot, + + /// Selects the `pushFlexibleToNextAvailableSlot` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. pushFlexibleToNextAvailableSlot, + + /// Selects the `pushFlexibleToTomorrowTopOfQueue` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. pushFlexibleToTomorrowTopOfQueue, + + /// Selects the `moveFlexibleToBacklog` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. moveFlexibleToBacklog, + + /// Selects the `completeFlexibleTask` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. completeFlexibleTask, + + /// Selects the `uncompleteTask` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. uncompleteTask, + + /// Selects the `applyRequiredTaskAction` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. applyRequiredTaskAction, + + /// Selects the `logSurpriseTask` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. logSurpriseTask, + + /// Selects the `createProtectedFreeSlot` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. createProtectedFreeSlot, + + /// Selects the `updateProtectedFreeSlot` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. updateProtectedFreeSlot, + + /// Selects the `removeProtectedFreeSlot` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. removeProtectedFreeSlot, + + /// Selects the `breakUpTask` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. breakUpTask, + + /// Selects the `completeChildTask` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. completeChildTask, + + /// Selects the `completeParentTask` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. completeParentTask, + + /// Selects the `completeParentFromChild` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. completeParentFromChild, } diff --git a/packages/scheduler_core/lib/src/application_commands/messages/application_child_task_draft.dart b/packages/scheduler_core/lib/src/application_commands/messages/application_child_task_draft.dart index 4bafc31..49a9086 100644 --- a/packages/scheduler_core/lib/src/application_commands/messages/application_child_task_draft.dart +++ b/packages/scheduler_core/lib/src/application_commands/messages/application_child_task_draft.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_commands.dart'; /// Draft row for creating one child task from an application command. class ApplicationChildTaskDraft { + /// Creates a `ApplicationChildTaskDraft` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ApplicationChildTaskDraft({ required this.title, this.priority, diff --git a/packages/scheduler_core/lib/src/application_commands/messages/application_command_read_hint.dart b/packages/scheduler_core/lib/src/application_commands/messages/application_command_read_hint.dart index 1897022..9f339cd 100644 --- a/packages/scheduler_core/lib/src/application_commands/messages/application_command_read_hint.dart +++ b/packages/scheduler_core/lib/src/application_commands/messages/application_command_read_hint.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_commands.dart'; /// Hint for read models that should be refreshed after a command. class ApplicationCommandReadHint { + /// Creates a `ApplicationCommandReadHint` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. ApplicationCommandReadHint({ CivilDate? localDate, Iterable affectedDates = const [], diff --git a/packages/scheduler_core/lib/src/application_commands/messages/application_command_result.dart b/packages/scheduler_core/lib/src/application_commands/messages/application_command_result.dart index d6b8722..e957201 100644 --- a/packages/scheduler_core/lib/src/application_commands/messages/application_command_result.dart +++ b/packages/scheduler_core/lib/src/application_commands/messages/application_command_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_commands.dart'; /// Structured result returned by V1 application commands. class ApplicationCommandResult { + /// Creates a `ApplicationCommandResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. ApplicationCommandResult({ required this.commandCode, required String operationId, diff --git a/packages/scheduler_core/lib/src/application_commands/planning/planning_state.dart b/packages/scheduler_core/lib/src/application_commands/planning/planning_state.dart index 5902833..9e1be77 100644 --- a/packages/scheduler_core/lib/src/application_commands/planning/planning_state.dart +++ b/packages/scheduler_core/lib/src/application_commands/planning/planning_state.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_commands.dart'; +/// Private implementation type for `_PlanningState` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _PlanningState { + /// Creates a `_PlanningState` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _PlanningState({ required List tasks, required this.window, @@ -8,10 +15,20 @@ class _PlanningState { }) : tasks = List.unmodifiable(tasks), lockedIntervals = List.unmodifiable(lockedIntervals); + /// Stores the `tasks` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final List tasks; + + /// Stores the `window` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final SchedulingWindow window; + + /// Stores the `lockedIntervals` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final List lockedIntervals; + /// Returns the derived `input` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. SchedulingInput get input { return SchedulingInput( tasks: tasks, @@ -20,6 +37,8 @@ class _PlanningState { ); } + /// Performs the `withTask` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. _PlanningState withTask(Task task) { if (tasks.any((existing) => existing.id == task.id)) { return this; @@ -31,6 +50,8 @@ class _PlanningState { ); } + /// Performs the `replaceTask` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. _PlanningState replaceTask(Task replacement) { return _PlanningState( tasks: _replaceTask(tasks, replacement), @@ -40,6 +61,8 @@ class _PlanningState { } } +/// Top-level helper that performs the `_failure` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. ApplicationResult _failure( ApplicationFailureCode code, { String? entityId, @@ -54,6 +77,8 @@ ApplicationResult _failure( ); } +/// Top-level helper that performs the `_failureForQuickCapture` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. ApplicationResult _failureForQuickCapture( QuickCaptureResult result, ) { @@ -75,6 +100,8 @@ ApplicationResult _failureForQuickCapture( ); } +/// Top-level helper that performs the `_failureForSchedulingResult` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. ApplicationFailure? _failureForSchedulingResult( SchedulingResult result, { required String entityId, @@ -102,6 +129,8 @@ ApplicationFailure? _failureForSchedulingResult( }; } +/// Top-level helper that performs the `_staleFailure` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. ApplicationFailure? _staleFailure(Task task, DateTime? expectedUpdatedAt) { if (expectedUpdatedAt == null || _sameNullableInstant(task.updatedAt, expectedUpdatedAt)) { @@ -114,6 +143,8 @@ ApplicationFailure? _staleFailure(Task task, DateTime? expectedUpdatedAt) { ); } +/// Top-level helper that performs the `_activitiesForSchedulingChanges` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _activitiesForSchedulingChanges({ required SchedulingResult? result, required List beforeTasks, @@ -159,6 +190,8 @@ List _activitiesForSchedulingChanges({ return List.unmodifiable(activities); } +/// Top-level helper that performs the `_nextStatusForChange` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TaskStatus _nextStatusForChange(Task task, TaskActivityCode code) { if (code == TaskActivityCode.restoredFromBacklog) { return TaskStatus.planned; @@ -170,6 +203,8 @@ TaskStatus _nextStatusForChange(Task task, TaskActivityCode code) { return task.status; } +/// Top-level helper that performs the `_changedTasks` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _changedTasks(List beforeTasks, List afterTasks) { final beforeById = { for (final task in beforeTasks) task.id: task, @@ -186,10 +221,14 @@ List _changedTasks(List beforeTasks, List afterTasks) { return List.unmodifiable(changed); } +/// Top-level helper that performs the `_changedTaskIds` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _changedTaskIds(List beforeTasks, List afterTasks) { return _taskIdsFromTasks(_changedTasks(beforeTasks, afterTasks)); } +/// Top-level helper that performs the `_taskChanged` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _taskChanged(Task before, Task after) { return before.title != after.title || before.projectId != after.projectId || @@ -209,6 +248,8 @@ bool _taskChanged(Task before, Task after) { before.stats != after.stats; } +/// Top-level helper that performs the `_sameNullableInstant` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _sameNullableInstant(DateTime? first, DateTime? second) { if (first == null || second == null) { return first == null && second == null; @@ -217,6 +258,8 @@ bool _sameNullableInstant(DateTime? first, DateTime? second) { return first.isAtSameMomentAs(second); } +/// Top-level helper that performs the `_taskById` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Task? _taskById(List tasks, String taskId) { for (final task in tasks) { if (task.id == taskId) { @@ -227,22 +270,30 @@ Task? _taskById(List tasks, String taskId) { return null; } +/// Top-level helper that performs the `_replaceTask` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _replaceTask(List tasks, Task replacement) { return tasks .map((task) => task.id == replacement.id ? replacement : task) .toList(growable: false); } +/// Top-level helper that performs the `_taskIdsFromChanges` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _taskIdsFromChanges(List changes) { return List.unmodifiable( changes.map((change) => change.taskId).toSet(), ); } +/// Top-level helper that performs the `_taskIdsFromTasks` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _taskIdsFromTasks(List tasks) { return List.unmodifiable(tasks.map((task) => task.id).toSet()); } +/// Top-level helper that performs the `_requiredTrimmed` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredTrimmed(String value, String name) { final trimmed = value.trim(); if (trimmed.isEmpty) { diff --git a/packages/scheduler_core/lib/src/application_commands/use_cases/v1_application_command_use_cases.dart b/packages/scheduler_core/lib/src/application_commands/use_cases/v1_application_command_use_cases.dart index fa8498c..245753c 100644 --- a/packages/scheduler_core/lib/src/application_commands/use_cases/v1_application_command_use_cases.dart +++ b/packages/scheduler_core/lib/src/application_commands/use_cases/v1_application_command_use_cases.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_commands.dart'; /// UI-facing V1 command use cases. class V1ApplicationCommandUseCases { + /// Creates a `V1ApplicationCommandUseCases` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const V1ApplicationCommandUseCases({ required this.applicationStore, required this.timeZoneResolver, @@ -26,13 +31,36 @@ class V1ApplicationCommandUseCases { /// DST/nonexistent/repeated local time policy. final TimeZoneResolutionOptions resolutionOptions; + /// Stores the `quickCaptureService` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final QuickCaptureService quickCaptureService; + + /// Stores the `flexibleTaskActionService` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final FlexibleTaskActionService flexibleTaskActionService; + + /// Stores the `requiredTaskActionService` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final RequiredTaskActionService requiredTaskActionService; + + /// Stores the `surpriseTaskLogService` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final SurpriseTaskLogService surpriseTaskLogService; + + /// Stores the `freeSlotService` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final FreeSlotService freeSlotService; + + /// Stores the `childTaskBreakUpService` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ChildTaskBreakUpService childTaskBreakUpService; + + /// Stores the `childTaskCompletionService` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ChildTaskCompletionService childTaskCompletionService; + + /// Stores the `projectStatisticsAggregationService` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ProjectStatisticsAggregationService projectStatisticsAggregationService; /// Quick capture a task into backlog. @@ -840,6 +868,8 @@ class V1ApplicationCommandUseCases { ); } + /// Runs the `_pushFlexible` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> _pushFlexible({ required ApplicationCommandCode commandCode, required ApplicationOperationContext context, @@ -901,6 +931,8 @@ class V1ApplicationCommandUseCases { ); } + /// Runs the `_completeChildOrParent` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> _completeChildOrParent({ required ApplicationCommandCode commandCode, required ApplicationOperationContext context, @@ -946,6 +978,8 @@ class V1ApplicationCommandUseCases { ); } + /// Runs the `_loadPlanningState` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future<_PlanningState> _loadPlanningState( ApplicationUnitOfWorkRepositories repositories, ApplicationOperationContext context, @@ -997,6 +1031,8 @@ class V1ApplicationCommandUseCases { ); } + /// Runs the `_resolve` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. DateTime _resolve({ required CivilDate date, required WallTime wallTime, @@ -1012,6 +1048,8 @@ class V1ApplicationCommandUseCases { .instant; } + /// Runs the `_persist` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> _persist({ required ApplicationUnitOfWorkRepositories repositories, required ApplicationCommandCode commandCode, @@ -1052,6 +1090,8 @@ class V1ApplicationCommandUseCases { ); } + /// Runs the `_saveProjectStatistics` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> _saveProjectStatistics({ required ApplicationUnitOfWorkRepositories repositories, required List activities, diff --git a/packages/scheduler_core/lib/src/application_layer.dart b/packages/scheduler_core/lib/src/application_layer.dart index 57e1f3e..a19fb48 100644 --- a/packages/scheduler_core/lib/src/application_layer.dart +++ b/packages/scheduler_core/lib/src/application_layer.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Application Layer behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/application_layer/context/application_operation_context.dart b/packages/scheduler_core/lib/src/application_layer/context/application_operation_context.dart index 858b21d..23ffa0e 100644 --- a/packages/scheduler_core/lib/src/application_layer/context/application_operation_context.dart +++ b/packages/scheduler_core/lib/src/application_layer/context/application_operation_context.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_layer.dart'; /// Per-operation application context. class ApplicationOperationContext { + /// Creates a `ApplicationOperationContext` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. ApplicationOperationContext({ required String operationId, required this.now, diff --git a/packages/scheduler_core/lib/src/application_layer/context/owner_time_zone_context.dart b/packages/scheduler_core/lib/src/application_layer/context/owner_time_zone_context.dart index 342e739..59ad45e 100644 --- a/packages/scheduler_core/lib/src/application_layer/context/owner_time_zone_context.dart +++ b/packages/scheduler_core/lib/src/application_layer/context/owner_time_zone_context.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_layer.dart'; /// Owner-local time context supplied to application operations. class OwnerTimeZoneContext { + /// Creates a `OwnerTimeZoneContext` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. OwnerTimeZoneContext({ required String ownerId, required String timeZoneId, diff --git a/packages/scheduler_core/lib/src/application_layer/loading/application_scheduling_loader.dart b/packages/scheduler_core/lib/src/application_layer/loading/application_scheduling_loader.dart index 68423bf..8b29ed1 100644 --- a/packages/scheduler_core/lib/src/application_layer/loading/application_scheduling_loader.dart +++ b/packages/scheduler_core/lib/src/application_layer/loading/application_scheduling_loader.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_layer.dart'; /// Repository loader for common scheduler input assembly. class ApplicationSchedulingLoader { + /// Creates a `ApplicationSchedulingLoader` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ApplicationSchedulingLoader(this.repositories); /// Repositories for the current application operation. diff --git a/packages/scheduler_core/lib/src/application_layer/records/application_operation_record.dart b/packages/scheduler_core/lib/src/application_layer/records/application_operation_record.dart index 342e82c..4f256c5 100644 --- a/packages/scheduler_core/lib/src/application_layer/records/application_operation_record.dart +++ b/packages/scheduler_core/lib/src/application_layer/records/application_operation_record.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_layer.dart'; /// Persisted exactly-once operation record. class ApplicationOperationRecord { + /// Creates a `ApplicationOperationRecord` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. ApplicationOperationRecord({ required String operationId, required String ownerId, diff --git a/packages/scheduler_core/lib/src/application_layer/records/notice_acknowledgement_record.dart b/packages/scheduler_core/lib/src/application_layer/records/notice_acknowledgement_record.dart index 86afa0b..637268d 100644 --- a/packages/scheduler_core/lib/src/application_layer/records/notice_acknowledgement_record.dart +++ b/packages/scheduler_core/lib/src/application_layer/records/notice_acknowledgement_record.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_layer.dart'; /// Owner-scoped acknowledgement for a one-time scheduling notice. class NoticeAcknowledgementRecord { + /// Creates a `NoticeAcknowledgementRecord` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. NoticeAcknowledgementRecord({ required String noticeId, required String ownerId, diff --git a/packages/scheduler_core/lib/src/application_layer/records/owner_settings.dart b/packages/scheduler_core/lib/src/application_layer/records/owner_settings.dart index af4fc7b..9c9d24f 100644 --- a/packages/scheduler_core/lib/src/application_layer/records/owner_settings.dart +++ b/packages/scheduler_core/lib/src/application_layer/records/owner_settings.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_layer.dart'; /// Owner-level settings needed by application use cases. class OwnerSettings { + /// Creates a `OwnerSettings` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. OwnerSettings({ required String ownerId, required String timeZoneId, diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/in_memory/in_memory_application_repositories.dart b/packages/scheduler_core/lib/src/application_layer/repositories/in_memory/in_memory_application_repositories.dart index bf071ae..a572a2a 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/in_memory/in_memory_application_repositories.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/in_memory/in_memory_application_repositories.dart @@ -1,7 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../application_layer.dart'; +/// Private implementation type for `_InMemoryApplicationRepositories` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _InMemoryApplicationRepositories implements ApplicationUnitOfWorkRepositories { + /// Creates a `_InMemoryApplicationRepositories` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _InMemoryApplicationRepositories(_InMemoryApplicationState state) : tasks = _UnitOfWorkTaskRepository( tasksById: state.tasksById, @@ -43,30 +50,48 @@ class _InMemoryApplicationRepositories ), operations = _UnitOfWorkOperationRepository(state.operationsById); + /// Stores the `tasks` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. @override final TaskRepository tasks; + /// Stores the `projects` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. @override final ProjectRepository projects; + /// Stores the `lockedBlocks` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. @override final LockedBlockRepository lockedBlocks; + /// Stores the `schedulingSnapshots` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. @override final SchedulingSnapshotRepository schedulingSnapshots; + /// Stores the `taskActivities` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. @override final TaskActivityRepository taskActivities; + /// Stores the `projectStatistics` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. @override final ProjectStatisticsRepository projectStatistics; + /// Stores the `ownerSettings` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. @override final OwnerSettingsRepository ownerSettings; + /// Stores the `noticeAcknowledgements` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. @override final NoticeAcknowledgementRepository noticeAcknowledgements; + /// Stores the `operations` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. @override final ApplicationOperationRepository operations; } diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/in_memory/in_memory_application_state.dart b/packages/scheduler_core/lib/src/application_layer/repositories/in_memory/in_memory_application_state.dart index 28649a5..effc9ca 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/in_memory/in_memory_application_state.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/in_memory/in_memory_application_state.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../application_layer.dart'; +/// Private implementation type for `_InMemoryApplicationState` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _InMemoryApplicationState { + /// Creates a `_InMemoryApplicationState` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _InMemoryApplicationState({ required this.tasksById, required this.taskOwnersById, @@ -27,31 +34,101 @@ class _InMemoryApplicationState { required this.operationsById, }); + /// Stores the `tasksById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map tasksById; + + /// Stores the `taskOwnersById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map taskOwnersById; + + /// Stores the `taskRevisionsById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map taskRevisionsById; + + /// Stores the `projectsById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map projectsById; + + /// Stores the `projectOwnersById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map projectOwnersById; + + /// Stores the `projectRevisionsById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map projectRevisionsById; + + /// Stores the `lockedBlocksById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map lockedBlocksById; + + /// Stores the `lockedBlockOwnersById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map lockedBlockOwnersById; + + /// Stores the `lockedBlockRevisionsById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map lockedBlockRevisionsById; + + /// Stores the `lockedOverridesById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map lockedOverridesById; + + /// Stores the `lockedOverrideOwnersById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map lockedOverrideOwnersById; + + /// Stores the `lockedOverrideRevisionsById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map lockedOverrideRevisionsById; + + /// Stores the `schedulingSnapshotsById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map schedulingSnapshotsById; + + /// Stores the `taskActivitiesById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map taskActivitiesById; + + /// Stores the `taskActivityOwnersById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map taskActivityOwnersById; + + /// Stores the `projectStatisticsByProjectId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map projectStatisticsByProjectId; + + /// Stores the `projectStatisticsOwnersByProjectId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map projectStatisticsOwnersByProjectId; + + /// Stores the `projectStatisticsRevisionsByProjectId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map projectStatisticsRevisionsByProjectId; + + /// Stores the `ownerSettingsByOwnerId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map ownerSettingsByOwnerId; + + /// Stores the `ownerSettingsRevisionsByOwnerId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map ownerSettingsRevisionsByOwnerId; + + /// Stores the `noticeAcknowledgementsByScopedId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map noticeAcknowledgementsByScopedId; + + /// Stores the `noticeAcknowledgementRevisionsByScopedId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map noticeAcknowledgementRevisionsByScopedId; + + /// Stores the `operationsById` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Map operationsById; + /// Performs the `copy` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. _InMemoryApplicationState copy() { return _InMemoryApplicationState( tasksById: Map.of(tasksById), diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/in_memory/in_memory_application_unit_of_work.dart b/packages/scheduler_core/lib/src/application_layer/repositories/in_memory/in_memory_application_unit_of_work.dart index 4cf69c1..d3049dc 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/in_memory/in_memory_application_unit_of_work.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/in_memory/in_memory_application_unit_of_work.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../application_layer.dart'; /// In-memory unit-of-work implementation for deterministic application tests. class InMemoryApplicationUnitOfWork implements ApplicationUnitOfWork { + /// Creates a `InMemoryApplicationUnitOfWork` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. InMemoryApplicationUnitOfWork({ Iterable initialTasks = const [], Iterable initialProjects = const [], @@ -107,7 +112,12 @@ class InMemoryApplicationUnitOfWork implements ApplicationUnitOfWork { }, ); + /// Private state stored as `_state` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. _InMemoryApplicationState _state; + + /// Private state stored as `_failNextCommit` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. bool _failNextCommit = false; /// Current committed tasks, useful for contract tests. @@ -175,6 +185,8 @@ class InMemoryApplicationUnitOfWork implements ApplicationUnitOfWork { _failNextCommit = true; } + /// Runs the `run` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> run({ required ApplicationOperationContext context, @@ -244,6 +256,8 @@ class InMemoryApplicationUnitOfWork implements ApplicationUnitOfWork { } } + /// Runs the `read` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> read({ required Future> Function( diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/application/application_operation_repository.dart b/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/application/application_operation_repository.dart index 2e1673b..096348b 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/application/application_operation_repository.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/application/application_operation_repository.dart @@ -1,16 +1,27 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; /// Repository contract for exactly-once operation records. abstract interface class ApplicationOperationRepository { + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future findById(String operationId); + /// Runs the `findByIdempotencyKey` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future findByIdempotencyKey({ required String ownerId, required String operationId, }); + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future save(ApplicationOperationRecord operation); + /// Runs the `insertIfAbsent` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future insertIfAbsent( ApplicationOperationRecord operation, ); diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/application/notice_acknowledgement_repository.dart b/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/application/notice_acknowledgement_repository.dart index a798e93..5785bc6 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/application/notice_acknowledgement_repository.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/application/notice_acknowledgement_repository.dart @@ -1,21 +1,34 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; /// Repository contract for consumed one-time notices. abstract interface class NoticeAcknowledgementRepository { + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future findById({ required String ownerId, required String noticeId, }); + /// Runs the `findByOwnerId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> findByOwnerId(String ownerId); + /// Runs the `findByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> findByOwner({ required String ownerId, RepositoryPageRequest page = const RepositoryPageRequest(), }); + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future save(NoticeAcknowledgementRecord record); + /// Runs the `insert` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future insert( NoticeAcknowledgementRecord record, ); diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/application/owner_settings_repository.dart b/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/application/owner_settings_repository.dart index 4d4afcc..770066d 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/application/owner_settings_repository.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/application/owner_settings_repository.dart @@ -1,13 +1,24 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; /// Repository contract for owner settings. abstract interface class OwnerSettingsRepository { + /// Runs the `findByOwnerId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future findByOwnerId(String ownerId); + /// Runs the `findRecordByOwnerId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future?> findRecordByOwnerId(String ownerId); + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future save(OwnerSettings settings); + /// Runs the `saveIfRevision` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future saveIfRevision({ required OwnerSettings settings, required int expectedRevision, diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/projects/project_statistics_repository.dart b/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/projects/project_statistics_repository.dart index 5b2fb00..3d1719e 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/projects/project_statistics_repository.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/projects/project_statistics_repository.dart @@ -1,17 +1,30 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; /// Repository contract for project statistics aggregates. abstract interface class ProjectStatisticsRepository { + /// Runs the `findByProjectId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future findByProjectId(String projectId); + /// Runs the `findRecordByProjectId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future?> findRecordByProjectId( String projectId, ); + /// Runs the `findAll` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> findAll(); + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future save(ProjectStatistics statistics); + /// Runs the `saveIfRevision` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future saveIfRevision({ required ProjectStatistics statistics, required String ownerId, diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/tasks/task_activity_repository.dart b/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/tasks/task_activity_repository.dart index c258d3d..2e3ffe0 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/tasks/task_activity_repository.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/tasks/task_activity_repository.dart @@ -1,26 +1,47 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; /// Repository contract for internal task activities. abstract interface class TaskActivityRepository { + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future findById(String id); + /// Runs the `findByOperationId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> findByOperationId(String operationId); + /// Runs the `findByTaskId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> findByTaskId(String taskId); + /// Runs the `findByProjectId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> findByProjectId(String projectId); + /// Runs the `findAll` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> findAll(); + /// Runs the `findByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> findByOwner({ required String ownerId, RepositoryPageRequest page = const RepositoryPageRequest(), }); + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future save(TaskActivity activity); + /// Runs the `saveAll` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future saveAll(Iterable activities); + /// Runs the `append` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future append({ required TaskActivity activity, required String ownerId, diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/unit_of_work/application_unit_of_work.dart b/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/unit_of_work/application_unit_of_work.dart index bef584d..206fefe 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/unit_of_work/application_unit_of_work.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/unit_of_work/application_unit_of_work.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; /// Atomic application transaction boundary. abstract interface class ApplicationUnitOfWork { + /// Runs the `run` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> run({ required ApplicationOperationContext context, required String operationName, @@ -10,6 +15,8 @@ abstract interface class ApplicationUnitOfWork { ) action, }); + /// Runs the `read` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> read({ required Future> Function( ApplicationUnitOfWorkRepositories repositories, diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/unit_of_work/application_unit_of_work_repositories.dart b/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/unit_of_work/application_unit_of_work_repositories.dart index 86e94ed..a8dbbfc 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/unit_of_work/application_unit_of_work_repositories.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/interfaces/unit_of_work/application_unit_of_work_repositories.dart @@ -1,22 +1,43 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; /// Repository set available inside one application unit of work. abstract interface class ApplicationUnitOfWorkRepositories { + /// Returns the derived `tasks` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TaskRepository get tasks; + /// Returns the derived `projects` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. ProjectRepository get projects; + /// Returns the derived `lockedBlocks` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. LockedBlockRepository get lockedBlocks; + /// Returns the derived `schedulingSnapshots` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. SchedulingSnapshotRepository get schedulingSnapshots; + /// Returns the derived `taskActivities` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TaskActivityRepository get taskActivities; + /// Returns the derived `projectStatistics` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. ProjectStatisticsRepository get projectStatistics; + /// Returns the derived `ownerSettings` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. OwnerSettingsRepository get ownerSettings; + /// Returns the derived `noticeAcknowledgements` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. NoticeAcknowledgementRepository get noticeAcknowledgements; + /// Returns the derived `operations` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. ApplicationOperationRepository get operations; } diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/application/unit_of_work_notice_acknowledgement_repository.dart b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/application/unit_of_work_notice_acknowledgement_repository.dart index 8fca707..d40eb21 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/application/unit_of_work_notice_acknowledgement_repository.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/application/unit_of_work_notice_acknowledgement_repository.dart @@ -1,16 +1,30 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; +/// Private implementation type for `_UnitOfWorkNoticeAcknowledgementRepository` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _UnitOfWorkNoticeAcknowledgementRepository implements NoticeAcknowledgementRepository { + /// Creates a `_UnitOfWorkNoticeAcknowledgementRepository` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _UnitOfWorkNoticeAcknowledgementRepository({ required Map recordsByScopedId, required Map revisionsByScopedId, }) : _recordsByScopedId = recordsByScopedId, _revisionsByScopedId = revisionsByScopedId; + /// Private state stored as `_recordsByScopedId` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _recordsByScopedId; + + /// Private state stored as `_revisionsByScopedId` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _revisionsByScopedId; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findById({ required String ownerId, @@ -20,6 +34,8 @@ class _UnitOfWorkNoticeAcknowledgementRepository _noticeAcknowledgementKey(ownerId: ownerId, noticeId: noticeId)]; } + /// Runs the `findByOwnerId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByOwnerId( String ownerId, @@ -29,6 +45,8 @@ class _UnitOfWorkNoticeAcknowledgementRepository ); } + /// Runs the `findByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByOwner({ required String ownerId, @@ -41,6 +59,8 @@ class _UnitOfWorkNoticeAcknowledgementRepository return _page(records, page); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future save(NoticeAcknowledgementRecord record) async { final key = _noticeAcknowledgementKey( @@ -51,6 +71,8 @@ class _UnitOfWorkNoticeAcknowledgementRepository _revisionsByScopedId[key] = (_revisionsByScopedId[key] ?? 1) + 1; } + /// Runs the `insert` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future insert( NoticeAcknowledgementRecord record, diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/application/unit_of_work_operation_repository.dart b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/application/unit_of_work_operation_repository.dart index 04c1d6e..a49d974 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/application/unit_of_work_operation_repository.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/application/unit_of_work_operation_repository.dart @@ -1,15 +1,28 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; +/// Private implementation type for `_UnitOfWorkOperationRepository` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _UnitOfWorkOperationRepository implements ApplicationOperationRepository { + /// Creates a `_UnitOfWorkOperationRepository` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _UnitOfWorkOperationRepository(this._operationsById); + /// Private state stored as `_operationsById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _operationsById; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findById(String operationId) async { return _operationsById[operationId]; } + /// Runs the `findByIdempotencyKey` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findByIdempotencyKey({ required String ownerId, @@ -22,11 +35,15 @@ class _UnitOfWorkOperationRepository implements ApplicationOperationRepository { return operation; } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future save(ApplicationOperationRecord operation) async { _operationsById[operation.operationId] = operation; } + /// Runs the `insertIfAbsent` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future insertIfAbsent( ApplicationOperationRecord operation, @@ -44,6 +61,8 @@ class _UnitOfWorkOperationRepository implements ApplicationOperationRepository { } } +/// Top-level helper that performs the `_noticeAcknowledgementKey` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _noticeAcknowledgementKey({ required String ownerId, required String noticeId, @@ -51,6 +70,8 @@ String _noticeAcknowledgementKey({ return '$ownerId::$noticeId'; } +/// Top-level helper that performs the `_page` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. RepositoryPage _page(List sortedItems, RepositoryPageRequest request) { final offset = int.tryParse(request.cursor ?? '') ?? 0; final safeOffset = offset.clamp(0, sortedItems.length); @@ -63,6 +84,8 @@ RepositoryPage _page(List sortedItems, RepositoryPageRequest request) { ); } +/// Top-level helper that performs the `_taskOverlapsWindow` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _taskOverlapsWindow(Task task, SchedulingWindow window) { final start = task.scheduledStart; final end = task.scheduledEnd; @@ -72,8 +95,12 @@ bool _taskOverlapsWindow(Task task, SchedulingWindow window) { return TimeInterval(start: start, end: end).overlaps(window.interval); } +/// Top-level helper that performs the `_compareTaskIds` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareTaskIds(Task left, Task right) => left.id.compareTo(right.id); +/// Top-level helper that performs the `_compareScheduledTasks` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareScheduledTasks(Task left, Task right) { final leftStart = left.scheduledStart; final rightStart = right.scheduledStart; @@ -86,6 +113,8 @@ int _compareScheduledTasks(Task left, Task right) { return left.id.compareTo(right.id); } +/// Top-level helper that performs the `_compareBacklogCandidates` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareBacklogCandidates(Task left, Task right) { final createdComparison = left.createdAt.compareTo(right.createdAt); if (createdComparison != 0) { @@ -94,6 +123,8 @@ int _compareBacklogCandidates(Task left, Task right) { return left.id.compareTo(right.id); } +/// Top-level helper that performs the `_compareProjects` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareProjects(ProjectProfile left, ProjectProfile right) { final nameComparison = left.name.compareTo(right.name); if (nameComparison != 0) { @@ -102,6 +133,8 @@ int _compareProjects(ProjectProfile left, ProjectProfile right) { return left.id.compareTo(right.id); } +/// Top-level helper that performs the `_compareLockedBlocks` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareLockedBlocks(LockedBlock left, LockedBlock right) { final nameComparison = left.name.compareTo(right.name); if (nameComparison != 0) { @@ -110,6 +143,8 @@ int _compareLockedBlocks(LockedBlock left, LockedBlock right) { return left.id.compareTo(right.id); } +/// Top-level helper that performs the `_compareLockedOverrides` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareLockedOverrides( LockedBlockOverride left, LockedBlockOverride right, @@ -125,6 +160,8 @@ int _compareLockedOverrides( return left.id.compareTo(right.id); } +/// Top-level helper that performs the `_compareActivities` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareActivities(TaskActivity left, TaskActivity right) { final occurredComparison = left.occurredAt.compareTo(right.occurredAt); if (occurredComparison != 0) { @@ -133,6 +170,8 @@ int _compareActivities(TaskActivity left, TaskActivity right) { return left.id.compareTo(right.id); } +/// Top-level helper that performs the `_compareNoticeAcknowledgements` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareNoticeAcknowledgements( NoticeAcknowledgementRecord left, NoticeAcknowledgementRecord right, @@ -145,6 +184,8 @@ int _compareNoticeAcknowledgements( return left.noticeId.compareTo(right.noticeId); } +/// Top-level helper that performs the `_requiredTrimmed` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredTrimmed(String value, String name) { final trimmed = value.trim(); if (trimmed.isEmpty) { diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/application/unit_of_work_owner_settings_repository.dart b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/application/unit_of_work_owner_settings_repository.dart index 27c0dd3..cba7866 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/application/unit_of_work_owner_settings_repository.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/application/unit_of_work_owner_settings_repository.dart @@ -1,20 +1,36 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; +/// Private implementation type for `_UnitOfWorkOwnerSettingsRepository` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _UnitOfWorkOwnerSettingsRepository implements OwnerSettingsRepository { + /// Creates a `_UnitOfWorkOwnerSettingsRepository` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _UnitOfWorkOwnerSettingsRepository({ required Map settingsByOwnerId, required Map revisionsByOwnerId, }) : _settingsByOwnerId = settingsByOwnerId, _revisionsByOwnerId = revisionsByOwnerId; + /// Private state stored as `_settingsByOwnerId` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _settingsByOwnerId; + + /// Private state stored as `_revisionsByOwnerId` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _revisionsByOwnerId; + /// Runs the `findByOwnerId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findByOwnerId(String ownerId) async { return _settingsByOwnerId[ownerId]; } + /// Runs the `findRecordByOwnerId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future?> findRecordByOwnerId( String ownerId, @@ -30,6 +46,8 @@ class _UnitOfWorkOwnerSettingsRepository implements OwnerSettingsRepository { ); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future save(OwnerSettings settings) async { _settingsByOwnerId[settings.ownerId] = settings; @@ -37,6 +55,8 @@ class _UnitOfWorkOwnerSettingsRepository implements OwnerSettingsRepository { (_revisionsByOwnerId[settings.ownerId] ?? 1) + 1; } + /// Runs the `saveIfRevision` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveIfRevision({ required OwnerSettings settings, diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/projects/unit_of_work_project_repository.dart b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/projects/unit_of_work_project_repository.dart index e379ff0..c3b4908 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/projects/unit_of_work_project_repository.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/projects/unit_of_work_project_repository.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; +/// Private implementation type for `_UnitOfWorkProjectRepository` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _UnitOfWorkProjectRepository implements ProjectRepository { + /// Creates a `_UnitOfWorkProjectRepository` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _UnitOfWorkProjectRepository({ required Map projectsById, required Map ownersById, @@ -9,13 +16,25 @@ class _UnitOfWorkProjectRepository implements ProjectRepository { _ownersById = ownersById, _revisionsById = revisionsById; + /// Private state stored as `_projectsById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _projectsById; + + /// Private state stored as `_ownersById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _ownersById; + + /// Private state stored as `_revisionsById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _revisionsById; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findById(String id) async => _projectsById[id]; + /// Runs the `findRecordById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future?> findRecordById(String id) async { final project = _projectsById[id]; @@ -30,11 +49,15 @@ class _UnitOfWorkProjectRepository implements ProjectRepository { ); } + /// Runs the `findAll` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findAll() async { return List.unmodifiable(_projectsById.values); } + /// Runs the `findByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByOwner({ required String ownerId, @@ -52,6 +75,8 @@ class _UnitOfWorkProjectRepository implements ProjectRepository { return _page(projects, page); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future save(ProjectProfile project) async { _projectsById[project.id] = project; @@ -59,6 +84,8 @@ class _UnitOfWorkProjectRepository implements ProjectRepository { _revisionsById[project.id] = _revisionFor(project.id) + 1; } + /// Runs the `insert` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future insert({ required ProjectProfile project, @@ -78,6 +105,8 @@ class _UnitOfWorkProjectRepository implements ProjectRepository { return RepositoryMutationResult.success(revision: 1); } + /// Runs the `saveIfRevision` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveIfRevision({ required ProjectProfile project, @@ -111,6 +140,8 @@ class _UnitOfWorkProjectRepository implements ProjectRepository { return RepositoryMutationResult.success(revision: nextRevision); } + /// Runs the `archive` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future archive({ required String projectId, @@ -134,7 +165,11 @@ class _UnitOfWorkProjectRepository implements ProjectRepository { ); } + /// Runs the `_ownerFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. String _ownerFor(String id) => _ownersById[id] ?? 'owner-1'; + /// Runs the `_revisionFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. int _revisionFor(String id) => _revisionsById[id] ?? 1; } diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/projects/unit_of_work_project_statistics_repository.dart b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/projects/unit_of_work_project_statistics_repository.dart index 73a2a68..5bd8e63 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/projects/unit_of_work_project_statistics_repository.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/projects/unit_of_work_project_statistics_repository.dart @@ -1,7 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; +/// Private implementation type for `_UnitOfWorkProjectStatisticsRepository` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _UnitOfWorkProjectStatisticsRepository implements ProjectStatisticsRepository { + /// Creates a `_UnitOfWorkProjectStatisticsRepository` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _UnitOfWorkProjectStatisticsRepository({ required Map statisticsByProjectId, required Map ownersByProjectId, @@ -10,15 +17,27 @@ class _UnitOfWorkProjectStatisticsRepository _ownersByProjectId = ownersByProjectId, _revisionsByProjectId = revisionsByProjectId; + /// Private state stored as `_statisticsByProjectId` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _statisticsByProjectId; + + /// Private state stored as `_ownersByProjectId` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _ownersByProjectId; + + /// Private state stored as `_revisionsByProjectId` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _revisionsByProjectId; + /// Runs the `findByProjectId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findByProjectId(String projectId) async { return _statisticsByProjectId[projectId]; } + /// Runs the `findRecordByProjectId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future?> findRecordByProjectId( String projectId, @@ -34,11 +53,15 @@ class _UnitOfWorkProjectStatisticsRepository ); } + /// Runs the `findAll` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findAll() async { return List.unmodifiable(_statisticsByProjectId.values); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future save(ProjectStatistics statistics) async { _statisticsByProjectId[statistics.projectId] = statistics; @@ -47,6 +70,8 @@ class _UnitOfWorkProjectStatisticsRepository (_revisionsByProjectId[statistics.projectId] ?? 1) + 1; } + /// Runs the `saveIfRevision` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveIfRevision({ required ProjectStatistics statistics, diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/scheduling/unit_of_work_locked_block_repository.dart b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/scheduling/unit_of_work_locked_block_repository.dart index 1a5909a..31dc001 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/scheduling/unit_of_work_locked_block_repository.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/scheduling/unit_of_work_locked_block_repository.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; +/// Private implementation type for `_UnitOfWorkLockedBlockRepository` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _UnitOfWorkLockedBlockRepository implements LockedBlockRepository { + /// Creates a `_UnitOfWorkLockedBlockRepository` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _UnitOfWorkLockedBlockRepository({ required Map blocksById, required Map blockOwnersById, @@ -15,16 +22,37 @@ class _UnitOfWorkLockedBlockRepository implements LockedBlockRepository { _overrideOwnersById = overrideOwnersById, _overrideRevisionsById = overrideRevisionsById; + /// Private state stored as `_blocksById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _blocksById; + + /// Private state stored as `_blockOwnersById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _blockOwnersById; + + /// Private state stored as `_blockRevisionsById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _blockRevisionsById; + + /// Private state stored as `_overridesById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _overridesById; + + /// Private state stored as `_overrideOwnersById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _overrideOwnersById; + + /// Private state stored as `_overrideRevisionsById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _overrideRevisionsById; + /// Runs the `findBlockById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findBlockById(String id) async => _blocksById[id]; + /// Runs the `findBlockRecordById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future?> findBlockRecordById(String id) async { final block = _blocksById[id]; @@ -39,11 +67,15 @@ class _UnitOfWorkLockedBlockRepository implements LockedBlockRepository { ); } + /// Runs the `findAllBlocks` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findAllBlocks() async { return List.unmodifiable(_blocksById.values); } + /// Runs the `findBlocksByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findBlocksByOwner({ required String ownerId, @@ -61,11 +93,15 @@ class _UnitOfWorkLockedBlockRepository implements LockedBlockRepository { return _page(blocks, page); } + /// Runs the `findOverrideById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findOverrideById(String id) async { return _overridesById[id]; } + /// Runs the `findOverrideRecordById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future?> findOverrideRecordById( String id, @@ -81,11 +117,15 @@ class _UnitOfWorkLockedBlockRepository implements LockedBlockRepository { ); } + /// Runs the `findAllOverrides` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findAllOverrides() async { return List.unmodifiable(_overridesById.values); } + /// Runs the `findOverridesForDate` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findOverridesForDate({ required String ownerId, @@ -103,6 +143,8 @@ class _UnitOfWorkLockedBlockRepository implements LockedBlockRepository { return _page(overrides, page); } + /// Runs the `saveBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveBlock(LockedBlock block) async { _blocksById[block.id] = block; @@ -110,6 +152,8 @@ class _UnitOfWorkLockedBlockRepository implements LockedBlockRepository { _blockRevisionsById[block.id] = _blockRevisionFor(block.id) + 1; } + /// Runs the `saveOverride` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveOverride(LockedBlockOverride override) async { _overridesById[override.id] = override; @@ -117,6 +161,8 @@ class _UnitOfWorkLockedBlockRepository implements LockedBlockRepository { _overrideRevisionsById[override.id] = _overrideRevisionFor(override.id) + 1; } + /// Runs the `insertBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future insertBlock({ required LockedBlock block, @@ -136,6 +182,8 @@ class _UnitOfWorkLockedBlockRepository implements LockedBlockRepository { return RepositoryMutationResult.success(revision: 1); } + /// Runs the `saveBlockIfRevision` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveBlockIfRevision({ required LockedBlock block, @@ -169,6 +217,8 @@ class _UnitOfWorkLockedBlockRepository implements LockedBlockRepository { return RepositoryMutationResult.success(revision: nextRevision); } + /// Runs the `archiveBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future archiveBlock({ required String blockId, @@ -192,6 +242,8 @@ class _UnitOfWorkLockedBlockRepository implements LockedBlockRepository { ); } + /// Runs the `insertOverride` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future insertOverride({ required LockedBlockOverride override, @@ -211,6 +263,8 @@ class _UnitOfWorkLockedBlockRepository implements LockedBlockRepository { return RepositoryMutationResult.success(revision: 1); } + /// Runs the `saveOverrideIfRevision` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveOverrideIfRevision({ required LockedBlockOverride override, @@ -244,11 +298,19 @@ class _UnitOfWorkLockedBlockRepository implements LockedBlockRepository { return RepositoryMutationResult.success(revision: nextRevision); } + /// Runs the `_blockOwnerFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. String _blockOwnerFor(String id) => _blockOwnersById[id] ?? 'owner-1'; + /// Runs the `_blockRevisionFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. int _blockRevisionFor(String id) => _blockRevisionsById[id] ?? 1; + /// Runs the `_overrideOwnerFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. String _overrideOwnerFor(String id) => _overrideOwnersById[id] ?? 'owner-1'; + /// Runs the `_overrideRevisionFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. int _overrideRevisionFor(String id) => _overrideRevisionsById[id] ?? 1; } diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/scheduling/unit_of_work_scheduling_snapshot_repository.dart b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/scheduling/unit_of_work_scheduling_snapshot_repository.dart index e7d9214..b7f2fa0 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/scheduling/unit_of_work_scheduling_snapshot_repository.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/scheduling/unit_of_work_scheduling_snapshot_repository.dart @@ -1,16 +1,29 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; +/// Private implementation type for `_UnitOfWorkSchedulingSnapshotRepository` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _UnitOfWorkSchedulingSnapshotRepository implements SchedulingSnapshotRepository { + /// Creates a `_UnitOfWorkSchedulingSnapshotRepository` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _UnitOfWorkSchedulingSnapshotRepository(this._snapshotsById); + /// Private state stored as `_snapshotsById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _snapshotsById; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findById(String id) async { return _snapshotsById[id]; } + /// Runs the `findInWindow` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findInWindow( SchedulingWindow window, @@ -22,6 +35,8 @@ class _UnitOfWorkSchedulingSnapshotRepository ); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future save(SchedulingStateSnapshot snapshot) async { _snapshotsById[snapshot.id] = snapshot; diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/tasks/unit_of_work_task_activity_repository.dart b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/tasks/unit_of_work_task_activity_repository.dart index 7e59e59..510c361 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/tasks/unit_of_work_task_activity_repository.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/tasks/unit_of_work_task_activity_repository.dart @@ -1,18 +1,34 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; +/// Private implementation type for `_UnitOfWorkTaskActivityRepository` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _UnitOfWorkTaskActivityRepository implements TaskActivityRepository { + /// Creates a `_UnitOfWorkTaskActivityRepository` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _UnitOfWorkTaskActivityRepository({ required Map activitiesById, required Map ownersById, }) : _activitiesById = activitiesById, _ownersById = ownersById; + /// Private state stored as `_activitiesById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _activitiesById; + + /// Private state stored as `_ownersById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _ownersById; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findById(String id) async => _activitiesById[id]; + /// Runs the `findByOperationId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByOperationId(String operationId) async { return List.unmodifiable( @@ -22,6 +38,8 @@ class _UnitOfWorkTaskActivityRepository implements TaskActivityRepository { ); } + /// Runs the `findByTaskId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByTaskId(String taskId) async { return List.unmodifiable( @@ -29,6 +47,8 @@ class _UnitOfWorkTaskActivityRepository implements TaskActivityRepository { ); } + /// Runs the `findByProjectId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByProjectId(String projectId) async { return List.unmodifiable( @@ -38,11 +58,15 @@ class _UnitOfWorkTaskActivityRepository implements TaskActivityRepository { ); } + /// Runs the `findAll` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findAll() async { return List.unmodifiable(_activitiesById.values); } + /// Runs the `findByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByOwner({ required String ownerId, @@ -55,12 +79,16 @@ class _UnitOfWorkTaskActivityRepository implements TaskActivityRepository { return _page(activities, page); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future save(TaskActivity activity) async { _activitiesById[activity.id] = activity; _ownersById.putIfAbsent(activity.id, () => 'owner-1'); } + /// Runs the `saveAll` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveAll(Iterable activities) async { for (final activity in activities) { @@ -69,6 +97,8 @@ class _UnitOfWorkTaskActivityRepository implements TaskActivityRepository { } } + /// Runs the `append` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future append({ required TaskActivity activity, @@ -87,5 +117,7 @@ class _UnitOfWorkTaskActivityRepository implements TaskActivityRepository { return RepositoryMutationResult.success(revision: 1); } + /// Runs the `_ownerFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. String _ownerFor(String id) => _ownersById[id] ?? 'owner-1'; } diff --git a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/tasks/unit_of_work_task_repository.dart b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/tasks/unit_of_work_task_repository.dart index dafe8d3..181abe5 100644 --- a/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/tasks/unit_of_work_task_repository.dart +++ b/packages/scheduler_core/lib/src/application_layer/repositories/unit_of_work/tasks/unit_of_work_task_repository.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../../application_layer.dart'; +/// Private implementation type for `_UnitOfWorkTaskRepository` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _UnitOfWorkTaskRepository implements TaskRepository { + /// Creates a `_UnitOfWorkTaskRepository` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _UnitOfWorkTaskRepository({ required Map tasksById, required Map ownersById, @@ -9,13 +16,25 @@ class _UnitOfWorkTaskRepository implements TaskRepository { _ownersById = ownersById, _revisionsById = revisionsById; + /// Private state stored as `_tasksById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _tasksById; + + /// Private state stored as `_ownersById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _ownersById; + + /// Private state stored as `_revisionsById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _revisionsById; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findById(String id) async => _tasksById[id]; + /// Runs the `findRecordById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future?> findRecordById(String id) async { final task = _tasksById[id]; @@ -29,11 +48,15 @@ class _UnitOfWorkTaskRepository implements TaskRepository { ); } + /// Runs the `findAll` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findAll() async { return List.unmodifiable(_tasksById.values); } + /// Runs the `findByStatus` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByStatus(TaskStatus status) async { return List.unmodifiable( @@ -41,6 +64,8 @@ class _UnitOfWorkTaskRepository implements TaskRepository { ); } + /// Runs the `findByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByOwner({ required String ownerId, @@ -53,6 +78,8 @@ class _UnitOfWorkTaskRepository implements TaskRepository { return _page(tasks, page); } + /// Runs the `findByProjectId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByProjectId({ required String ownerId, @@ -69,6 +96,8 @@ class _UnitOfWorkTaskRepository implements TaskRepository { return _page(tasks, page); } + /// Runs the `findByParentTaskId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByParentTaskId({ required String ownerId, @@ -86,6 +115,8 @@ class _UnitOfWorkTaskRepository implements TaskRepository { return _page(tasks, page); } + /// Runs the `findBacklogCandidates` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findBacklogCandidates( BacklogCandidateQuery query, @@ -103,6 +134,8 @@ class _UnitOfWorkTaskRepository implements TaskRepository { return _page(tasks, query.page); } + /// Runs the `findScheduledInWindow` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findScheduledInWindow(SchedulingWindow window) async { return List.unmodifiable( @@ -112,6 +145,8 @@ class _UnitOfWorkTaskRepository implements TaskRepository { ); } + /// Runs the `findScheduledInWindowForOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findScheduledInWindowForOwner({ required String ownerId, @@ -129,6 +164,8 @@ class _UnitOfWorkTaskRepository implements TaskRepository { return _page(tasks, page); } + /// Runs the `findForLocalDay` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findForLocalDay({ required String ownerId, @@ -143,6 +180,8 @@ class _UnitOfWorkTaskRepository implements TaskRepository { ); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future save(Task task) async { _tasksById[task.id] = task; @@ -150,6 +189,8 @@ class _UnitOfWorkTaskRepository implements TaskRepository { _revisionsById[task.id] = _revisionFor(task.id) + 1; } + /// Runs the `saveAll` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveAll(Iterable tasks) async { for (final task in tasks) { @@ -157,6 +198,8 @@ class _UnitOfWorkTaskRepository implements TaskRepository { } } + /// Runs the `insert` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future insert({ required Task task, @@ -176,6 +219,8 @@ class _UnitOfWorkTaskRepository implements TaskRepository { return RepositoryMutationResult.success(revision: 1); } + /// Runs the `saveIfRevision` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveIfRevision({ required Task task, @@ -206,7 +251,11 @@ class _UnitOfWorkTaskRepository implements TaskRepository { return RepositoryMutationResult.success(revision: nextRevision); } + /// Runs the `_ownerFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. String _ownerFor(String id) => _ownersById[id] ?? 'owner-1'; + /// Runs the `_revisionFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. int _revisionFor(String id) => _revisionsById[id] ?? 1; } diff --git a/packages/scheduler_core/lib/src/application_layer/results/application_failure.dart b/packages/scheduler_core/lib/src/application_layer/results/application_failure.dart index bd7c3c8..5d09c67 100644 --- a/packages/scheduler_core/lib/src/application_layer/results/application_failure.dart +++ b/packages/scheduler_core/lib/src/application_layer/results/application_failure.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_layer.dart'; /// Typed failure returned by application commands and queries. class ApplicationFailure { + /// Creates a `ApplicationFailure` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ApplicationFailure({ required this.code, this.entityId, diff --git a/packages/scheduler_core/lib/src/application_layer/results/application_failure_code.dart b/packages/scheduler_core/lib/src/application_layer/results/application_failure_code.dart index 777f90e..e427cca 100644 --- a/packages/scheduler_core/lib/src/application_layer/results/application_failure_code.dart +++ b/packages/scheduler_core/lib/src/application_layer/results/application_failure_code.dart @@ -1,13 +1,39 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_layer.dart'; /// Stable application-layer result categories. enum ApplicationFailureCode { + /// Selects the `validation` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. validation, + + /// Selects the `notFound` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. notFound, + + /// Selects the `conflict` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. conflict, + + /// Selects the `staleRevision` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. staleRevision, + + /// Selects the `noSlot` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. noSlot, + + /// Selects the `duplicateOperation` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. duplicateOperation, + + /// Selects the `persistenceFailure` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. persistenceFailure, + + /// Selects the `unexpected` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. unexpected, } diff --git a/packages/scheduler_core/lib/src/application_layer/results/application_failure_exception.dart b/packages/scheduler_core/lib/src/application_layer/results/application_failure_exception.dart index d90b35d..2f30565 100644 --- a/packages/scheduler_core/lib/src/application_layer/results/application_failure_exception.dart +++ b/packages/scheduler_core/lib/src/application_layer/results/application_failure_exception.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_layer.dart'; /// Exception for expected failures raised inside a unit-of-work callback. class ApplicationFailureException implements Exception { + /// Creates a `ApplicationFailureException` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ApplicationFailureException(this.failure); /// Failure to return from the application boundary. diff --git a/packages/scheduler_core/lib/src/application_layer/results/application_persistence_exception.dart b/packages/scheduler_core/lib/src/application_layer/results/application_persistence_exception.dart index 4d3d702..a033e8d 100644 --- a/packages/scheduler_core/lib/src/application_layer/results/application_persistence_exception.dart +++ b/packages/scheduler_core/lib/src/application_layer/results/application_persistence_exception.dart @@ -1,6 +1,11 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_layer.dart'; /// Exception representing persistence/driver failures at repository boundaries. class ApplicationPersistenceException implements Exception { + /// Creates a `ApplicationPersistenceException` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ApplicationPersistenceException(); } diff --git a/packages/scheduler_core/lib/src/application_layer/results/application_result.dart b/packages/scheduler_core/lib/src/application_layer/results/application_result.dart index c478c5e..a433378 100644 --- a/packages/scheduler_core/lib/src/application_layer/results/application_result.dart +++ b/packages/scheduler_core/lib/src/application_layer/results/application_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_layer.dart'; /// Result wrapper for expected application success/failure paths. class ApplicationResult { + /// Creates a `ApplicationResult._` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ApplicationResult._({ this.value, this.failure, diff --git a/packages/scheduler_core/lib/src/application_management.dart b/packages/scheduler_core/lib/src/application_management.dart index 061e8f9..c2ba8e9 100644 --- a/packages/scheduler_core/lib/src/application_management.dart +++ b/packages/scheduler_core/lib/src/application_management.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Application Management behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/application_management/codes/application_management_command_code.dart b/packages/scheduler_core/lib/src/application_management/codes/application_management_command_code.dart index 06d4fda..7aaea08 100644 --- a/packages/scheduler_core/lib/src/application_management/codes/application_management_command_code.dart +++ b/packages/scheduler_core/lib/src/application_management/codes/application_management_command_code.dart @@ -1,16 +1,51 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// Stable management command identifiers. enum ApplicationManagementCommandCode { + /// Selects the `createProject` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. createProject, + + /// Selects the `updateProject` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. updateProject, + + /// Selects the `archiveProject` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. archiveProject, + + /// Selects the `createLockedBlock` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. createLockedBlock, + + /// Selects the `updateLockedBlock` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. updateLockedBlock, + + /// Selects the `archiveLockedBlock` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. archiveLockedBlock, + + /// Selects the `addLockedBlockOverride` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. addLockedBlockOverride, + + /// Selects the `removeLockedBlockOccurrence` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. removeLockedBlockOccurrence, + + /// Selects the `replaceLockedBlockOccurrence` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. replaceLockedBlockOccurrence, + + /// Selects the `updateOwnerSettings` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. updateOwnerSettings, + + /// Selects the `acknowledgeNotice` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. acknowledgeNotice, } diff --git a/packages/scheduler_core/lib/src/application_management/codes/owner_settings_warning_code.dart b/packages/scheduler_core/lib/src/application_management/codes/owner_settings_warning_code.dart index a01e1fc..5483a3a 100644 --- a/packages/scheduler_core/lib/src/application_management/codes/owner_settings_warning_code.dart +++ b/packages/scheduler_core/lib/src/application_management/codes/owner_settings_warning_code.dart @@ -1,7 +1,15 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// Typed warning codes for settings changes that reinterpret local dates/times. enum OwnerSettingsWarningCode { + /// Selects the `timeZoneChanged` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. timeZoneChanged, + + /// Selects the `planningWindowChanged` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. planningWindowChanged, } diff --git a/packages/scheduler_core/lib/src/application_management/drafts/locked_block_draft.dart b/packages/scheduler_core/lib/src/application_management/drafts/locked_block_draft.dart index ab018f8..6771e3d 100644 --- a/packages/scheduler_core/lib/src/application_management/drafts/locked_block_draft.dart +++ b/packages/scheduler_core/lib/src/application_management/drafts/locked_block_draft.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// Draft used when creating a locked block. class LockedBlockDraft { + /// Creates a `LockedBlockDraft` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const LockedBlockDraft({ this.id, required this.name, @@ -13,12 +18,35 @@ class LockedBlockDraft { this.projectId, }); + /// Stores the `id` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? id; + + /// Stores the `name` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String name; + + /// Stores the `startTime` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ClockTime startTime; + + /// Stores the `endTime` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ClockTime endTime; + + /// Stores the `date` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final CivilDate? date; + + /// Stores the `recurrence` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final LockedBlockRecurrence? recurrence; + + /// Stores the `hiddenByDefault` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool hiddenByDefault; + + /// Stores the `projectId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? projectId; } diff --git a/packages/scheduler_core/lib/src/application_management/drafts/project_profile_draft.dart b/packages/scheduler_core/lib/src/application_management/drafts/project_profile_draft.dart index af0470a..da7b1a4 100644 --- a/packages/scheduler_core/lib/src/application_management/drafts/project_profile_draft.dart +++ b/packages/scheduler_core/lib/src/application_management/drafts/project_profile_draft.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// Draft used when creating a project. class ProjectProfileDraft { + /// Creates a `ProjectProfileDraft` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ProjectProfileDraft({ this.id, required this.name, @@ -13,12 +18,35 @@ class ProjectProfileDraft { this.defaultDurationMinutes, }); + /// Stores the `id` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? id; + + /// Stores the `name` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String name; + + /// Stores the `colorKey` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String colorKey; + + /// Stores the `defaultPriority` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final PriorityLevel defaultPriority; + + /// Stores the `defaultReward` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final RewardLevel defaultReward; + + /// Stores the `defaultDifficulty` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DifficultyLevel defaultDifficulty; + + /// Stores the `defaultReminderProfile` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ReminderProfile defaultReminderProfile; + + /// Stores the `defaultDurationMinutes` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int? defaultDurationMinutes; } diff --git a/packages/scheduler_core/lib/src/application_management/parsing/parsed_notice_id.dart b/packages/scheduler_core/lib/src/application_management/parsing/parsed_notice_id.dart index 04cd55d..fa1b6ec 100644 --- a/packages/scheduler_core/lib/src/application_management/parsing/parsed_notice_id.dart +++ b/packages/scheduler_core/lib/src/application_management/parsing/parsed_notice_id.dart @@ -1,11 +1,23 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; +/// Private implementation type for `_ParsedNoticeId` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _ParsedNoticeId { + /// Creates a `_ParsedNoticeId` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _ParsedNoticeId({ required this.snapshotId, required this.noticeIndex, }); + /// Stores the `snapshotId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String snapshotId; + + /// Stores the `noticeIndex` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int noticeIndex; } diff --git a/packages/scheduler_core/lib/src/application_management/read_models/backlog_item_read_model.dart b/packages/scheduler_core/lib/src/application_management/read_models/backlog_item_read_model.dart index d0d5048..800f1e6 100644 --- a/packages/scheduler_core/lib/src/application_management/read_models/backlog_item_read_model.dart +++ b/packages/scheduler_core/lib/src/application_management/read_models/backlog_item_read_model.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// One backlog row with its configured staleness marker. class BacklogItemReadModel { + /// Creates a `BacklogItemReadModel` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const BacklogItemReadModel({ required this.task, required this.stalenessMarker, diff --git a/packages/scheduler_core/lib/src/application_management/read_models/backlog_query_result.dart b/packages/scheduler_core/lib/src/application_management/read_models/backlog_query_result.dart index a388ea1..0d12f17 100644 --- a/packages/scheduler_core/lib/src/application_management/read_models/backlog_query_result.dart +++ b/packages/scheduler_core/lib/src/application_management/read_models/backlog_query_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// Query result for the backlog surface. class BacklogQueryResult { + /// Creates a `BacklogQueryResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. BacklogQueryResult({ required this.ownerId, required this.settings, diff --git a/packages/scheduler_core/lib/src/application_management/read_models/project_defaults_query_result.dart b/packages/scheduler_core/lib/src/application_management/read_models/project_defaults_query_result.dart index b5e3cd5..bd16284 100644 --- a/packages/scheduler_core/lib/src/application_management/read_models/project_defaults_query_result.dart +++ b/packages/scheduler_core/lib/src/application_management/read_models/project_defaults_query_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// Project defaults query result. class ProjectDefaultsQueryResult { + /// Creates a `ProjectDefaultsQueryResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. ProjectDefaultsQueryResult({ required this.ownerId, required List projects, diff --git a/packages/scheduler_core/lib/src/application_management/requests/get_backlog_request.dart b/packages/scheduler_core/lib/src/application_management/requests/get_backlog_request.dart index 2d5e280..33e0b40 100644 --- a/packages/scheduler_core/lib/src/application_management/requests/get_backlog_request.dart +++ b/packages/scheduler_core/lib/src/application_management/requests/get_backlog_request.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// Backlog query request. class GetBacklogRequest { + /// Creates a `GetBacklogRequest` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const GetBacklogRequest({ required this.context, this.filter, diff --git a/packages/scheduler_core/lib/src/application_management/requests/get_project_defaults_request.dart b/packages/scheduler_core/lib/src/application_management/requests/get_project_defaults_request.dart index eefd6e0..b355c66 100644 --- a/packages/scheduler_core/lib/src/application_management/requests/get_project_defaults_request.dart +++ b/packages/scheduler_core/lib/src/application_management/requests/get_project_defaults_request.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// Query request for project defaults and learned suggestions. class GetProjectDefaultsRequest { + /// Creates a `GetProjectDefaultsRequest` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const GetProjectDefaultsRequest({ required this.context, this.includeArchived = false, diff --git a/packages/scheduler_core/lib/src/application_management/results/notice_acknowledgement_result.dart b/packages/scheduler_core/lib/src/application_management/results/notice_acknowledgement_result.dart index 671b5e4..fab8293 100644 --- a/packages/scheduler_core/lib/src/application_management/results/notice_acknowledgement_result.dart +++ b/packages/scheduler_core/lib/src/application_management/results/notice_acknowledgement_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// Result for notice acknowledgement commands. class NoticeAcknowledgementResult { + /// Creates a `NoticeAcknowledgementResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const NoticeAcknowledgementResult({ required this.record, required this.alreadyAcknowledged, diff --git a/packages/scheduler_core/lib/src/application_management/results/owner_settings_update_result.dart b/packages/scheduler_core/lib/src/application_management/results/owner_settings_update_result.dart index 99c8bfb..97cce91 100644 --- a/packages/scheduler_core/lib/src/application_management/results/owner_settings_update_result.dart +++ b/packages/scheduler_core/lib/src/application_management/results/owner_settings_update_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// Result for owner settings updates. class OwnerSettingsUpdateResult { + /// Creates a `OwnerSettingsUpdateResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. OwnerSettingsUpdateResult({ required this.settings, Iterable warnings = diff --git a/packages/scheduler_core/lib/src/application_management/updates/locked_block_update.dart b/packages/scheduler_core/lib/src/application_management/updates/locked_block_update.dart index b7204d0..adbb0bf 100644 --- a/packages/scheduler_core/lib/src/application_management/updates/locked_block_update.dart +++ b/packages/scheduler_core/lib/src/application_management/updates/locked_block_update.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// Patch used when updating a locked block definition. class LockedBlockUpdate { + /// Creates a `LockedBlockUpdate` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const LockedBlockUpdate({ this.name, this.startTime, @@ -12,11 +17,31 @@ class LockedBlockUpdate { this.projectId, }); + /// Stores the `name` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? name; + + /// Stores the `startTime` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ClockTime? startTime; + + /// Stores the `endTime` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ClockTime? endTime; + + /// Stores the `date` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final CivilDate? date; + + /// Stores the `recurrence` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final LockedBlockRecurrence? recurrence; + + /// Stores the `hiddenByDefault` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool? hiddenByDefault; + + /// Stores the `projectId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? projectId; } diff --git a/packages/scheduler_core/lib/src/application_management/updates/owner_settings_update.dart b/packages/scheduler_core/lib/src/application_management/updates/owner_settings_update.dart index 4395dd6..e7f3913 100644 --- a/packages/scheduler_core/lib/src/application_management/updates/owner_settings_update.dart +++ b/packages/scheduler_core/lib/src/application_management/updates/owner_settings_update.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// Patch used when updating owner settings. class OwnerSettingsUpdate { + /// Creates a `OwnerSettingsUpdate` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const OwnerSettingsUpdate({ this.timeZoneId, this.dayStart, @@ -10,9 +15,23 @@ class OwnerSettingsUpdate { this.backlogStalenessSettings, }); + /// Stores the `timeZoneId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? timeZoneId; + + /// Stores the `dayStart` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final WallTime? dayStart; + + /// Stores the `dayEnd` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final WallTime? dayEnd; + + /// Stores the `compactModeEnabled` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool? compactModeEnabled; + + /// Stores the `backlogStalenessSettings` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final BacklogStalenessSettings? backlogStalenessSettings; } diff --git a/packages/scheduler_core/lib/src/application_management/updates/project_profile_update.dart b/packages/scheduler_core/lib/src/application_management/updates/project_profile_update.dart index 4dcf4cd..2b07d10 100644 --- a/packages/scheduler_core/lib/src/application_management/updates/project_profile_update.dart +++ b/packages/scheduler_core/lib/src/application_management/updates/project_profile_update.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// Patch used when updating configured project defaults. class ProjectProfileUpdate { + /// Creates a `ProjectProfileUpdate` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ProjectProfileUpdate({ this.name, this.colorKey, @@ -13,12 +18,35 @@ class ProjectProfileUpdate { this.clearDefaultDuration = false, }); + /// Stores the `name` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? name; + + /// Stores the `colorKey` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? colorKey; + + /// Stores the `defaultPriority` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final PriorityLevel? defaultPriority; + + /// Stores the `defaultReward` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final RewardLevel? defaultReward; + + /// Stores the `defaultDifficulty` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DifficultyLevel? defaultDifficulty; + + /// Stores the `defaultReminderProfile` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ReminderProfile? defaultReminderProfile; + + /// Stores the `defaultDurationMinutes` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int? defaultDurationMinutes; + + /// Stores the `clearDefaultDuration` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool clearDefaultDuration; } diff --git a/packages/scheduler_core/lib/src/application_management/use_cases/v1_application_management_use_cases.dart b/packages/scheduler_core/lib/src/application_management/use_cases/v1_application_management_use_cases.dart index 6cfa204..20cbe71 100644 --- a/packages/scheduler_core/lib/src/application_management/use_cases/v1_application_management_use_cases.dart +++ b/packages/scheduler_core/lib/src/application_management/use_cases/v1_application_management_use_cases.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../application_management.dart'; /// V1 management facade used by future Flutter state management. class V1ApplicationManagementUseCases { + /// Creates a `V1ApplicationManagementUseCases` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const V1ApplicationManagementUseCases({ required this.applicationStore, this.projectSuggestionService = const ProjectSuggestionService(), @@ -99,6 +104,8 @@ class V1ApplicationManagementUseCases { ); } + /// Runs the `createProject` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> createProject({ required ApplicationOperationContext context, required ProjectProfileDraft draft, @@ -132,6 +139,8 @@ class V1ApplicationManagementUseCases { ); } + /// Runs the `updateProject` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> updateProject({ required ApplicationOperationContext context, required String projectId, @@ -158,6 +167,8 @@ class V1ApplicationManagementUseCases { ); } + /// Runs the `archiveProject` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> archiveProject({ required ApplicationOperationContext context, required String projectId, @@ -174,6 +185,8 @@ class V1ApplicationManagementUseCases { ); } + /// Runs the `createLockedBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> createLockedBlock({ required ApplicationOperationContext context, required LockedBlockDraft draft, @@ -209,6 +222,8 @@ class V1ApplicationManagementUseCases { ); } + /// Runs the `updateLockedBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> updateLockedBlock({ required ApplicationOperationContext context, required String lockedBlockId, @@ -235,6 +250,8 @@ class V1ApplicationManagementUseCases { ); } + /// Runs the `archiveLockedBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> archiveLockedBlock({ required ApplicationOperationContext context, required String lockedBlockId, @@ -254,6 +271,8 @@ class V1ApplicationManagementUseCases { ); } + /// Runs the `addOneDayLockedOverride` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> addOneDayLockedOverride({ required ApplicationOperationContext context, required CivilDate date, @@ -284,6 +303,8 @@ class V1ApplicationManagementUseCases { ); } + /// Runs the `removeOneDayLockedOccurrence` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> removeOneDayLockedOccurrence({ required ApplicationOperationContext context, required String lockedBlockId, @@ -307,6 +328,8 @@ class V1ApplicationManagementUseCases { ); } + /// Runs the `replaceOneDayLockedOccurrence` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> replaceOneDayLockedOccurrence({ required ApplicationOperationContext context, required String lockedBlockId, @@ -340,6 +363,8 @@ class V1ApplicationManagementUseCases { ); } + /// Runs the `updateOwnerSettings` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> updateOwnerSettings({ required ApplicationOperationContext context, required OwnerSettingsUpdate update, @@ -386,6 +411,8 @@ class V1ApplicationManagementUseCases { ); } + /// Runs the `acknowledgeNotice` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> acknowledgeNotice({ required ApplicationOperationContext context, required String noticeId, @@ -441,6 +468,8 @@ class V1ApplicationManagementUseCases { ); } + /// Runs the `_requireProject` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _requireProject( ApplicationUnitOfWorkRepositories repositories, String projectId, @@ -458,6 +487,8 @@ class V1ApplicationManagementUseCases { return project; } + /// Runs the `_requireLockedBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _requireLockedBlock( ApplicationUnitOfWorkRepositories repositories, String lockedBlockId, @@ -476,6 +507,8 @@ class V1ApplicationManagementUseCases { } } +/// Top-level helper that performs the `_ownerSettingsOrDefault` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _ownerSettingsOrDefault( ApplicationUnitOfWorkRepositories repositories, OwnerTimeZoneContext ownerTimeZone, @@ -488,6 +521,8 @@ Future _ownerSettingsOrDefault( ); } +/// Top-level helper that performs the `_failure` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. ApplicationResult _failure( ApplicationFailureCode code, { String? entityId, @@ -502,6 +537,8 @@ ApplicationResult _failure( ); } +/// Top-level helper that performs the `_parseNoticeId` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. _ParsedNoticeId? _parseNoticeId(String noticeId) { final separator = noticeId.lastIndexOf(':'); if (separator <= 0 || separator == noticeId.length - 1) { diff --git a/packages/scheduler_core/lib/src/application_recovery.dart b/packages/scheduler_core/lib/src/application_recovery.dart index 2e7a53a..2be5dc1 100644 --- a/packages/scheduler_core/lib/src/application_recovery.dart +++ b/packages/scheduler_core/lib/src/application_recovery.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Application Recovery behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/application_recovery/app_open_recovery_outcome.dart b/packages/scheduler_core/lib/src/application_recovery/app_open_recovery_outcome.dart index 23db761..c41b829 100644 --- a/packages/scheduler_core/lib/src/application_recovery/app_open_recovery_outcome.dart +++ b/packages/scheduler_core/lib/src/application_recovery/app_open_recovery_outcome.dart @@ -1,8 +1,19 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../application_recovery.dart'; /// Stable app-open recovery outcomes. enum AppOpenRecoveryOutcome { + /// Selects the `rolledOver` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. rolledOver, + + /// Selects the `noUnfinishedFlexibleTasks` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. noUnfinishedFlexibleTasks, + + /// Selects the `alreadyProcessed` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. alreadyProcessed, } diff --git a/packages/scheduler_core/lib/src/application_recovery/app_open_recovery_result.dart b/packages/scheduler_core/lib/src/application_recovery/app_open_recovery_result.dart index b0c30e4..f7f545d 100644 --- a/packages/scheduler_core/lib/src/application_recovery/app_open_recovery_result.dart +++ b/packages/scheduler_core/lib/src/application_recovery/app_open_recovery_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../application_recovery.dart'; /// Result returned by app-open recovery. class AppOpenRecoveryResult { + /// Creates a `AppOpenRecoveryResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. AppOpenRecoveryResult({ required this.outcome, required this.sourceDate, diff --git a/packages/scheduler_core/lib/src/application_recovery/run_app_open_recovery_request.dart b/packages/scheduler_core/lib/src/application_recovery/run_app_open_recovery_request.dart index b79ad6d..41a8746 100644 --- a/packages/scheduler_core/lib/src/application_recovery/run_app_open_recovery_request.dart +++ b/packages/scheduler_core/lib/src/application_recovery/run_app_open_recovery_request.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../application_recovery.dart'; /// Request for explicit app-open/start-day rollover recovery. class RunAppOpenRecoveryRequest { + /// Creates a `RunAppOpenRecoveryRequest` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const RunAppOpenRecoveryRequest({ required this.context, required this.sourceDate, diff --git a/packages/scheduler_core/lib/src/application_recovery/v1_app_open_recovery_use_cases.dart b/packages/scheduler_core/lib/src/application_recovery/v1_app_open_recovery_use_cases.dart index f214d23..b84239a 100644 --- a/packages/scheduler_core/lib/src/application_recovery/v1_app_open_recovery_use_cases.dart +++ b/packages/scheduler_core/lib/src/application_recovery/v1_app_open_recovery_use_cases.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../application_recovery.dart'; /// Explicit app-open recovery facade. class V1AppOpenRecoveryUseCases { + /// Creates a `V1AppOpenRecoveryUseCases` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const V1AppOpenRecoveryUseCases({ required this.applicationStore, required this.timeZoneResolver, @@ -152,6 +157,8 @@ class V1AppOpenRecoveryUseCases { ); } + /// Runs the `_windowForDate` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. SchedulingWindow _windowForDate(CivilDate date, OwnerSettings settings) { return SchedulingWindow( start: _resolve( @@ -167,6 +174,8 @@ class V1AppOpenRecoveryUseCases { ); } + /// Runs the `_resolve` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. DateTime _resolve({ required CivilDate date, required WallTime wallTime, @@ -183,6 +192,8 @@ class V1AppOpenRecoveryUseCases { } } +/// Top-level helper that performs the `_ownerSettingsOrDefault` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _ownerSettingsOrDefault( ApplicationUnitOfWorkRepositories repositories, OwnerTimeZoneContext ownerTimeZone, @@ -195,6 +206,8 @@ Future _ownerSettingsOrDefault( ); } +/// Top-level helper that performs the `_loadSourceAndTargetTasks` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future> _loadSourceAndTargetTasks( ApplicationUnitOfWorkRepositories repositories, { required SchedulingWindow sourceWindow, @@ -214,6 +227,8 @@ Future> _loadSourceAndTargetTasks( return List.unmodifiable(byId.values); } +/// Top-level helper that performs the `_rolloverNotice` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. SchedulingNotice? _rolloverNotice({ required SchedulingWindow sourceWindow, required SchedulingResult result, @@ -248,6 +263,8 @@ SchedulingNotice? _rolloverNotice({ ); } +/// Top-level helper that performs the `_activitiesForRolloverChanges` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _activitiesForRolloverChanges({ required SchedulingResult result, required List beforeTasks, @@ -295,6 +312,8 @@ List _activitiesForRolloverChanges({ return List.unmodifiable(activities); } +/// Top-level helper that performs the `_changedTasks` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _changedTasks(List beforeTasks, List afterTasks) { final beforeById = { for (final task in beforeTasks) task.id: task, @@ -311,6 +330,8 @@ List _changedTasks(List beforeTasks, List afterTasks) { return List.unmodifiable(changed); } +/// Top-level helper that performs the `_taskChanged` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _taskChanged(Task before, Task after) { return before.status != after.status || before.scheduledStart != after.scheduledStart || @@ -319,6 +340,8 @@ bool _taskChanged(Task before, Task after) { before.stats != after.stats; } +/// Top-level helper that performs the `_rolloverSnapshotId` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _rolloverSnapshotId({ required String ownerId, required CivilDate sourceDate, diff --git a/packages/scheduler_core/lib/src/backlog.dart b/packages/scheduler_core/lib/src/backlog.dart index f468f79..2cbbd31 100644 --- a/packages/scheduler_core/lib/src/backlog.dart +++ b/packages/scheduler_core/lib/src/backlog.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Backlog behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/backlog/queries/backlog_filter.dart b/packages/scheduler_core/lib/src/backlog/queries/backlog_filter.dart index b0e7fab..d49f579 100644 --- a/packages/scheduler_core/lib/src/backlog/queries/backlog_filter.dart +++ b/packages/scheduler_core/lib/src/backlog/queries/backlog_filter.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../backlog.dart'; /// Derived backlog filters for a unified backlog list. diff --git a/packages/scheduler_core/lib/src/backlog/queries/backlog_sort_key.dart b/packages/scheduler_core/lib/src/backlog/queries/backlog_sort_key.dart index abc33db..7fbdd39 100644 --- a/packages/scheduler_core/lib/src/backlog/queries/backlog_sort_key.dart +++ b/packages/scheduler_core/lib/src/backlog/queries/backlog_sort_key.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../backlog.dart'; /// Sort options for a unified backlog list. diff --git a/packages/scheduler_core/lib/src/backlog/staleness/backlog_staleness_marker.dart b/packages/scheduler_core/lib/src/backlog/staleness/backlog_staleness_marker.dart index c2b254c..e0a837d 100644 --- a/packages/scheduler_core/lib/src/backlog/staleness/backlog_staleness_marker.dart +++ b/packages/scheduler_core/lib/src/backlog/staleness/backlog_staleness_marker.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../backlog.dart'; /// Visual age bucket for backlog display. diff --git a/packages/scheduler_core/lib/src/backlog/staleness/backlog_staleness_settings.dart b/packages/scheduler_core/lib/src/backlog/staleness/backlog_staleness_settings.dart index 4fc3768..f100a3a 100644 --- a/packages/scheduler_core/lib/src/backlog/staleness/backlog_staleness_settings.dart +++ b/packages/scheduler_core/lib/src/backlog/staleness/backlog_staleness_settings.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../backlog.dart'; /// Configurable thresholds for backlog age markers. @@ -7,6 +10,8 @@ part of '../../backlog.dart'; /// a value object makes future settings/preferences easy to inject in tests or /// user configuration. class BacklogStalenessSettings { + /// Creates a `BacklogStalenessSettings` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const BacklogStalenessSettings({ this.greenMaxAge = const Duration(days: 7), this.blueMaxAge = const Duration(days: 30), diff --git a/packages/scheduler_core/lib/src/backlog/views/backlog_view.dart b/packages/scheduler_core/lib/src/backlog/views/backlog_view.dart index 51069d2..e19cecf 100644 --- a/packages/scheduler_core/lib/src/backlog/views/backlog_view.dart +++ b/packages/scheduler_core/lib/src/backlog/views/backlog_view.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../backlog.dart'; /// Read-only backlog projection over the unified task list. @@ -7,6 +10,8 @@ part of '../../backlog.dart'; /// That keeps backlog display logic out of widgets and avoids duplicating the /// same filtering rules in multiple screens. class BacklogView { + /// Creates a `BacklogView` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. BacklogView({ required List tasks, required this.now, diff --git a/packages/scheduler_core/lib/src/backlog/views/indexed_task.dart b/packages/scheduler_core/lib/src/backlog/views/indexed_task.dart index 0c0d93f..c538c6f 100644 --- a/packages/scheduler_core/lib/src/backlog/views/indexed_task.dart +++ b/packages/scheduler_core/lib/src/backlog/views/indexed_task.dart @@ -1,12 +1,22 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../backlog.dart'; /// Backlog task paired with its source-list position for stable sorting. class _IndexedTask { + /// Creates a `_IndexedTask` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _IndexedTask({ required this.task, required this.originalIndex, }); + /// Stores the `task` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Task task; + + /// Stores the `originalIndex` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int originalIndex; } diff --git a/packages/scheduler_core/lib/src/child_tasks.dart b/packages/scheduler_core/lib/src/child_tasks.dart index fd6017c..3fb2cc5 100644 --- a/packages/scheduler_core/lib/src/child_tasks.dart +++ b/packages/scheduler_core/lib/src/child_tasks.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Child Tasks behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/child_tasks/indexing/indexed_child.dart b/packages/scheduler_core/lib/src/child_tasks/indexing/indexed_child.dart index 7f27e93..62b03ca 100644 --- a/packages/scheduler_core/lib/src/child_tasks/indexing/indexed_child.dart +++ b/packages/scheduler_core/lib/src/child_tasks/indexing/indexed_child.dart @@ -1,15 +1,29 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../child_tasks.dart'; +/// Private implementation type for `_IndexedChild` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _IndexedChild { + /// Creates a `_IndexedChild` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _IndexedChild({ required this.task, required this.originalIndex, }); + /// Stores the `task` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Task task; + + /// Stores the `originalIndex` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int originalIndex; } +/// Top-level helper that performs the `_priorityRank` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _priorityRank(PriorityLevel? priority) { return switch (priority) { PriorityLevel.veryLow => 0, @@ -21,6 +35,8 @@ int _priorityRank(PriorityLevel? priority) { }; } +/// Top-level helper that performs the `_taskById` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Task? _taskById(List tasks, String taskId) { for (final task in tasks) { if (task.id == taskId) { @@ -31,16 +47,22 @@ Task? _taskById(List tasks, String taskId) { return null; } +/// Top-level helper that performs the `_replaceTask` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _replaceTask(List tasks, Task replacement) { return tasks .map((task) => task.id == replacement.id ? replacement : task) .toList(growable: false); } +/// Top-level helper that performs the `_defaultOperationId` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _defaultOperationId(String actionName, String taskId, DateTime at) { return '$actionName:$taskId:${at.toIso8601String()}'; } +/// Top-level helper that performs the `_activityId` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _activityId( String operationId, String taskId, @@ -49,6 +71,8 @@ String _activityId( return '$operationId:$taskId:${activityCode.name}'; } +/// Top-level helper that performs the `_requiredTrimmed` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredTrimmed(String value, String name) { final trimmed = value.trim(); if (trimmed.isEmpty) { diff --git a/packages/scheduler_core/lib/src/child_tasks/models/child_task_entry.dart b/packages/scheduler_core/lib/src/child_tasks/models/child_task_entry.dart index 8cdfa8c..0820410 100644 --- a/packages/scheduler_core/lib/src/child_tasks/models/child_task_entry.dart +++ b/packages/scheduler_core/lib/src/child_tasks/models/child_task_entry.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../child_tasks.dart'; /// Row-style input for creating one child task. @@ -6,6 +9,8 @@ part of '../../child_tasks.dart'; /// one, so callers should preserve row insertion order instead of treating the /// child as medium priority. class ChildTaskEntry { + /// Creates a `ChildTaskEntry` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ChildTaskEntry({ required this.id, required this.title, diff --git a/packages/scheduler_core/lib/src/child_tasks/models/child_task_summary.dart b/packages/scheduler_core/lib/src/child_tasks/models/child_task_summary.dart index 2cedcd8..94df154 100644 --- a/packages/scheduler_core/lib/src/child_tasks/models/child_task_summary.dart +++ b/packages/scheduler_core/lib/src/child_tasks/models/child_task_summary.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../child_tasks.dart'; /// Status counts for a parent's direct children. class ChildTaskSummary { + /// Creates a `ChildTaskSummary` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ChildTaskSummary({ required this.totalCount, required this.plannedCount, diff --git a/packages/scheduler_core/lib/src/child_tasks/models/child_task_view.dart b/packages/scheduler_core/lib/src/child_tasks/models/child_task_view.dart index 7a49e3d..6502920 100644 --- a/packages/scheduler_core/lib/src/child_tasks/models/child_task_view.dart +++ b/packages/scheduler_core/lib/src/child_tasks/models/child_task_view.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../child_tasks.dart'; /// Read-only parent/child projection over a task list. @@ -6,6 +9,8 @@ part of '../../child_tasks.dart'; /// as "which tasks belong to this parent?" while leaving task placement and /// completion rules to other domain services. class ChildTaskView { + /// Creates a `ChildTaskView` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. ChildTaskView({ required List tasks, }) : tasks = List.unmodifiable(tasks); diff --git a/packages/scheduler_core/lib/src/child_tasks/requests/child_task_break_up_request.dart b/packages/scheduler_core/lib/src/child_tasks/requests/child_task_break_up_request.dart index 7ae03bf..3ed8538 100644 --- a/packages/scheduler_core/lib/src/child_tasks/requests/child_task_break_up_request.dart +++ b/packages/scheduler_core/lib/src/child_tasks/requests/child_task_break_up_request.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../child_tasks.dart'; /// Command input for breaking one parent task into direct children. class ChildTaskBreakUpRequest { + /// Creates a `ChildTaskBreakUpRequest` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. ChildTaskBreakUpRequest({ required String parentTaskId, required List entries, diff --git a/packages/scheduler_core/lib/src/child_tasks/results/child_task_break_up_result.dart b/packages/scheduler_core/lib/src/child_tasks/results/child_task_break_up_result.dart index 710167b..3176a06 100644 --- a/packages/scheduler_core/lib/src/child_tasks/results/child_task_break_up_result.dart +++ b/packages/scheduler_core/lib/src/child_tasks/results/child_task_break_up_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../child_tasks.dart'; /// Result from breaking a parent task into direct children. class ChildTaskBreakUpResult { + /// Creates a `ChildTaskBreakUpResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. ChildTaskBreakUpResult({ required List tasks, required this.parentTask, diff --git a/packages/scheduler_core/lib/src/child_tasks/results/child_task_completion_result.dart b/packages/scheduler_core/lib/src/child_tasks/results/child_task_completion_result.dart index 316d093..2fde7ea 100644 --- a/packages/scheduler_core/lib/src/child_tasks/results/child_task_completion_result.dart +++ b/packages/scheduler_core/lib/src/child_tasks/results/child_task_completion_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../child_tasks.dart'; /// Result from child/parent completion propagation. class ChildTaskCompletionResult { + /// Creates a `ChildTaskCompletionResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. ChildTaskCompletionResult({ required List tasks, required List changedTaskIds, diff --git a/packages/scheduler_core/lib/src/child_tasks/services/child_task_break_up_service.dart b/packages/scheduler_core/lib/src/child_tasks/services/child_task_break_up_service.dart index 23bf73f..23fa5ce 100644 --- a/packages/scheduler_core/lib/src/child_tasks/services/child_task_break_up_service.dart +++ b/packages/scheduler_core/lib/src/child_tasks/services/child_task_break_up_service.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../child_tasks.dart'; /// Creates direct child tasks from ordered child-entry rows. class ChildTaskBreakUpService { + /// Creates a `ChildTaskBreakUpService` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ChildTaskBreakUpService(); /// Break `request.parentTaskId` into direct child tasks. diff --git a/packages/scheduler_core/lib/src/child_tasks/services/child_task_completion_service.dart b/packages/scheduler_core/lib/src/child_tasks/services/child_task_completion_service.dart index a16d8a3..9b8509a 100644 --- a/packages/scheduler_core/lib/src/child_tasks/services/child_task_completion_service.dart +++ b/packages/scheduler_core/lib/src/child_tasks/services/child_task_completion_service.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../child_tasks.dart'; /// Applies direct parent/child completion rules. @@ -6,6 +9,8 @@ part of '../../child_tasks.dart'; /// dependency graphs, and it only completes sibling children when the caller /// explicitly completes the parent. class ChildTaskCompletionService { + /// Creates a `ChildTaskCompletionService` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ChildTaskCompletionService({ this.clock = const SystemClock(), this.transitionService = const TaskTransitionService(), @@ -241,6 +246,8 @@ class ChildTaskCompletionService { ); } + /// Runs the `_completeWithTransition` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. TaskTransitionResult _completeWithTransition({ required Task task, required String operationId, diff --git a/packages/scheduler_core/lib/src/document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping.dart index c8a0749..7da131a 100644 --- a/packages/scheduler_core/lib/src/document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Document Mapping behavior for the Scheduler Core package. library; @@ -43,7 +46,11 @@ part 'document_mapping/tasks/task_document_extension.dart'; part 'document_mapping/tasks/task_statistics_document_extension.dart'; part 'document_mapping/projects/project_statistics_document_extension.dart'; +/// Adds focused helper behavior through `on`. +/// The extension keeps conversion or convenience logic near the type it supports while avoiding changes to the original model surface. extension on Task { + /// Converts scheduler data for `_validateTaskDocumentMetadata` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. void _validateTaskDocumentMetadata(Map document) { _requiredNullableDateTime(document, TaskDocumentFields.backlogEnteredAt); _requiredNullableString( @@ -53,7 +60,11 @@ extension on Task { } } +/// Adds focused helper behavior through `on`. +/// The extension keeps conversion or convenience logic near the type it supports while avoiding changes to the original model surface. extension on ProjectStatistics { + /// Converts scheduler data for `_validateProjectStatisticsDocumentMetadata` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. void _validateProjectStatisticsDocumentMetadata( Map document, ) { @@ -71,7 +82,11 @@ extension on ProjectStatistics { } } +/// Adds focused helper behavior through `on`. +/// The extension keeps conversion or convenience logic near the type it supports while avoiding changes to the original model surface. extension on SchedulingStateSnapshot { + /// Converts scheduler data for `_validateSchedulingSnapshotDocumentMetadata` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. void _validateSchedulingSnapshotDocumentMetadata( Map document, ) { diff --git a/packages/scheduler_core/lib/src/document_mapping/application/application_operation_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/application/application_operation_document_mapping.dart index eb53e45..20bd1ae 100644 --- a/packages/scheduler_core/lib/src/document_mapping/application/application_operation_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/application/application_operation_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [ApplicationOperationRecord]. abstract final class ApplicationOperationDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument( ApplicationOperationRecord record, { int revision = 1, @@ -21,6 +26,8 @@ abstract final class ApplicationOperationDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static ApplicationOperationRecord fromDocument( Map document, ) { diff --git a/packages/scheduler_core/lib/src/document_mapping/application/backlog_staleness_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/application/backlog_staleness_document_mapping.dart index db55fb0..46bd537 100644 --- a/packages/scheduler_core/lib/src/document_mapping/application/backlog_staleness_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/application/backlog_staleness_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [BacklogStalenessSettings]. abstract final class BacklogStalenessDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument(BacklogStalenessSettings settings) { return { BacklogStalenessDocumentFields.greenMaxAgeDays: @@ -10,6 +15,8 @@ abstract final class BacklogStalenessDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static BacklogStalenessSettings fromDocument(Map document) { return _mapInvalidValues(() { final greenDays = _requiredInt( diff --git a/packages/scheduler_core/lib/src/document_mapping/application/notice_acknowledgement_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/application/notice_acknowledgement_document_mapping.dart index 3b98ee4..f409bb3 100644 --- a/packages/scheduler_core/lib/src/document_mapping/application/notice_acknowledgement_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/application/notice_acknowledgement_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [NoticeAcknowledgementRecord]. abstract final class NoticeAcknowledgementDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument( NoticeAcknowledgementRecord record, { int revision = 1, @@ -20,6 +25,8 @@ abstract final class NoticeAcknowledgementDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static NoticeAcknowledgementRecord fromDocument( Map document, ) { diff --git a/packages/scheduler_core/lib/src/document_mapping/application/owner_settings_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/application/owner_settings_document_mapping.dart index 4df1841..efcfa93 100644 --- a/packages/scheduler_core/lib/src/document_mapping/application/owner_settings_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/application/owner_settings_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [OwnerSettings]. abstract final class OwnerSettingsDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument( OwnerSettings settings, { required DateTime createdAt, @@ -30,6 +35,8 @@ abstract final class OwnerSettingsDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static OwnerSettings fromDocument(Map document) { return _mapInvalidValues(() { _readCommon(document); diff --git a/packages/scheduler_core/lib/src/document_mapping/enums/persistence_enum_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/enums/persistence_enum_mapping.dart index d9bee32..12628cc 100644 --- a/packages/scheduler_core/lib/src/document_mapping/enums/persistence_enum_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/enums/persistence_enum_mapping.dart @@ -1,11 +1,18 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Stable enum encode/decode helpers for V1 document maps. abstract final class PersistenceEnumMapping { + /// Performs the `encodeNullable` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String? encodeNullable(Enum? value) { return value == null ? null : encode(value); } + /// Performs the `encode` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encode(Enum value) { if (value is TaskType) return encodeTaskType(value); if (value is TaskStatus) return encodeTaskStatus(value); @@ -36,6 +43,8 @@ abstract final class PersistenceEnumMapping { ); } + /// Performs the `encodeTaskType` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodeTaskType(TaskType value) => switch (value) { TaskType.flexible => 'flexible', TaskType.inflexible => 'inflexible', @@ -45,10 +54,14 @@ abstract final class PersistenceEnumMapping { TaskType.freeSlot => 'free_slot', }; + /// Performs the `decodeTaskType` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static TaskType decodeTaskType(String value) { return _decodeCode(_taskTypeByCode, value, 'TaskType'); } + /// Performs the `encodeTaskStatus` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodeTaskStatus(TaskStatus value) => switch (value) { TaskStatus.planned => 'planned', TaskStatus.active => 'active', @@ -59,10 +72,14 @@ abstract final class PersistenceEnumMapping { TaskStatus.backlog => 'backlog', }; + /// Performs the `decodeTaskStatus` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static TaskStatus decodeTaskStatus(String value) { return _decodeCode(_taskStatusByCode, value, 'TaskStatus'); } + /// Performs the `encodePriority` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodePriority(PriorityLevel value) => switch (value) { PriorityLevel.veryLow => 'very_low', PriorityLevel.low => 'low', @@ -71,12 +88,16 @@ abstract final class PersistenceEnumMapping { PriorityLevel.veryHigh => 'very_high', }; + /// Performs the `decodeNullablePriority` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static PriorityLevel? decodeNullablePriority(String? value) { return value == null ? null : _decodeCode(_priorityByCode, value, 'PriorityLevel'); } + /// Performs the `encodeReward` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodeReward(RewardLevel value) => switch (value) { RewardLevel.notSet => 'not_set', RewardLevel.veryLow => 'very_low', @@ -86,10 +107,14 @@ abstract final class PersistenceEnumMapping { RewardLevel.veryHigh => 'very_high', }; + /// Performs the `decodeReward` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static RewardLevel decodeReward(String value) { return _decodeCode(_rewardByCode, value, 'RewardLevel'); } + /// Performs the `encodeDifficulty` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodeDifficulty(DifficultyLevel value) => switch (value) { DifficultyLevel.notSet => 'not_set', DifficultyLevel.veryEasy => 'very_easy', @@ -99,10 +124,14 @@ abstract final class PersistenceEnumMapping { DifficultyLevel.veryHard => 'very_hard', }; + /// Performs the `decodeDifficulty` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static DifficultyLevel decodeDifficulty(String value) { return _decodeCode(_difficultyByCode, value, 'DifficultyLevel'); } + /// Performs the `encodeReminderProfile` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodeReminderProfile(ReminderProfile value) => switch (value) { ReminderProfile.silent => 'silent', ReminderProfile.gentle => 'gentle', @@ -110,20 +139,28 @@ abstract final class PersistenceEnumMapping { ReminderProfile.strict => 'strict', }; + /// Performs the `decodeNullableReminderProfile` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static ReminderProfile? decodeNullableReminderProfile(String? value) { return value == null ? null : _decodeCode(_reminderProfileByCode, value, 'ReminderProfile'); } + /// Performs the `encodeBacklogTag` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodeBacklogTag(BacklogTag value) => switch (value) { BacklogTag.wishlist => 'wishlist', }; + /// Performs the `decodeBacklogTag` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static BacklogTag decodeBacklogTag(String value) { return _decodeCode(_backlogTagByCode, value, 'BacklogTag'); } + /// Performs the `encodeLockedWeekday` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodeLockedWeekday(LockedWeekday value) => switch (value) { LockedWeekday.monday => 'monday', LockedWeekday.tuesday => 'tuesday', @@ -134,10 +171,14 @@ abstract final class PersistenceEnumMapping { LockedWeekday.sunday => 'sunday', }; + /// Performs the `decodeLockedWeekday` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static LockedWeekday decodeLockedWeekday(String value) { return _decodeCode(_lockedWeekdayByCode, value, 'LockedWeekday'); } + /// Performs the `encodeLockedBlockOverrideType` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodeLockedBlockOverrideType( LockedBlockOverrideType value, ) => @@ -147,6 +188,8 @@ abstract final class PersistenceEnumMapping { LockedBlockOverrideType.add => 'add', }; + /// Performs the `decodeLockedBlockOverrideType` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static LockedBlockOverrideType decodeLockedBlockOverrideType(String value) { return _decodeCode( _lockedBlockOverrideTypeByCode, @@ -155,6 +198,8 @@ abstract final class PersistenceEnumMapping { ); } + /// Performs the `encodeTaskActivityCode` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodeTaskActivityCode(TaskActivityCode value) => switch (value) { TaskActivityCode.completed => 'completed', @@ -168,10 +213,14 @@ abstract final class PersistenceEnumMapping { TaskActivityCode.activated => 'activated', }; + /// Performs the `decodeTaskActivityCode` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static TaskActivityCode decodeTaskActivityCode(String value) { return _decodeCode(_taskActivityCodeByCode, value, 'TaskActivityCode'); } + /// Performs the `encodeSchedulingNoticeType` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodeSchedulingNoticeType(SchedulingNoticeType value) => switch (value) { SchedulingNoticeType.info => 'info', @@ -181,6 +230,8 @@ abstract final class PersistenceEnumMapping { SchedulingNoticeType.overflow => 'overflow', }; + /// Performs the `decodeSchedulingNoticeType` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static SchedulingNoticeType decodeSchedulingNoticeType(String value) { return _decodeCode( _schedulingNoticeTypeByCode, @@ -189,6 +240,8 @@ abstract final class PersistenceEnumMapping { ); } + /// Performs the `encodeSchedulingIssueCode` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodeSchedulingIssueCode(SchedulingIssueCode value) => switch (value) { SchedulingIssueCode.taskNotFound => 'task_not_found', @@ -204,6 +257,8 @@ abstract final class PersistenceEnumMapping { SchedulingIssueCode.duplicateSurpriseLog => 'duplicate_surprise_log', }; + /// Performs the `decodeNullableSchedulingIssueCode` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static SchedulingIssueCode? decodeNullableSchedulingIssueCode(String? value) { return value == null ? null @@ -214,6 +269,8 @@ abstract final class PersistenceEnumMapping { ); } + /// Performs the `encodeSchedulingMovementCode` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodeSchedulingMovementCode(SchedulingMovementCode value) => switch (value) { SchedulingMovementCode.backlogTaskInserted => 'backlog_task_inserted', @@ -231,6 +288,8 @@ abstract final class PersistenceEnumMapping { 'required_commitment_scheduled', }; + /// Performs the `decodeNullableSchedulingMovementCode` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static SchedulingMovementCode? decodeNullableSchedulingMovementCode( String? value, ) { @@ -243,6 +302,8 @@ abstract final class PersistenceEnumMapping { ); } + /// Performs the `encodeSchedulingConflictCode` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodeSchedulingConflictCode(SchedulingConflictCode value) => switch (value) { SchedulingConflictCode.flexibleTaskOverlapsBlockedTime => @@ -253,6 +314,8 @@ abstract final class PersistenceEnumMapping { 'required_commitment_overlaps_protected_free_slot', }; + /// Performs the `decodeNullableSchedulingConflictCode` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static SchedulingConflictCode? decodeNullableSchedulingConflictCode( String? value, ) { @@ -265,6 +328,8 @@ abstract final class PersistenceEnumMapping { ); } + /// Performs the `encodeProjectCompletionTimeBucket` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static String encodeProjectCompletionTimeBucket( ProjectCompletionTimeBucket value, ) => @@ -276,6 +341,8 @@ abstract final class PersistenceEnumMapping { ProjectCompletionTimeBucket.night => 'night', }; + /// Performs the `decodeProjectCompletionTimeBucket` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static ProjectCompletionTimeBucket decodeProjectCompletionTimeBucket( String value, ) { diff --git a/packages/scheduler_core/lib/src/document_mapping/failures/document_mapping_exception.dart b/packages/scheduler_core/lib/src/document_mapping/failures/document_mapping_exception.dart index d383dfb..de1b8b2 100644 --- a/packages/scheduler_core/lib/src/document_mapping/failures/document_mapping_exception.dart +++ b/packages/scheduler_core/lib/src/document_mapping/failures/document_mapping_exception.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Typed mapping failure for malformed V1 documents. class DocumentMappingException implements Exception { + /// Creates a `DocumentMappingException` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const DocumentMappingException({ required this.code, this.fieldName, @@ -17,6 +22,8 @@ class DocumentMappingException implements Exception { /// Optional narrower reason. final String? detailCode; + /// Converts scheduler data for `toString` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. @override String toString() { return 'DocumentMappingException($code, field: $fieldName, detail: ' diff --git a/packages/scheduler_core/lib/src/document_mapping/failures/document_mapping_failure_code.dart b/packages/scheduler_core/lib/src/document_mapping/failures/document_mapping_failure_code.dart index 2971cef..ce0b0b2 100644 --- a/packages/scheduler_core/lib/src/document_mapping/failures/document_mapping_failure_code.dart +++ b/packages/scheduler_core/lib/src/document_mapping/failures/document_mapping_failure_code.dart @@ -1,11 +1,31 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Stable document mapping failure categories. enum DocumentMappingFailureCode { + /// Selects the `missingField` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. missingField, + + /// Selects the `wrongType` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. wrongType, + + /// Selects the `unknownCode` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. unknownCode, + + /// Selects the `invalidSchemaVersion` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidSchemaVersion, + + /// Selects the `invalidRevision` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidRevision, + + /// Selects the `invalidValue` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidValue, } diff --git a/packages/scheduler_core/lib/src/document_mapping/locked_time/locked_block_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/locked_time/locked_block_document_mapping.dart index 041562d..e201c33 100644 --- a/packages/scheduler_core/lib/src/document_mapping/locked_time/locked_block_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/locked_time/locked_block_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [LockedBlock]. abstract final class LockedBlockDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument( LockedBlock block, { required String ownerId, @@ -32,6 +37,8 @@ abstract final class LockedBlockDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static LockedBlock fromDocument(Map document) { return _mapInvalidValues(() { _readCommon(document); diff --git a/packages/scheduler_core/lib/src/document_mapping/locked_time/locked_block_override_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/locked_time/locked_block_override_document_mapping.dart index 2ff50c4..0d8cb15 100644 --- a/packages/scheduler_core/lib/src/document_mapping/locked_time/locked_block_override_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/locked_time/locked_block_override_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [LockedBlockOverride]. abstract final class LockedBlockOverrideDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument( LockedBlockOverride override, { required String ownerId, @@ -31,6 +36,8 @@ abstract final class LockedBlockOverrideDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static LockedBlockOverride fromDocument(Map document) { return _mapInvalidValues(() { _readCommon(document); diff --git a/packages/scheduler_core/lib/src/document_mapping/locked_time/locked_block_recurrence_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/locked_time/locked_block_recurrence_document_mapping.dart index 5facbb8..bba354b 100644 --- a/packages/scheduler_core/lib/src/document_mapping/locked_time/locked_block_recurrence_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/locked_time/locked_block_recurrence_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [LockedBlockRecurrence]. abstract final class LockedBlockRecurrenceDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument(LockedBlockRecurrence recurrence) { return { LockedBlockRecurrenceDocumentFields.type: 'weekly', @@ -11,6 +16,8 @@ abstract final class LockedBlockRecurrenceDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static LockedBlockRecurrence fromDocument(Map document) { return _mapInvalidValues(() { final type = _requiredString( diff --git a/packages/scheduler_core/lib/src/document_mapping/metadata/document_metadata.dart b/packages/scheduler_core/lib/src/document_mapping/metadata/document_metadata.dart index 5b15a3d..69177f1 100644 --- a/packages/scheduler_core/lib/src/document_mapping/metadata/document_metadata.dart +++ b/packages/scheduler_core/lib/src/document_mapping/metadata/document_metadata.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Common metadata decoded from a V1 top-level document. class DocumentMetadata { + /// Creates a `DocumentMetadata` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const DocumentMetadata({ required this.id, required this.ownerId, @@ -10,9 +15,23 @@ class DocumentMetadata { required this.updatedAt, }); + /// Stores the `id` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String id; + + /// Stores the `ownerId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String ownerId; + + /// Stores the `revision` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int revision; + + /// Stores the `createdAt` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DateTime createdAt; + + /// Stores the `updatedAt` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DateTime updatedAt; } diff --git a/packages/scheduler_core/lib/src/document_mapping/projects/project_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/projects/project_document_mapping.dart index c505f90..982e54b 100644 --- a/packages/scheduler_core/lib/src/document_mapping/projects/project_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/projects/project_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [ProjectProfile]. abstract final class ProjectDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument( ProjectProfile project, { required String ownerId, @@ -35,6 +40,8 @@ abstract final class ProjectDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static ProjectProfile fromDocument(Map document) { return _mapInvalidValues(() { _readCommon(document); diff --git a/packages/scheduler_core/lib/src/document_mapping/projects/project_statistics_document_extension.dart b/packages/scheduler_core/lib/src/document_mapping/projects/project_statistics_document_extension.dart index bd3d4f9..64794ec 100644 --- a/packages/scheduler_core/lib/src/document_mapping/projects/project_statistics_document_extension.dart +++ b/packages/scheduler_core/lib/src/document_mapping/projects/project_statistics_document_extension.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Convenience extension for converting [ProjectStatistics] into a document. extension ProjectStatisticsDocumentExtension on ProjectStatistics { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. Map toDocument({ required String ownerId, required DateTime createdAt, @@ -20,6 +25,8 @@ extension ProjectStatisticsDocumentExtension on ProjectStatistics { } } +/// Private file-level value for `_taskTypeByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _taskTypeByCode = { 'flexible': TaskType.flexible, 'inflexible': TaskType.inflexible, @@ -29,6 +36,8 @@ const _taskTypeByCode = { 'free_slot': TaskType.freeSlot, }; +/// Private file-level value for `_taskStatusByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _taskStatusByCode = { 'planned': TaskStatus.planned, 'active': TaskStatus.active, @@ -39,6 +48,8 @@ const _taskStatusByCode = { 'backlog': TaskStatus.backlog, }; +/// Private file-level value for `_priorityByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _priorityByCode = { 'very_low': PriorityLevel.veryLow, 'low': PriorityLevel.low, @@ -47,6 +58,8 @@ const _priorityByCode = { 'very_high': PriorityLevel.veryHigh, }; +/// Private file-level value for `_rewardByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _rewardByCode = { 'not_set': RewardLevel.notSet, 'very_low': RewardLevel.veryLow, @@ -56,6 +69,8 @@ const _rewardByCode = { 'very_high': RewardLevel.veryHigh, }; +/// Private file-level value for `_difficultyByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _difficultyByCode = { 'not_set': DifficultyLevel.notSet, 'very_easy': DifficultyLevel.veryEasy, @@ -65,6 +80,8 @@ const _difficultyByCode = { 'very_hard': DifficultyLevel.veryHard, }; +/// Private file-level value for `_reminderProfileByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _reminderProfileByCode = { 'silent': ReminderProfile.silent, 'gentle': ReminderProfile.gentle, @@ -72,10 +89,14 @@ const _reminderProfileByCode = { 'strict': ReminderProfile.strict, }; +/// Private file-level value for `_backlogTagByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _backlogTagByCode = { 'wishlist': BacklogTag.wishlist, }; +/// Private file-level value for `_lockedWeekdayByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _lockedWeekdayByCode = { 'monday': LockedWeekday.monday, 'tuesday': LockedWeekday.tuesday, @@ -86,12 +107,16 @@ const _lockedWeekdayByCode = { 'sunday': LockedWeekday.sunday, }; +/// Private file-level value for `_lockedBlockOverrideTypeByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _lockedBlockOverrideTypeByCode = { 'remove': LockedBlockOverrideType.remove, 'replace': LockedBlockOverrideType.replace, 'add': LockedBlockOverrideType.add, }; +/// Private file-level value for `_taskActivityCodeByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _taskActivityCodeByCode = { 'completed': TaskActivityCode.completed, 'missed': TaskActivityCode.missed, @@ -104,6 +129,8 @@ const _taskActivityCodeByCode = { 'activated': TaskActivityCode.activated, }; +/// Private file-level value for `_schedulingNoticeTypeByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _schedulingNoticeTypeByCode = { 'info': SchedulingNoticeType.info, 'moved': SchedulingNoticeType.moved, @@ -112,6 +139,8 @@ const _schedulingNoticeTypeByCode = { 'overflow': SchedulingNoticeType.overflow, }; +/// Private file-level value for `_schedulingIssueCodeByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _schedulingIssueCodeByCode = { 'task_not_found': SchedulingIssueCode.taskNotFound, 'invalid_task_state': SchedulingIssueCode.invalidTaskState, @@ -125,6 +154,8 @@ const _schedulingIssueCodeByCode = { 'duplicate_surprise_log': SchedulingIssueCode.duplicateSurpriseLog, }; +/// Private file-level value for `_schedulingMovementCodeByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _schedulingMovementCodeByCode = { 'backlog_task_inserted': SchedulingMovementCode.backlogTaskInserted, 'flexible_task_moved_to_make_room': @@ -141,6 +172,8 @@ const _schedulingMovementCodeByCode = { SchedulingMovementCode.requiredCommitmentScheduled, }; +/// Private file-level value for `_schedulingConflictCodeByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _schedulingConflictCodeByCode = { 'flexible_task_overlaps_blocked_time': SchedulingConflictCode.flexibleTaskOverlapsBlockedTime, @@ -150,6 +183,8 @@ const _schedulingConflictCodeByCode = { SchedulingConflictCode.requiredCommitmentOverlapsProtectedFreeSlot, }; +/// Private file-level value for `_projectCompletionTimeBucketByCode`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _projectCompletionTimeBucketByCode = { 'overnight': ProjectCompletionTimeBucket.overnight, @@ -159,6 +194,8 @@ const _projectCompletionTimeBucketByCode = 'night': ProjectCompletionTimeBucket.night, }; +/// Top-level helper that performs the `_decodeCode` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. T _decodeCode(Map valuesByCode, String code, String fieldName) { final value = valuesByCode[code]; if (value == null) { @@ -171,6 +208,8 @@ T _decodeCode(Map valuesByCode, String code, String fieldName) { return value; } +/// Top-level helper that performs the `_commonFields` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _commonFields({ required String id, required String ownerId, @@ -196,6 +235,8 @@ Map _commonFields({ }; } +/// Top-level helper that performs the `_readCommon` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. DocumentMetadata _readCommon(Map document) { final schemaVersion = _requiredInt(document, DocumentFields.schemaVersion); if (schemaVersion != v1SchemaVersion) { @@ -222,6 +263,8 @@ DocumentMetadata _readCommon(Map document) { ); } +/// Top-level helper that performs the `_mapInvalidValues` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. T _mapInvalidValues(T Function() read) { try { return read(); @@ -246,24 +289,32 @@ T _mapInvalidValues(T Function() read) { } } +/// Top-level helper that performs the `_dateTimeToStored` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _dateTimeToStored(DateTime? value) { return value == null ? null : PersistenceDateTimeConvention.toStoredString(value); } +/// Top-level helper that performs the `_civilDateToStored` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _civilDateToStored(CivilDate? value) { return value == null ? null : PersistenceCivilDateConvention.toStoredString(value); } +/// Top-level helper that performs the `_wallTimeToStored` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _wallTimeToStored(WallTime? value) { return value == null ? null : PersistenceWallTimeConvention.toStoredString(value); } +/// Top-level helper that performs the `_requiredString` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredString(Map document, String fieldName) { if (!document.containsKey(fieldName)) { throw DocumentMappingException( @@ -281,6 +332,8 @@ String _requiredString(Map document, String fieldName) { ); } +/// Top-level helper that performs the `_requiredNullableString` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _requiredNullableString( Map document, String fieldName, @@ -301,6 +354,8 @@ String? _requiredNullableString( ); } +/// Top-level helper that performs the `_requiredInt` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _requiredInt(Map document, String fieldName) { if (!document.containsKey(fieldName)) { throw DocumentMappingException( @@ -318,6 +373,8 @@ int _requiredInt(Map document, String fieldName) { ); } +/// Top-level helper that performs the `_requiredNullableInt` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int? _requiredNullableInt( Map document, String fieldName, @@ -338,6 +395,8 @@ int? _requiredNullableInt( ); } +/// Top-level helper that performs the `_requiredBool` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _requiredBool(Map document, String fieldName) { if (!document.containsKey(fieldName)) { throw DocumentMappingException( @@ -355,12 +414,16 @@ bool _requiredBool(Map document, String fieldName) { ); } +/// Top-level helper that performs the `_requiredDateTime` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. DateTime _requiredDateTime(Map document, String fieldName) { return PersistenceDateTimeConvention.fromStoredString( _requiredString(document, fieldName), ); } +/// Top-level helper that performs the `_requiredNullableDateTime` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. DateTime? _requiredNullableDateTime( Map document, String fieldName, @@ -371,12 +434,16 @@ DateTime? _requiredNullableDateTime( : PersistenceDateTimeConvention.fromStoredString(value); } +/// Top-level helper that performs the `_requiredCivilDate` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. CivilDate _requiredCivilDate(Map document, String fieldName) { return PersistenceCivilDateConvention.fromStoredString( _requiredString(document, fieldName), ); } +/// Top-level helper that performs the `_requiredNullableCivilDate` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. CivilDate? _requiredNullableCivilDate( Map document, String fieldName, @@ -387,12 +454,16 @@ CivilDate? _requiredNullableCivilDate( : PersistenceCivilDateConvention.fromStoredString(value); } +/// Top-level helper that performs the `_requiredWallTime` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. WallTime _requiredWallTime(Map document, String fieldName) { return PersistenceWallTimeConvention.fromStoredString( _requiredString(document, fieldName), ); } +/// Top-level helper that performs the `_requiredNullableWallTime` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. WallTime? _requiredNullableWallTime( Map document, String fieldName, @@ -403,6 +474,8 @@ WallTime? _requiredNullableWallTime( : PersistenceWallTimeConvention.fromStoredString(value); } +/// Top-level helper that performs the `_requiredMap` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _requiredMap( Map document, String fieldName, @@ -426,6 +499,8 @@ Map _requiredMap( ); } +/// Top-level helper that performs the `_requiredNullableMap` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map? _requiredNullableMap( Map document, String fieldName, @@ -452,6 +527,8 @@ Map? _requiredNullableMap( ); } +/// Top-level helper that performs the `_requiredList` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _requiredList(Map document, String fieldName) { if (!document.containsKey(fieldName)) { throw DocumentMappingException( @@ -469,6 +546,8 @@ List _requiredList(Map document, String fieldName) { ); } +/// Top-level helper that performs the `_mappedList` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _mappedList( Map document, String fieldName, @@ -488,12 +567,16 @@ List _mappedList( }).toList(growable: false); } +/// Top-level helper that performs the `_intKeyCountMapToDocument` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _intKeyCountMapToDocument(Map counts) { return { for (final entry in counts.entries) entry.key.toString(): entry.value, }; } +/// Runs the `Enum>` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Map _enumCountMapToDocument( Map counts, String Function(T value) encode, @@ -503,6 +586,8 @@ Map _enumCountMapToDocument( }; } +/// Top-level helper that performs the `_intKeyCountMapFromDocument` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _intKeyCountMapFromDocument( Map document, String fieldName, @@ -514,6 +599,8 @@ Map _intKeyCountMapFromDocument( }; } +/// Runs the `Enum>` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Map _enumCountMapFromDocument( Map document, String fieldName, @@ -526,6 +613,8 @@ Map _enumCountMapFromDocument( }; } +/// Top-level helper that performs the `_countValue` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _countValue(Object? value, String fieldName) { if (value is int) { return value; @@ -536,12 +625,16 @@ int _countValue(Object? value, String fieldName) { ); } +/// Top-level helper that performs the `_plainDocument` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _plainDocument(Map value) { return Map.unmodifiable( value.map((key, value) => MapEntry(key, _plainDocumentValue(value))), ); } +/// Top-level helper that performs the `_plainDocumentValue` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Object? _plainDocumentValue(Object? value) { if (value == null || value is String || diff --git a/packages/scheduler_core/lib/src/document_mapping/projects/project_statistics_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/projects/project_statistics_document_mapping.dart index acea981..9acc263 100644 --- a/packages/scheduler_core/lib/src/document_mapping/projects/project_statistics_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/projects/project_statistics_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [ProjectStatistics]. abstract final class ProjectStatisticsDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument( ProjectStatistics statistics, { required String ownerId, @@ -50,6 +55,8 @@ abstract final class ProjectStatisticsDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static ProjectStatistics fromDocument(Map document) { return _mapInvalidValues(() { _readCommon(document); diff --git a/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_change_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_change_document_mapping.dart index 734831a..3c26120 100644 --- a/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_change_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_change_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [SchedulingChange]. abstract final class SchedulingChangeDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument(SchedulingChange change) { return { SchedulingChangeDocumentFields.taskId: change.taskId, @@ -15,6 +20,8 @@ abstract final class SchedulingChangeDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static SchedulingChange fromDocument(Map document) { return _mapInvalidValues(() { return SchedulingChange( diff --git a/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_notice_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_notice_document_mapping.dart index 9f687db..bee49d8 100644 --- a/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_notice_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_notice_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [SchedulingNotice]. abstract final class SchedulingNoticeDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument(SchedulingNotice notice) { return { SchedulingNoticeDocumentFields.message: notice.message, @@ -26,6 +31,8 @@ abstract final class SchedulingNoticeDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static SchedulingNotice fromDocument(Map document) { return _mapInvalidValues(() { return SchedulingNotice( diff --git a/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_overlap_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_overlap_document_mapping.dart index 439a87c..b5e6971 100644 --- a/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_overlap_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_overlap_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [SchedulingOverlap]. abstract final class SchedulingOverlapDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument(SchedulingOverlap overlap) { return { SchedulingOverlapDocumentFields.taskId: overlap.taskId, @@ -12,6 +17,8 @@ abstract final class SchedulingOverlapDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static SchedulingOverlap fromDocument(Map document) { return _mapInvalidValues(() { return SchedulingOverlap( diff --git a/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_snapshot_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_snapshot_document_mapping.dart index e10efb2..4533181 100644 --- a/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_snapshot_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_snapshot_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [SchedulingStateSnapshot]. abstract final class SchedulingSnapshotDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument( SchedulingStateSnapshot snapshot, { required String ownerId, @@ -58,6 +63,8 @@ abstract final class SchedulingSnapshotDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static SchedulingStateSnapshot fromDocument(Map document) { return _mapInvalidValues(() { _readCommon(document); diff --git a/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_window_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_window_document_mapping.dart index c0b2758..eadc7c9 100644 --- a/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_window_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/scheduling/scheduling_window_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [SchedulingWindow]. abstract final class SchedulingWindowDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument(SchedulingWindow window) { return { SchedulingWindowDocumentFields.start: @@ -11,6 +16,8 @@ abstract final class SchedulingWindowDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static SchedulingWindow fromDocument(Map document) { return _mapInvalidValues(() { return SchedulingWindow( diff --git a/packages/scheduler_core/lib/src/document_mapping/tasks/task_activity_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/tasks/task_activity_document_mapping.dart index 6a476ab..dc2a837 100644 --- a/packages/scheduler_core/lib/src/document_mapping/tasks/task_activity_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/tasks/task_activity_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [TaskActivity]. abstract final class TaskActivityDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument( TaskActivity activity, { required String ownerId, @@ -30,6 +35,8 @@ abstract final class TaskActivityDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static TaskActivity fromDocument(Map document) { return _mapInvalidValues(() { _readCommon(document); diff --git a/packages/scheduler_core/lib/src/document_mapping/tasks/task_document_extension.dart b/packages/scheduler_core/lib/src/document_mapping/tasks/task_document_extension.dart index 7e3d437..d289a3f 100644 --- a/packages/scheduler_core/lib/src/document_mapping/tasks/task_document_extension.dart +++ b/packages/scheduler_core/lib/src/document_mapping/tasks/task_document_extension.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Convenience extension for converting a [Task] into a V1 document map. extension TaskDocumentExtension on Task { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. Map toDocument({ required String ownerId, int revision = 1, diff --git a/packages/scheduler_core/lib/src/document_mapping/tasks/task_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/tasks/task_document_mapping.dart index 3d3a877..3f43df4 100644 --- a/packages/scheduler_core/lib/src/document_mapping/tasks/task_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/tasks/task_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [Task]. abstract final class TaskDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument( Task task, { required String ownerId, @@ -55,6 +60,8 @@ abstract final class TaskDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Task fromDocument(Map document) { return _mapInvalidValues(() { _readCommon(document); @@ -119,6 +126,8 @@ abstract final class TaskDocumentMapping { }); } + /// Converts scheduler data for `_backlogTagsFromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Set _backlogTagsFromDocument( Map document, ) { diff --git a/packages/scheduler_core/lib/src/document_mapping/tasks/task_statistics_document_extension.dart b/packages/scheduler_core/lib/src/document_mapping/tasks/task_statistics_document_extension.dart index 12f679d..4914af7 100644 --- a/packages/scheduler_core/lib/src/document_mapping/tasks/task_statistics_document_extension.dart +++ b/packages/scheduler_core/lib/src/document_mapping/tasks/task_statistics_document_extension.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Convenience extension for converting [TaskStatistics] into an embedded map. extension TaskStatisticsDocumentExtension on TaskStatistics { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. Map toDocument() { return TaskStatisticsDocumentMapping.toDocument(this); } diff --git a/packages/scheduler_core/lib/src/document_mapping/tasks/task_statistics_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/tasks/task_statistics_document_mapping.dart index 871794f..f0f1dec 100644 --- a/packages/scheduler_core/lib/src/document_mapping/tasks/task_statistics_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/tasks/task_statistics_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [TaskStatistics]. abstract final class TaskStatisticsDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument(TaskStatistics stats) { return { TaskStatisticsDocumentFields.skippedDuringBurnoutCount: @@ -29,6 +34,8 @@ abstract final class TaskStatisticsDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static TaskStatistics fromDocument(Map document) { return _mapInvalidValues(() { return TaskStatistics( diff --git a/packages/scheduler_core/lib/src/document_mapping/time/time_interval_document_mapping.dart b/packages/scheduler_core/lib/src/document_mapping/time/time_interval_document_mapping.dart index 4f3a924..7f78c2c 100644 --- a/packages/scheduler_core/lib/src/document_mapping/time/time_interval_document_mapping.dart +++ b/packages/scheduler_core/lib/src/document_mapping/time/time_interval_document_mapping.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_mapping.dart'; /// Document mapping for [TimeInterval]. abstract final class TimeIntervalDocumentMapping { + /// Converts scheduler data for `toDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static Map toDocument(TimeInterval interval) { return { TimeIntervalDocumentFields.start: @@ -12,6 +17,8 @@ abstract final class TimeIntervalDocumentMapping { }; } + /// Converts scheduler data for `fromDocument` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. static TimeInterval fromDocument(Map document) { return _mapInvalidValues(() { return TimeInterval( diff --git a/packages/scheduler_core/lib/src/document_migration.dart b/packages/scheduler_core/lib/src/document_migration.dart index 7cdb9c3..c031d9b 100644 --- a/packages/scheduler_core/lib/src/document_migration.dart +++ b/packages/scheduler_core/lib/src/document_migration.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Document Migration behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/document_migration/codes/document_migration_entity.dart b/packages/scheduler_core/lib/src/document_migration/codes/document_migration_entity.dart index af5a730..e355e1a 100644 --- a/packages/scheduler_core/lib/src/document_migration/codes/document_migration_entity.dart +++ b/packages/scheduler_core/lib/src/document_migration/codes/document_migration_entity.dart @@ -1,9 +1,23 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_migration.dart'; /// Entity shape being migrated. enum DocumentMigrationEntity { + /// Selects the `task` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. task, + + /// Selects the `project` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. project, + + /// Selects the `lockedBlock` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. lockedBlock, + + /// Selects the `lockedBlockOverride` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. lockedBlockOverride, } diff --git a/packages/scheduler_core/lib/src/document_migration/codes/document_migration_failure_code.dart b/packages/scheduler_core/lib/src/document_migration/codes/document_migration_failure_code.dart index 57cea1c..6b7bd20 100644 --- a/packages/scheduler_core/lib/src/document_migration/codes/document_migration_failure_code.dart +++ b/packages/scheduler_core/lib/src/document_migration/codes/document_migration_failure_code.dart @@ -1,9 +1,23 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_migration.dart'; /// Typed categories for migration failures. enum DocumentMigrationFailureCode { + /// Selects the `invalidSchemaVersion` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidSchemaVersion, + + /// Selects the `unsupportedSchemaVersion` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. unsupportedSchemaVersion, + + /// Selects the `legacyDocumentFailure` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. legacyDocumentFailure, + + /// Selects the `currentDocumentFailure` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. currentDocumentFailure, } diff --git a/packages/scheduler_core/lib/src/document_migration/codes/document_migration_note_code.dart b/packages/scheduler_core/lib/src/document_migration/codes/document_migration_note_code.dart index 0f65bea..56a38a7 100644 --- a/packages/scheduler_core/lib/src/document_migration/codes/document_migration_note_code.dart +++ b/packages/scheduler_core/lib/src/document_migration/codes/document_migration_note_code.dart @@ -1,7 +1,15 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_migration.dart'; /// Non-fatal migration notes surfaced to callers during dry-runs. enum DocumentMigrationNoteCode { + /// Selects the `approximatedBacklogEnteredAt` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. approximatedBacklogEnteredAt, + + /// Selects the `synthesizedMetadataTimestamp` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. synthesizedMetadataTimestamp, } diff --git a/packages/scheduler_core/lib/src/document_migration/codes/document_migration_status.dart b/packages/scheduler_core/lib/src/document_migration/codes/document_migration_status.dart index 172a03f..5b420ac 100644 --- a/packages/scheduler_core/lib/src/document_migration/codes/document_migration_status.dart +++ b/packages/scheduler_core/lib/src/document_migration/codes/document_migration_status.dart @@ -1,8 +1,19 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_migration.dart'; /// Result state for a migration attempt. enum DocumentMigrationStatus { + /// Selects the `migrated` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. migrated, + + /// Selects the `alreadyCurrent` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. alreadyCurrent, + + /// Selects the `failed` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. failed, } diff --git a/packages/scheduler_core/lib/src/document_migration/legacy/legacy_document_exception.dart b/packages/scheduler_core/lib/src/document_migration/legacy/legacy_document_exception.dart index 285ce5a..cb5e20b 100644 --- a/packages/scheduler_core/lib/src/document_migration/legacy/legacy_document_exception.dart +++ b/packages/scheduler_core/lib/src/document_migration/legacy/legacy_document_exception.dart @@ -1,11 +1,23 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_migration.dart'; +/// Private implementation type for `_LegacyDocumentException` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _LegacyDocumentException implements Exception { + /// Creates a `_LegacyDocumentException` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _LegacyDocumentException({ required this.fieldName, required this.detailCode, }); + /// Stores the `fieldName` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String fieldName; + + /// Stores the `detailCode` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String detailCode; } diff --git a/packages/scheduler_core/lib/src/document_migration/legacy/legacy_metadata_instants.dart b/packages/scheduler_core/lib/src/document_migration/legacy/legacy_metadata_instants.dart index 0f8b8d0..b163ff3 100644 --- a/packages/scheduler_core/lib/src/document_migration/legacy/legacy_metadata_instants.dart +++ b/packages/scheduler_core/lib/src/document_migration/legacy/legacy_metadata_instants.dart @@ -1,15 +1,29 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_migration.dart'; +/// Private implementation type for `_LegacyMetadataInstants` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _LegacyMetadataInstants { + /// Creates a `_LegacyMetadataInstants` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _LegacyMetadataInstants({ required this.createdAt, required this.updatedAt, }); + /// Stores the `createdAt` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String createdAt; + + /// Stores the `updatedAt` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String updatedAt; } +/// Private file-level value for `_taskTypeCodes`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _taskTypeCodes = { 'flexible': 'flexible', 'inflexible': 'inflexible', @@ -20,6 +34,8 @@ const _taskTypeCodes = { 'free_slot': 'free_slot', }; +/// Private file-level value for `_taskStatusCodes`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _taskStatusCodes = { 'planned': 'planned', 'active': 'active', @@ -31,6 +47,8 @@ const _taskStatusCodes = { 'backlog': 'backlog', }; +/// Private file-level value for `_priorityCodes`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _priorityCodes = { 'veryLow': 'very_low', 'very_low': 'very_low', @@ -41,6 +59,8 @@ const _priorityCodes = { 'very_high': 'very_high', }; +/// Private file-level value for `_rewardCodes`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _rewardCodes = { 'notSet': 'not_set', 'not_set': 'not_set', @@ -53,6 +73,8 @@ const _rewardCodes = { 'very_high': 'very_high', }; +/// Private file-level value for `_difficultyCodes`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _difficultyCodes = { 'notSet': 'not_set', 'not_set': 'not_set', @@ -65,6 +87,8 @@ const _difficultyCodes = { 'very_hard': 'very_hard', }; +/// Private file-level value for `_reminderProfileCodes`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _reminderProfileCodes = { 'silent': 'silent', 'gentle': 'gentle', @@ -72,10 +96,14 @@ const _reminderProfileCodes = { 'strict': 'strict', }; +/// Private file-level value for `_backlogTagCodes`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _backlogTagCodes = { 'wishlist': 'wishlist', }; +/// Private file-level value for `_lockedWeekdayCodes`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _lockedWeekdayCodes = { 'monday': 'monday', 'tuesday': 'tuesday', @@ -86,14 +114,20 @@ const _lockedWeekdayCodes = { 'sunday': 'sunday', }; +/// Private file-level value for `_lockedOverrideTypeCodes`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _lockedOverrideTypeCodes = { 'remove': 'remove', 'replace': 'replace', 'add': 'add', }; +/// Private file-level value for `_explicitOffsetPattern`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. final _explicitOffsetPattern = RegExp(r'(Z|[+-]\d{2}:\d{2})$'); +/// Top-level helper that performs the `_readSchemaVersion` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. _SchemaVersionRead _readSchemaVersion(Map document) { if (!document.containsKey(DocumentFields.schemaVersion)) { return const _SchemaVersionRead.version(0); @@ -105,11 +139,15 @@ _SchemaVersionRead _readSchemaVersion(Map document) { return const _SchemaVersionRead.failure('wrongType'); } +/// Top-level helper that performs the `_documentId` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _documentId(Map document) { final value = document[DocumentFields.id]; return value is String ? value : null; } +/// Top-level helper that performs the `_failed` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. DocumentMigrationResult _failed({ required DocumentMigrationEntity entity, required String? documentId, @@ -132,6 +170,8 @@ DocumentMigrationResult _failed({ ); } +/// Top-level helper that performs the `_failedFromMapping` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. DocumentMigrationResult _failedFromMapping({ required DocumentMigrationEntity entity, required String? documentId, @@ -154,6 +194,8 @@ DocumentMigrationResult _failedFromMapping({ ); } +/// Top-level helper that performs the `_requiredString` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredString(Map document, String fieldName) { if (!document.containsKey(fieldName)) { throw _LegacyDocumentException( @@ -171,6 +213,8 @@ String _requiredString(Map document, String fieldName) { ); } +/// Top-level helper that performs the `_requiredNullableString` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _requiredNullableString( Map document, String fieldName, @@ -191,6 +235,8 @@ String? _requiredNullableString( ); } +/// Top-level helper that performs the `_requiredNullableInt` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int? _requiredNullableInt(Map document, String fieldName) { if (!document.containsKey(fieldName)) { throw _LegacyDocumentException( @@ -208,6 +254,8 @@ int? _requiredNullableInt(Map document, String fieldName) { ); } +/// Top-level helper that performs the `_requiredBool` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _requiredBool(Map document, String fieldName) { if (!document.containsKey(fieldName)) { throw _LegacyDocumentException( @@ -225,6 +273,8 @@ bool _requiredBool(Map document, String fieldName) { ); } +/// Top-level helper that performs the `_requiredMap` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _requiredMap( Map document, String fieldName, @@ -245,6 +295,8 @@ Map _requiredMap( ); } +/// Top-level helper that performs the `_requiredLegacyCode` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredLegacyCode( Map document, String fieldName, @@ -261,6 +313,8 @@ String _requiredLegacyCode( return code; } +/// Top-level helper that performs the `_nullableLegacyCode` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _nullableLegacyCode( Map document, String fieldName, @@ -280,6 +334,8 @@ String? _nullableLegacyCode( return code; } +/// Top-level helper that performs the `_requiredLegacyCodeList` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _requiredLegacyCodeList( Map document, String fieldName, @@ -316,6 +372,8 @@ List _requiredLegacyCodeList( }).toList(growable: false); } +/// Top-level helper that performs the `_requiredInstant` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredInstant(Map document, String fieldName) { if (!document.containsKey(fieldName)) { throw _LegacyDocumentException( @@ -334,6 +392,8 @@ String _requiredInstant(Map document, String fieldName) { return stored; } +/// Top-level helper that performs the `_nullableInstant` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _nullableInstant(Map document, String fieldName) { if (!document.containsKey(fieldName)) { throw _LegacyDocumentException( @@ -344,6 +404,8 @@ String? _nullableInstant(Map document, String fieldName) { return _instantToStored(document[fieldName], fieldName); } +/// Top-level helper that performs the `_optionalNullableInstant` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _optionalNullableInstant( Map document, String fieldName, @@ -354,6 +416,8 @@ String? _optionalNullableInstant( return _instantToStored(document[fieldName], fieldName); } +/// Top-level helper that performs the `_instantToStored` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _instantToStored(Object? value, String fieldName) { if (value == null) { return null; @@ -391,6 +455,8 @@ String? _instantToStored(Object? value, String fieldName) { ); } +/// Top-level helper that performs the `_requiredCivilDate` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredCivilDate(Map document, String fieldName) { if (!document.containsKey(fieldName)) { throw _LegacyDocumentException( @@ -408,6 +474,8 @@ String _requiredCivilDate(Map document, String fieldName) { return value; } +/// Top-level helper that performs the `_requiredNullableCivilDate` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _requiredNullableCivilDate( Map document, String fieldName, @@ -421,6 +489,8 @@ String? _requiredNullableCivilDate( return _civilDateToStored(document[fieldName], fieldName); } +/// Top-level helper that performs the `_civilDateToStored` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _civilDateToStored(Object? value, String fieldName) { if (value == null) { return null; @@ -449,6 +519,8 @@ String? _civilDateToStored(Object? value, String fieldName) { ); } +/// Top-level helper that performs the `_requiredWallTime` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredWallTime(Map document, String fieldName) { if (!document.containsKey(fieldName)) { throw _LegacyDocumentException( @@ -466,6 +538,8 @@ String _requiredWallTime(Map document, String fieldName) { return value; } +/// Top-level helper that performs the `_requiredNullableWallTime` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _requiredNullableWallTime( Map document, String fieldName, @@ -479,6 +553,8 @@ String? _requiredNullableWallTime( return _wallTimeToStored(document[fieldName], fieldName); } +/// Top-level helper that performs the `_wallTimeToStored` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _wallTimeToStored(Object? value, String fieldName) { if (value == null) { return null; @@ -520,6 +596,8 @@ String? _wallTimeToStored(Object? value, String fieldName) { ); } +/// Top-level helper that performs the `_nullableRecurrence` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map? _nullableRecurrence( Map document, String fieldName, @@ -570,10 +648,14 @@ Map? _nullableRecurrence( }; } +/// Top-level helper that performs the `_deepCopyDocument` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _deepCopyDocument(Map document) { return _deepCopyMap(document, 'document'); } +/// Top-level helper that performs the `_deepCopyMap` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _deepCopyMap(Map map, String fieldName) { return { for (final entry in map.entries) @@ -581,6 +663,8 @@ Map _deepCopyMap(Map map, String fieldName) { }; } +/// Top-level helper that performs the `_stringKey` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _stringKey(Object? key, String fieldName) { if (key is String) { return key; @@ -591,6 +675,8 @@ String _stringKey(Object? key, String fieldName) { ); } +/// Top-level helper that performs the `_deepCopyValue` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Object? _deepCopyValue(Object? value, String fieldName) { if (value is Map) { return _deepCopyMap(value, fieldName); diff --git a/packages/scheduler_core/lib/src/document_migration/reports/document_migration_note.dart b/packages/scheduler_core/lib/src/document_migration/reports/document_migration_note.dart index 3f12708..ce0258f 100644 --- a/packages/scheduler_core/lib/src/document_migration/reports/document_migration_note.dart +++ b/packages/scheduler_core/lib/src/document_migration/reports/document_migration_note.dart @@ -1,14 +1,27 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_migration.dart'; /// A non-fatal detail about a migrated document. class DocumentMigrationNote { + /// Creates a `DocumentMigrationNote` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const DocumentMigrationNote({ required this.code, this.fieldName, this.detailCode, }); + /// Stores the `code` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DocumentMigrationNoteCode code; + + /// Stores the `fieldName` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? fieldName; + + /// Stores the `detailCode` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? detailCode; } diff --git a/packages/scheduler_core/lib/src/document_migration/reports/document_migration_provenance.dart b/packages/scheduler_core/lib/src/document_migration/reports/document_migration_provenance.dart index 00b0626..831885d 100644 --- a/packages/scheduler_core/lib/src/document_migration/reports/document_migration_provenance.dart +++ b/packages/scheduler_core/lib/src/document_migration/reports/document_migration_provenance.dart @@ -1,6 +1,11 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_migration.dart'; /// Provenance labels written by migrations. abstract final class DocumentMigrationProvenance { + /// Shared constant value for `approximatedFromCreatedAt`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const approximatedFromCreatedAt = 'approximated_from_created_at'; } diff --git a/packages/scheduler_core/lib/src/document_migration/reports/document_migration_report.dart b/packages/scheduler_core/lib/src/document_migration/reports/document_migration_report.dart index 51f589e..7c2e0d3 100644 --- a/packages/scheduler_core/lib/src/document_migration/reports/document_migration_report.dart +++ b/packages/scheduler_core/lib/src/document_migration/reports/document_migration_report.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_migration.dart'; /// Typed dry-run report for one document migration attempt. class DocumentMigrationReport { + /// Creates a `DocumentMigrationReport` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const DocumentMigrationReport({ required this.entity, required this.status, @@ -15,16 +20,47 @@ class DocumentMigrationReport { this.notes = const [], }); + /// Stores the `entity` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DocumentMigrationEntity entity; + + /// Stores the `status` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DocumentMigrationStatus status; + + /// Stores the `documentId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? documentId; + + /// Stores the `fromSchemaVersion` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int? fromSchemaVersion; + + /// Stores the `targetSchemaVersion` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int targetSchemaVersion; + + /// Stores the `failureCode` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DocumentMigrationFailureCode? failureCode; + + /// Stores the `mappingFailureCode` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DocumentMappingFailureCode? mappingFailureCode; + + /// Stores the `fieldName` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? fieldName; + + /// Stores the `detailCode` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? detailCode; + + /// Stores the `notes` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final List notes; + /// Returns the derived `canWrite` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. bool get canWrite => status != DocumentMigrationStatus.failed; } diff --git a/packages/scheduler_core/lib/src/document_migration/reports/document_migration_result.dart b/packages/scheduler_core/lib/src/document_migration/reports/document_migration_result.dart index 39370b5..c5f56c8 100644 --- a/packages/scheduler_core/lib/src/document_migration/reports/document_migration_result.dart +++ b/packages/scheduler_core/lib/src/document_migration/reports/document_migration_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_migration.dart'; /// Migration output plus report. class DocumentMigrationResult { + /// Creates a `DocumentMigrationResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const DocumentMigrationResult({ required this.report, required this.document, @@ -10,8 +15,12 @@ class DocumentMigrationResult { /// Migrated/current document. Null means the source must not be overwritten. final Map? document; + /// Stores the `report` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DocumentMigrationReport report; + /// Returns the derived `isSuccess` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. bool get isSuccess => report.status != DocumentMigrationStatus.failed; /// True only when the caller should persist a transformed replacement. diff --git a/packages/scheduler_core/lib/src/document_migration/service/schema_version_read.dart b/packages/scheduler_core/lib/src/document_migration/service/schema_version_read.dart index 3ff8049..3466740 100644 --- a/packages/scheduler_core/lib/src/document_migration/service/schema_version_read.dart +++ b/packages/scheduler_core/lib/src/document_migration/service/schema_version_read.dart @@ -1,9 +1,24 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_migration.dart'; +/// Private implementation type for `_SchemaVersionRead` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _SchemaVersionRead { + /// Creates a `_SchemaVersionRead.version` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _SchemaVersionRead.version(this.version) : failure = null; + + /// Creates a `_SchemaVersionRead.failure` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _SchemaVersionRead.failure(this.failure) : version = 0; + /// Stores the `version` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int version; + + /// Stores the `failure` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? failure; } diff --git a/packages/scheduler_core/lib/src/document_migration/service/v0_migrator.dart b/packages/scheduler_core/lib/src/document_migration/service/v0_migrator.dart index e53f28f..91558cc 100644 --- a/packages/scheduler_core/lib/src/document_migration/service/v0_migrator.dart +++ b/packages/scheduler_core/lib/src/document_migration/service/v0_migrator.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_migration.dart'; typedef _V0Migrator = Map Function( diff --git a/packages/scheduler_core/lib/src/document_migration/service/v1_document_migration_service.dart b/packages/scheduler_core/lib/src/document_migration/service/v1_document_migration_service.dart index ee5d07e..9c71f0a 100644 --- a/packages/scheduler_core/lib/src/document_migration/service/v1_document_migration_service.dart +++ b/packages/scheduler_core/lib/src/document_migration/service/v1_document_migration_service.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../document_migration.dart'; /// Pure V0-to-V1 migration service. @@ -7,14 +10,23 @@ part of '../../document_migration.dart'; /// timestamp. Missing `schemaVersion` is treated as V0; unsupported future /// versions fail closed. class V1DocumentMigrationService { + /// Creates a `V1DocumentMigrationService` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const V1DocumentMigrationService({ required this.ownerId, required this.migratedAt, }); + /// Stores the `ownerId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String ownerId; + + /// Stores the `migratedAt` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DateTime migratedAt; + /// Performs the `migrateTask` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. DocumentMigrationResult migrateTask(Map document) { return _migrate( entity: DocumentMigrationEntity.task, @@ -24,6 +36,8 @@ class V1DocumentMigrationService { ); } + /// Performs the `migrateProject` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. DocumentMigrationResult migrateProject(Map document) { return _migrate( entity: DocumentMigrationEntity.project, @@ -33,6 +47,8 @@ class V1DocumentMigrationService { ); } + /// Performs the `migrateLockedBlock` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. DocumentMigrationResult migrateLockedBlock(Map document) { return _migrate( entity: DocumentMigrationEntity.lockedBlock, @@ -42,6 +58,8 @@ class V1DocumentMigrationService { ); } + /// Performs the `migrateLockedBlockOverride` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. DocumentMigrationResult migrateLockedBlockOverride( Map document, ) { @@ -53,6 +71,8 @@ class V1DocumentMigrationService { ); } + /// Runs the `_migrate` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. DocumentMigrationResult _migrate({ required DocumentMigrationEntity entity, required Map document, @@ -158,6 +178,8 @@ class V1DocumentMigrationService { ); } + /// Runs the `_taskV0ToV1` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. Map _taskV0ToV1( Map document, List notes, @@ -247,6 +269,8 @@ class V1DocumentMigrationService { }; } + /// Runs the `_projectV0ToV1` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. Map _projectV0ToV1( Map document, List notes, @@ -291,6 +315,8 @@ class V1DocumentMigrationService { }; } + /// Runs the `_lockedBlockV0ToV1` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. Map _lockedBlockV0ToV1( Map document, List notes, @@ -325,6 +351,8 @@ class V1DocumentMigrationService { }; } + /// Runs the `_lockedBlockOverrideV0ToV1` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. Map _lockedBlockOverrideV0ToV1( Map document, List notes, @@ -372,6 +400,8 @@ class V1DocumentMigrationService { }; } + /// Runs the `_commonV1Fields` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. Map _commonV1Fields({ required String id, required String createdAt, @@ -387,6 +417,8 @@ class V1DocumentMigrationService { }; } + /// Runs the `_metadataInstants` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. _LegacyMetadataInstants _metadataInstants( Map document, List notes, diff --git a/packages/scheduler_core/lib/src/free_slots.dart b/packages/scheduler_core/lib/src/free_slots.dart index 1325118..d315483 100644 --- a/packages/scheduler_core/lib/src/free_slots.dart +++ b/packages/scheduler_core/lib/src/free_slots.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Free Slots behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/free_slots/free_slot_service.dart b/packages/scheduler_core/lib/src/free_slots/free_slot_service.dart index 8f8566a..6e4b32f 100644 --- a/packages/scheduler_core/lib/src/free_slots/free_slot_service.dart +++ b/packages/scheduler_core/lib/src/free_slots/free_slot_service.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../free_slots.dart'; /// Creates and updates protected Free Slot task records. class FreeSlotService { + /// Creates a `FreeSlotService` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const FreeSlotService(); /// Create a scheduled Free Slot record. @@ -186,6 +191,8 @@ class FreeSlotService { } } +/// Top-level helper that performs the `_unchangedRequiredResult` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. RequiredCommitmentScheduleResult _unchangedRequiredResult({ required SchedulingInput input, required RequiredCommitmentScheduleStatus status, @@ -204,6 +211,8 @@ RequiredCommitmentScheduleResult _unchangedRequiredResult({ ); } +/// Top-level helper that performs the `_protectedFreeSlotConflicts` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _protectedFreeSlotConflicts({ required SchedulingInput input, required String requiredTaskId, @@ -237,6 +246,8 @@ List _protectedFreeSlotConflicts({ return List.unmodifiable(conflicts); } +/// Top-level helper that performs the `_taskById` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Task? _taskById(List tasks, String taskId) { for (final task in tasks) { if (task.id == taskId) { @@ -247,6 +258,8 @@ Task? _taskById(List tasks, String taskId) { return null; } +/// Top-level helper that performs the `_sameDateTime` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _sameDateTime(DateTime? first, DateTime? second) { if (first == null || second == null) { return first == null && second == null; diff --git a/packages/scheduler_core/lib/src/free_slots/protected_free_slot_conflict.dart b/packages/scheduler_core/lib/src/free_slots/protected_free_slot_conflict.dart index 26062ab..467cef2 100644 --- a/packages/scheduler_core/lib/src/free_slots/protected_free_slot_conflict.dart +++ b/packages/scheduler_core/lib/src/free_slots/protected_free_slot_conflict.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../free_slots.dart'; /// Typed overlap between an explicitly placed required commitment and rest. class ProtectedFreeSlotConflict { + /// Creates a `ProtectedFreeSlotConflict` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ProtectedFreeSlotConflict({ required this.requiredTaskId, required this.freeSlotTaskId, diff --git a/packages/scheduler_core/lib/src/free_slots/required_commitment_schedule_result.dart b/packages/scheduler_core/lib/src/free_slots/required_commitment_schedule_result.dart index ab0c89e..8b7c61b 100644 --- a/packages/scheduler_core/lib/src/free_slots/required_commitment_schedule_result.dart +++ b/packages/scheduler_core/lib/src/free_slots/required_commitment_schedule_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../free_slots.dart'; /// Result from explicitly scheduling a required visible commitment. class RequiredCommitmentScheduleResult { + /// Creates a `RequiredCommitmentScheduleResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. RequiredCommitmentScheduleResult({ required this.status, required this.schedulingResult, diff --git a/packages/scheduler_core/lib/src/free_slots/required_commitment_schedule_status.dart b/packages/scheduler_core/lib/src/free_slots/required_commitment_schedule_status.dart index 7c64690..1d6d84b 100644 --- a/packages/scheduler_core/lib/src/free_slots/required_commitment_schedule_status.dart +++ b/packages/scheduler_core/lib/src/free_slots/required_commitment_schedule_status.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../free_slots.dart'; /// Typed outcome for explicitly placing a required visible commitment. diff --git a/packages/scheduler_core/lib/src/locked_time.dart b/packages/scheduler_core/lib/src/locked_time.dart index 0774dfc..9003496 100644 --- a/packages/scheduler_core/lib/src/locked_time.dart +++ b/packages/scheduler_core/lib/src/locked_time.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Locked Time behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/locked_time/aliases/clock_time.dart b/packages/scheduler_core/lib/src/locked_time/aliases/clock_time.dart index c339b79..ab73afb 100644 --- a/packages/scheduler_core/lib/src/locked_time/aliases/clock_time.dart +++ b/packages/scheduler_core/lib/src/locked_time/aliases/clock_time.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../locked_time.dart'; /// Backwards-compatible name for explicit wall-clock time. diff --git a/packages/scheduler_core/lib/src/locked_time/blocks/locked_block.dart b/packages/scheduler_core/lib/src/locked_time/blocks/locked_block.dart index f661436..bb5d63b 100644 --- a/packages/scheduler_core/lib/src/locked_time/blocks/locked_block.dart +++ b/packages/scheduler_core/lib/src/locked_time/blocks/locked_block.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../locked_time.dart'; /// Scheduling constraint that reserves time without becoming a task card. @@ -12,6 +15,8 @@ part of '../../locked_time.dart'; /// - one-off, with [date] set and [recurrence] null; or /// - recurring, with [recurrence] set and [date] usually null. class LockedBlock { + /// Creates a `LockedBlock` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. LockedBlock({ required String id, required String name, diff --git a/packages/scheduler_core/lib/src/locked_time/blocks/locked_block_occurrence.dart b/packages/scheduler_core/lib/src/locked_time/blocks/locked_block_occurrence.dart index 2156803..8fe48b0 100644 --- a/packages/scheduler_core/lib/src/locked_time/blocks/locked_block_occurrence.dart +++ b/packages/scheduler_core/lib/src/locked_time/blocks/locked_block_occurrence.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../locked_time.dart'; /// Concrete locked-time occurrence for one calendar day. @@ -6,6 +9,8 @@ part of '../../locked_time.dart'; /// specific date. The scheduler only needs occurrences/time intervals, while UI /// can use ids and visibility flags to explain where the blocked time came from. class LockedBlockOccurrence { + /// Creates a `LockedBlockOccurrence` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const LockedBlockOccurrence({ required this.name, required this.interval, diff --git a/packages/scheduler_core/lib/src/locked_time/enums/locked_block_override_type.dart b/packages/scheduler_core/lib/src/locked_time/enums/locked_block_override_type.dart index 1fa1fb8..441ea8a 100644 --- a/packages/scheduler_core/lib/src/locked_time/enums/locked_block_override_type.dart +++ b/packages/scheduler_core/lib/src/locked_time/enums/locked_block_override_type.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../locked_time.dart'; /// Type of one-day override applied to locked time. diff --git a/packages/scheduler_core/lib/src/locked_time/enums/locked_weekday.dart b/packages/scheduler_core/lib/src/locked_time/enums/locked_weekday.dart index 607b513..3c9752b 100644 --- a/packages/scheduler_core/lib/src/locked_time/enums/locked_weekday.dart +++ b/packages/scheduler_core/lib/src/locked_time/enums/locked_weekday.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../locked_time.dart'; /// Weekday value using DateTime's Monday-first convention. @@ -6,14 +9,36 @@ part of '../../locked_time.dart'; /// This enum wraps those integers so the rest of the code can talk in readable /// names while still comparing directly to [DateTime.weekday]. enum LockedWeekday { + /// Selects the `monday` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. monday(DateTime.monday), + + /// Selects the `tuesday` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. tuesday(DateTime.tuesday), + + /// Selects the `wednesday` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. wednesday(DateTime.wednesday), + + /// Selects the `thursday` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. thursday(DateTime.thursday), + + /// Selects the `friday` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. friday(DateTime.friday), + + /// Selects the `saturday` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. saturday(DateTime.saturday), + + /// Selects the `sunday` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. sunday(DateTime.sunday); + /// Creates a `LockedWeekday` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const LockedWeekday(this.dateTimeValue); /// Matching [DateTime.weekday] integer value. diff --git a/packages/scheduler_core/lib/src/locked_time/expansion/locked_schedule_expansion.dart b/packages/scheduler_core/lib/src/locked_time/expansion/locked_schedule_expansion.dart index 7abb9be..8d2d3bb 100644 --- a/packages/scheduler_core/lib/src/locked_time/expansion/locked_schedule_expansion.dart +++ b/packages/scheduler_core/lib/src/locked_time/expansion/locked_schedule_expansion.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../locked_time.dart'; /// Expands locked blocks and one-day overrides into concrete intervals. @@ -6,6 +9,8 @@ part of '../../locked_time.dart'; /// and scheduler-friendly intervals. It retains the occurrence details for UI /// while exposing [schedulingIntervals] for placement algorithms. class LockedScheduleExpansion { + /// Creates a `LockedScheduleExpansion` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const LockedScheduleExpansion({ required this.date, required this.occurrences, @@ -377,6 +382,8 @@ DateTime _latest(DateTime first, DateTime second) { return first.isAfter(second) ? first : second; } +/// Top-level helper that performs the `_resolvedInterval` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TimeInterval _resolvedInterval({ required CivilDate date, required ClockTime startTime, @@ -406,8 +413,12 @@ TimeInterval _resolvedInterval({ ); } +/// Top-level helper that performs the `_sameDate` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _sameDate(CivilDate first, CivilDate second) => first == second; +/// Top-level helper that performs the `_requiredLockedString` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredLockedString( String value, String name, @@ -425,6 +436,8 @@ String _requiredLockedString( return trimmed; } +/// Top-level helper that performs the `_nullableLockedString` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _nullableLockedString( String? value, String name, @@ -445,6 +458,8 @@ String? _nullableLockedString( return trimmed; } +/// Top-level helper that performs the `_clockTimeIsBefore` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _clockTimeIsBefore(ClockTime start, ClockTime end) { if (start.hour != end.hour) { return start.hour < end.hour; @@ -452,6 +467,8 @@ bool _clockTimeIsBefore(ClockTime start, ClockTime end) { return start.minute < end.minute; } +/// Top-level helper that performs the `_validateOverrideShape` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. void _validateOverrideShape({ required LockedBlockOverrideType type, required String? lockedBlockId, @@ -504,6 +521,8 @@ void _validateOverrideShape({ } } +/// Top-level helper that performs the `_validateOverrideInterval` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. void _validateOverrideInterval({ required ClockTime? startTime, required ClockTime? endTime, diff --git a/packages/scheduler_core/lib/src/locked_time/overrides/locked_block_override.dart b/packages/scheduler_core/lib/src/locked_time/overrides/locked_block_override.dart index 836b490..af622cc 100644 --- a/packages/scheduler_core/lib/src/locked_time/overrides/locked_block_override.dart +++ b/packages/scheduler_core/lib/src/locked_time/overrides/locked_block_override.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../locked_time.dart'; /// One-day change to locked time that leaves the base recurrence unchanged. @@ -11,6 +14,8 @@ part of '../../locked_time.dart'; /// - [replace] references a base block and swaps its details for one day. /// - [add] creates an extra locked occurrence that has no base block. class LockedBlockOverride { + /// Creates a `LockedBlockOverride` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. LockedBlockOverride({ required String id, required this.date, diff --git a/packages/scheduler_core/lib/src/locked_time/recurrence/locked_block_recurrence.dart b/packages/scheduler_core/lib/src/locked_time/recurrence/locked_block_recurrence.dart index cc6b489..68a3bf8 100644 --- a/packages/scheduler_core/lib/src/locked_time/recurrence/locked_block_recurrence.dart +++ b/packages/scheduler_core/lib/src/locked_time/recurrence/locked_block_recurrence.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../locked_time.dart'; /// Recurrence rule for locked time. @@ -7,6 +10,8 @@ part of '../../locked_time.dart'; /// keeps recurrence separate from [LockedBlock] so monthly or custom recurrence /// rules can be added later without changing the rest of the locked-time model. class LockedBlockRecurrence { + /// Creates a `LockedBlockRecurrence.weekly` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. LockedBlockRecurrence.weekly({ required Set weekdays, }) : weekdays = Set.unmodifiable(weekdays) { diff --git a/packages/scheduler_core/lib/src/models.dart b/packages/scheduler_core/lib/src/models.dart index 928f59e..21ed47c 100644 --- a/packages/scheduler_core/lib/src/models.dart +++ b/packages/scheduler_core/lib/src/models.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Models behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/models/entities/project_profile.dart b/packages/scheduler_core/lib/src/models/entities/project_profile.dart index d9edb6b..66db66c 100644 --- a/packages/scheduler_core/lib/src/models/entities/project_profile.dart +++ b/packages/scheduler_core/lib/src/models/entities/project_profile.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../models.dart'; /// Starter project defaults used when creating or scheduling tasks. @@ -10,6 +13,8 @@ part of '../../models.dart'; /// project defaults separate prevents every scheduling function from needing to /// know project configuration details. class ProjectProfile { + /// Creates a `ProjectProfile` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. ProjectProfile({ required String id, required String name, diff --git a/packages/scheduler_core/lib/src/models/entities/task.dart b/packages/scheduler_core/lib/src/models/entities/task.dart index ac54f3f..46b9b8d 100644 --- a/packages/scheduler_core/lib/src/models/entities/task.dart +++ b/packages/scheduler_core/lib/src/models/entities/task.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../models.dart'; /// Starter task model for the scheduling core. @@ -22,6 +25,8 @@ part of '../../models.dart'; /// This is still a starter V1 model, so behavior changes should be explicit and /// backed by tests as the product rules settle. class Task { + /// Creates a `Task` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. Task({ required String id, required String title, diff --git a/packages/scheduler_core/lib/src/models/entities/time_interval.dart b/packages/scheduler_core/lib/src/models/entities/time_interval.dart index b1bf8cb..8e5e493 100644 --- a/packages/scheduler_core/lib/src/models/entities/time_interval.dart +++ b/packages/scheduler_core/lib/src/models/entities/time_interval.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../models.dart'; /// Starter time range value used by scheduling helpers. @@ -7,6 +10,8 @@ part of '../../models.dart'; /// candidate placements. The interval convention is start-inclusive and /// end-exclusive, which avoids treating two back-to-back blocks as overlapping. class TimeInterval { + /// Creates a `TimeInterval` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. TimeInterval({ required this.start, required this.end, @@ -45,6 +50,8 @@ class TimeInterval { } } +/// Top-level helper that performs the `_requiredTrimmed` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredTrimmed( String value, String name, @@ -63,6 +70,8 @@ String _requiredTrimmed( return trimmed; } +/// Top-level helper that performs the `_nullableTrimmed` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _nullableTrimmed( String? value, String name, @@ -84,6 +93,8 @@ String? _nullableTrimmed( return trimmed; } +/// Top-level helper that performs the `_validatePositiveDuration` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. void _validatePositiveDuration(int? durationMinutes, String name) { if (durationMinutes == null) { return; @@ -98,6 +109,8 @@ void _validatePositiveDuration(int? durationMinutes, String name) { } } +/// Top-level helper that performs the `_validateOptionalInterval` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. void _validateOptionalInterval({ required DateTime? start, required DateTime? end, diff --git a/packages/scheduler_core/lib/src/models/enums/effort/difficulty_level.dart b/packages/scheduler_core/lib/src/models/enums/effort/difficulty_level.dart index 9d7da9d..7dc5035 100644 --- a/packages/scheduler_core/lib/src/models/enums/effort/difficulty_level.dart +++ b/packages/scheduler_core/lib/src/models/enums/effort/difficulty_level.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../models.dart'; /// Expected effort or activation difficulty for a task. diff --git a/packages/scheduler_core/lib/src/models/enums/effort/reward_level.dart b/packages/scheduler_core/lib/src/models/enums/effort/reward_level.dart index 196375a..8856091 100644 --- a/packages/scheduler_core/lib/src/models/enums/effort/reward_level.dart +++ b/packages/scheduler_core/lib/src/models/enums/effort/reward_level.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../models.dart'; /// Expected reward or payoff from completing a task. diff --git a/packages/scheduler_core/lib/src/models/enums/planning/backlog_tag.dart b/packages/scheduler_core/lib/src/models/enums/planning/backlog_tag.dart index a4a6472..f6e4242 100644 --- a/packages/scheduler_core/lib/src/models/enums/planning/backlog_tag.dart +++ b/packages/scheduler_core/lib/src/models/enums/planning/backlog_tag.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../models.dart'; /// Lightweight backlog-only metadata. diff --git a/packages/scheduler_core/lib/src/models/enums/planning/priority_level.dart b/packages/scheduler_core/lib/src/models/enums/planning/priority_level.dart index bdd459d..bb03c2c 100644 --- a/packages/scheduler_core/lib/src/models/enums/planning/priority_level.dart +++ b/packages/scheduler_core/lib/src/models/enums/planning/priority_level.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../models.dart'; /// User-facing importance level. diff --git a/packages/scheduler_core/lib/src/models/enums/planning/reminder_profile.dart b/packages/scheduler_core/lib/src/models/enums/planning/reminder_profile.dart index 8198007..b53a079 100644 --- a/packages/scheduler_core/lib/src/models/enums/planning/reminder_profile.dart +++ b/packages/scheduler_core/lib/src/models/enums/planning/reminder_profile.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../models.dart'; /// Reminder intensity preference. diff --git a/packages/scheduler_core/lib/src/models/enums/tasks/task_status.dart b/packages/scheduler_core/lib/src/models/enums/tasks/task_status.dart index 3aa6321..72b3b50 100644 --- a/packages/scheduler_core/lib/src/models/enums/tasks/task_status.dart +++ b/packages/scheduler_core/lib/src/models/enums/tasks/task_status.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../models.dart'; /// Current lifecycle state of a task. diff --git a/packages/scheduler_core/lib/src/models/enums/tasks/task_type.dart b/packages/scheduler_core/lib/src/models/enums/tasks/task_type.dart index d38017a..ed2663e 100644 --- a/packages/scheduler_core/lib/src/models/enums/tasks/task_type.dart +++ b/packages/scheduler_core/lib/src/models/enums/tasks/task_type.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../models.dart'; /// Scheduling behavior category. diff --git a/packages/scheduler_core/lib/src/models/validation/domain_validation_code.dart b/packages/scheduler_core/lib/src/models/validation/domain_validation_code.dart index ee0b591..b912cb2 100644 --- a/packages/scheduler_core/lib/src/models/validation/domain_validation_code.dart +++ b/packages/scheduler_core/lib/src/models/validation/domain_validation_code.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../models.dart'; /// Stable validation failure categories for domain model boundaries. @@ -6,26 +9,91 @@ part of '../../models.dart'; /// explanatory messages may change, but these enum values are part of the V1 /// backend contract. enum DomainValidationCode { + /// Selects the `blankStableId` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. blankStableId, + + /// Selects the `blankTitle` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. blankTitle, + + /// Selects the `blankProjectId` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. blankProjectId, + + /// Selects the `blankName` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. blankName, + + /// Selects the `blankColorKey` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. blankColorKey, + + /// Selects the `blankParentTaskId` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. blankParentTaskId, + + /// Selects the `selfParent` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. selfParent, + + /// Selects the `nonPositiveDuration` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. nonPositiveDuration, + + /// Selects the `partialScheduledInterval` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. partialScheduledInterval, + + /// Selects the `invalidScheduledInterval` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidScheduledInterval, + + /// Selects the `partialActualInterval` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. partialActualInterval, + + /// Selects the `invalidActualInterval` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidActualInterval, + + /// Selects the `invalidTimeInterval` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidTimeInterval, + + /// Selects the `invalidSchedulingWindow` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidSchedulingWindow, + + /// Selects the `invalidCivilDate` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidCivilDate, + + /// Selects the `invalidClockTime` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidClockTime, + + /// Selects the `blankTimeZoneId` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. blankTimeZoneId, + + /// Selects the `nonexistentLocalTime` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. nonexistentLocalTime, + + /// Selects the `ambiguousLocalTime` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. ambiguousLocalTime, + + /// Selects the `emptyRecurrence` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. emptyRecurrence, + + /// Selects the `invalidLockedBlock` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidLockedBlock, + + /// Selects the `invalidLockedOverride` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidLockedOverride, } diff --git a/packages/scheduler_core/lib/src/models/validation/domain_validation_exception.dart b/packages/scheduler_core/lib/src/models/validation/domain_validation_exception.dart index 1d7f6ef..f710461 100644 --- a/packages/scheduler_core/lib/src/models/validation/domain_validation_exception.dart +++ b/packages/scheduler_core/lib/src/models/validation/domain_validation_exception.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../models.dart'; /// Typed validation error thrown by domain model constructors. class DomainValidationException extends ArgumentError { + /// Creates a `DomainValidationException` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. DomainValidationException({ required this.code, required Object? invalidValue, diff --git a/packages/scheduler_core/lib/src/occupancy_policy.dart b/packages/scheduler_core/lib/src/occupancy_policy.dart index 523ee56..4779f97 100644 --- a/packages/scheduler_core/lib/src/occupancy_policy.dart +++ b/packages/scheduler_core/lib/src/occupancy_policy.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Occupancy Policy behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/occupancy_policy/occupancy_category.dart b/packages/scheduler_core/lib/src/occupancy_policy/occupancy_category.dart index ec69b2f..ec871dc 100644 --- a/packages/scheduler_core/lib/src/occupancy_policy/occupancy_category.dart +++ b/packages/scheduler_core/lib/src/occupancy_policy/occupancy_category.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../occupancy_policy.dart'; /// Scheduling-facing occupancy category for one task or external interval. diff --git a/packages/scheduler_core/lib/src/occupancy_policy/occupancy_entry.dart b/packages/scheduler_core/lib/src/occupancy_policy/occupancy_entry.dart index 5d67009..9bded27 100644 --- a/packages/scheduler_core/lib/src/occupancy_policy/occupancy_entry.dart +++ b/packages/scheduler_core/lib/src/occupancy_policy/occupancy_entry.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../occupancy_policy.dart'; /// Policy classification for one task or external interval. class OccupancyEntry { + /// Creates a `OccupancyEntry` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const OccupancyEntry({ required this.source, required this.category, diff --git a/packages/scheduler_core/lib/src/occupancy_policy/occupancy_policy.dart b/packages/scheduler_core/lib/src/occupancy_policy/occupancy_policy.dart index d94798e..1b5975e 100644 --- a/packages/scheduler_core/lib/src/occupancy_policy/occupancy_policy.dart +++ b/packages/scheduler_core/lib/src/occupancy_policy/occupancy_policy.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../occupancy_policy.dart'; /// UI-independent V1 occupancy policy. class OccupancyPolicy { + /// Creates a `OccupancyPolicy` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const OccupancyPolicy(); /// Classify all task and external interval inputs for a scheduling operation. @@ -135,6 +140,8 @@ class OccupancyPolicy { ); } + /// Runs the `_taskEntry` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. OccupancyEntry _taskEntry({ required Task task, required OccupancyCategory category, @@ -148,6 +155,8 @@ class OccupancyPolicy { ); } + /// Runs the `_entry` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. OccupancyEntry _entry({ required OccupancySource source, required OccupancyCategory category, @@ -220,12 +229,16 @@ class OccupancyPolicy { } } +/// Top-level helper that performs the `_isNonOccupyingStatus` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _isNonOccupyingStatus(TaskStatus status) { return status == TaskStatus.backlog || status == TaskStatus.cancelled || status == TaskStatus.noLongerRelevant; } +/// Top-level helper that performs the `_scheduledIntervalFor` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TimeInterval? _scheduledIntervalFor(Task task) { final start = task.scheduledStart; final end = task.scheduledEnd; @@ -236,6 +249,8 @@ TimeInterval? _scheduledIntervalFor(Task task) { return TimeInterval(start: start, end: end, label: task.id); } +/// Top-level helper that performs the `_actualIntervalFor` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TimeInterval? _actualIntervalFor(Task task) { final start = task.actualStart; final end = task.actualEnd; diff --git a/packages/scheduler_core/lib/src/occupancy_policy/occupancy_source.dart b/packages/scheduler_core/lib/src/occupancy_policy/occupancy_source.dart index cf86143..b31ba0c 100644 --- a/packages/scheduler_core/lib/src/occupancy_policy/occupancy_source.dart +++ b/packages/scheduler_core/lib/src/occupancy_policy/occupancy_source.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../occupancy_policy.dart'; /// Where an occupancy entry came from. diff --git a/packages/scheduler_core/lib/src/persistence_contract.dart b/packages/scheduler_core/lib/src/persistence_contract.dart index c8a1e08..2971e52 100644 --- a/packages/scheduler_core/lib/src/persistence_contract.dart +++ b/packages/scheduler_core/lib/src/persistence_contract.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Persistence Contract behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/persistence_contract/collections/persistence_collections.dart b/packages/scheduler_core/lib/src/persistence_contract/collections/persistence_collections.dart index d6898e3..79f24ec 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/collections/persistence_collections.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/collections/persistence_collections.dart @@ -1,18 +1,52 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_contract.dart'; /// Stable V1 logical collection names for persistence adapters. abstract final class PersistenceCollections { + /// Shared constant value for `tasks`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const tasks = 'tasks'; + + /// Shared constant value for `projects`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const projects = 'projects'; + + /// Shared constant value for `projectStatistics`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const projectStatistics = 'project_statistics'; + + /// Shared constant value for `lockedBlocks`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const lockedBlocks = 'locked_blocks'; + + /// Shared constant value for `lockedOverrides`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const lockedOverrides = 'locked_overrides'; + + /// Shared constant value for `taskActivities`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const taskActivities = 'task_activities'; + + /// Shared constant value for `ownerSettings`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const ownerSettings = 'owner_settings'; + + /// Shared constant value for `noticeAcknowledgements`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const noticeAcknowledgements = 'notice_acknowledgements'; + + /// Shared constant value for `applicationOperations`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const applicationOperations = 'application_operations'; + + /// Shared constant value for `schedulingSnapshots`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const schedulingSnapshots = 'scheduling_snapshots'; + /// Shared constant value for `authoritative`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const authoritative = { tasks, projects, @@ -22,6 +56,8 @@ abstract final class PersistenceCollections { ownerSettings, }; + /// Shared constant value for `internalRetained`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const internalRetained = { taskActivities, noticeAcknowledgements, diff --git a/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_civil_date_convention.dart b/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_civil_date_convention.dart index 08ebf34..e238af5 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_civil_date_convention.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_civil_date_convention.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_contract.dart'; /// Civil-date storage convention for future document persistence. diff --git a/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_date_time_convention.dart b/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_date_time_convention.dart index 1161b52..4362ae8 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_date_time_convention.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_date_time_convention.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_contract.dart'; /// DateTime storage convention for future document persistence. diff --git a/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_enum_name.dart b/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_enum_name.dart index 26b6e23..21f44d3 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_enum_name.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_enum_name.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_contract.dart'; /// Legacy enum-name extension retained for older callers. diff --git a/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_wall_time_convention.dart b/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_wall_time_convention.dart index 9c52cb6..8b4034e 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_wall_time_convention.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/conventions/persistence_wall_time_convention.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_contract.dart'; /// Wall-time storage convention for future document persistence. diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/application/application_operation_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/application/application_operation_document_fields.dart index 14fa7d3..48310e9 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/application/application_operation_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/application/application_operation_document_fields.dart @@ -1,17 +1,48 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for idempotent operation records. abstract final class ApplicationOperationDocumentFields { + /// Stable storage field for `schemaVersion`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const schemaVersion = DocumentFields.schemaVersion; + + /// Stable storage field for `id`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const id = DocumentFields.id; + + /// Stable storage field for `ownerId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const ownerId = DocumentFields.ownerId; + + /// Stable storage field for `revision`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const revision = DocumentFields.revision; + + /// Stable storage field for `createdAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const createdAt = DocumentFields.createdAt; + + /// Stable storage field for `updatedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const updatedAt = DocumentFields.updatedAt; + + /// Stable storage field for `operationId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const operationId = 'operationId'; + + /// Stable storage field for `operationName`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const operationName = 'operationName'; + + /// Stable storage field for `committedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const committedAt = 'committedAt'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { ...DocumentFields.common, operationId, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/application/backlog_staleness_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/application/backlog_staleness_document_fields.dart index b70ba41..b72f3f4 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/application/backlog_staleness_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/application/backlog_staleness_document_fields.dart @@ -1,10 +1,20 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for backlog staleness settings. abstract final class BacklogStalenessDocumentFields { + /// Stable storage field for `greenMaxAgeDays`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const greenMaxAgeDays = 'greenMaxAgeDays'; + + /// Stable storage field for `blueMaxAgeDays`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const blueMaxAgeDays = 'blueMaxAgeDays'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { greenMaxAgeDays, blueMaxAgeDays, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/application/notice_acknowledgement_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/application/notice_acknowledgement_document_fields.dart index a11de62..004c68d 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/application/notice_acknowledgement_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/application/notice_acknowledgement_document_fields.dart @@ -1,16 +1,44 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for notice acknowledgement documents. abstract final class NoticeAcknowledgementDocumentFields { + /// Stable storage field for `schemaVersion`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const schemaVersion = DocumentFields.schemaVersion; + + /// Stable storage field for `id`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const id = DocumentFields.id; + + /// Stable storage field for `ownerId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const ownerId = DocumentFields.ownerId; + + /// Stable storage field for `revision`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const revision = DocumentFields.revision; + + /// Stable storage field for `createdAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const createdAt = DocumentFields.createdAt; + + /// Stable storage field for `updatedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const updatedAt = DocumentFields.updatedAt; + + /// Stable storage field for `noticeId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const noticeId = 'noticeId'; + + /// Stable storage field for `acknowledgedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const acknowledgedAt = 'acknowledgedAt'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { ...DocumentFields.common, noticeId, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/application/owner_settings_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/application/owner_settings_document_fields.dart index c069f19..4ff8bce 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/application/owner_settings_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/application/owner_settings_document_fields.dart @@ -1,19 +1,56 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [OwnerSettings] documents. abstract final class OwnerSettingsDocumentFields { + /// Stable storage field for `schemaVersion`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const schemaVersion = DocumentFields.schemaVersion; + + /// Stable storage field for `id`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const id = DocumentFields.id; + + /// Stable storage field for `ownerId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const ownerId = DocumentFields.ownerId; + + /// Stable storage field for `revision`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const revision = DocumentFields.revision; + + /// Stable storage field for `createdAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const createdAt = DocumentFields.createdAt; + + /// Stable storage field for `updatedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const updatedAt = DocumentFields.updatedAt; + + /// Stable storage field for `timeZoneId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const timeZoneId = 'timeZoneId'; + + /// Stable storage field for `dayStart`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const dayStart = 'dayStart'; + + /// Stable storage field for `dayEnd`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const dayEnd = 'dayEnd'; + + /// Stable storage field for `compactModeEnabled`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const compactModeEnabled = 'compactModeEnabled'; + + /// Stable storage field for `backlogStaleness`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const backlogStaleness = 'backlogStaleness'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { ...DocumentFields.common, timeZoneId, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/core/document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/core/document_fields.dart index 071a62b..1de4c5f 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/core/document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/core/document_fields.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Shared V1 document field names. @@ -20,6 +23,8 @@ abstract final class DocumentFields { /// Last update instant. static const updatedAt = 'updatedAt'; + /// Stable storage field for `common`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const common = { schemaVersion, id, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/locked_time/locked_block_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/locked_time/locked_block_document_fields.dart index 7374f63..155e259 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/locked_time/locked_block_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/locked_time/locked_block_document_fields.dart @@ -1,22 +1,68 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [LockedBlock] documents. abstract final class LockedBlockDocumentFields { + /// Stable storage field for `schemaVersion`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const schemaVersion = DocumentFields.schemaVersion; + + /// Stable storage field for `id`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const id = DocumentFields.id; + + /// Stable storage field for `ownerId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const ownerId = DocumentFields.ownerId; + + /// Stable storage field for `revision`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const revision = DocumentFields.revision; + + /// Stable storage field for `name`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const name = 'name'; + + /// Stable storage field for `startTime`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const startTime = 'startTime'; + + /// Stable storage field for `endTime`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const endTime = 'endTime'; + + /// Stable storage field for `date`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const date = 'date'; + + /// Stable storage field for `recurrence`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const recurrence = 'recurrence'; + + /// Stable storage field for `hiddenByDefault`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const hiddenByDefault = 'hiddenByDefault'; + + /// Stable storage field for `projectId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const projectId = 'projectId'; + + /// Stable storage field for `createdAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const createdAt = DocumentFields.createdAt; + + /// Stable storage field for `updatedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const updatedAt = DocumentFields.updatedAt; + + /// Stable storage field for `archivedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const archivedAt = 'archivedAt'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { ...DocumentFields.common, name, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/locked_time/locked_block_override_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/locked_time/locked_block_override_document_fields.dart index fb32362..5a6f86c 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/locked_time/locked_block_override_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/locked_time/locked_block_override_document_fields.dart @@ -1,22 +1,68 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [LockedBlockOverride] documents. abstract final class LockedBlockOverrideDocumentFields { + /// Stable storage field for `schemaVersion`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const schemaVersion = DocumentFields.schemaVersion; + + /// Stable storage field for `id`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const id = DocumentFields.id; + + /// Stable storage field for `ownerId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const ownerId = DocumentFields.ownerId; + + /// Stable storage field for `revision`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const revision = DocumentFields.revision; + + /// Stable storage field for `lockedBlockId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const lockedBlockId = 'lockedBlockId'; + + /// Stable storage field for `date`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const date = 'date'; + + /// Stable storage field for `type`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const type = 'type'; + + /// Stable storage field for `name`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const name = 'name'; + + /// Stable storage field for `startTime`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const startTime = 'startTime'; + + /// Stable storage field for `endTime`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const endTime = 'endTime'; + + /// Stable storage field for `hiddenByDefault`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const hiddenByDefault = 'hiddenByDefault'; + + /// Stable storage field for `projectId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const projectId = 'projectId'; + + /// Stable storage field for `createdAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const createdAt = DocumentFields.createdAt; + + /// Stable storage field for `updatedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const updatedAt = DocumentFields.updatedAt; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { ...DocumentFields.common, lockedBlockId, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/locked_time/locked_block_recurrence_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/locked_time/locked_block_recurrence_document_fields.dart index 6be9001..61f1ada 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/locked_time/locked_block_recurrence_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/locked_time/locked_block_recurrence_document_fields.dart @@ -1,10 +1,20 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [LockedBlockRecurrence] embedded documents. abstract final class LockedBlockRecurrenceDocumentFields { + /// Stable storage field for `type`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const type = 'type'; + + /// Stable storage field for `weekdays`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const weekdays = 'weekdays'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { type, weekdays, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/projects/project_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/projects/project_document_fields.dart index 92d3c34..62bb015 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/projects/project_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/projects/project_document_fields.dart @@ -1,22 +1,68 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [ProjectProfile] documents. abstract final class ProjectDocumentFields { + /// Stable storage field for `schemaVersion`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const schemaVersion = DocumentFields.schemaVersion; + + /// Stable storage field for `id`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const id = DocumentFields.id; + + /// Stable storage field for `ownerId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const ownerId = DocumentFields.ownerId; + + /// Stable storage field for `revision`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const revision = DocumentFields.revision; + + /// Stable storage field for `createdAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const createdAt = DocumentFields.createdAt; + + /// Stable storage field for `updatedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const updatedAt = DocumentFields.updatedAt; + + /// Stable storage field for `name`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const name = 'name'; + + /// Stable storage field for `colorKey`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const colorKey = 'colorKey'; + + /// Stable storage field for `defaultPriority`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const defaultPriority = 'defaultPriority'; + + /// Stable storage field for `defaultReward`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const defaultReward = 'defaultReward'; + + /// Stable storage field for `defaultDifficulty`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const defaultDifficulty = 'defaultDifficulty'; + + /// Stable storage field for `defaultReminderProfile`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const defaultReminderProfile = 'defaultReminderProfile'; + + /// Stable storage field for `defaultDurationMinutes`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const defaultDurationMinutes = 'defaultDurationMinutes'; + + /// Stable storage field for `archivedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const archivedAt = 'archivedAt'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { ...DocumentFields.common, name, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/projects/project_statistics_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/projects/project_statistics_document_fields.dart index ee80025..66d55b4 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/projects/project_statistics_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/projects/project_statistics_document_fields.dart @@ -1,24 +1,76 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [ProjectStatistics] documents. abstract final class ProjectStatisticsDocumentFields { + /// Stable storage field for `schemaVersion`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const schemaVersion = DocumentFields.schemaVersion; + + /// Stable storage field for `id`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const id = DocumentFields.id; + + /// Stable storage field for `ownerId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const ownerId = DocumentFields.ownerId; + + /// Stable storage field for `revision`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const revision = DocumentFields.revision; + + /// Stable storage field for `createdAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const createdAt = DocumentFields.createdAt; + + /// Stable storage field for `updatedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const updatedAt = DocumentFields.updatedAt; + + /// Stable storage field for `projectId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const projectId = 'projectId'; + + /// Stable storage field for `completedTaskCount`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const completedTaskCount = 'completedTaskCount'; + + /// Stable storage field for `durationMinuteCounts`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const durationMinuteCounts = 'durationMinuteCounts'; + + /// Stable storage field for `completionTimeBucketCounts`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const completionTimeBucketCounts = 'completionTimeBucketCounts'; + + /// Stable storage field for `totalPushesBeforeCompletion`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const totalPushesBeforeCompletion = 'totalPushesBeforeCompletion'; + + /// Stable storage field for `completedAfterPushCount`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const completedAfterPushCount = 'completedAfterPushCount'; + + /// Stable storage field for `rewardCounts`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const rewardCounts = 'rewardCounts'; + + /// Stable storage field for `difficultyCounts`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const difficultyCounts = 'difficultyCounts'; + + /// Stable storage field for `reminderProfileCounts`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const reminderProfileCounts = 'reminderProfileCounts'; + + /// Stable storage field for `appliedActivityIds`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const appliedActivityIds = 'appliedActivityIds'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { ...DocumentFields.common, projectId, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_change_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_change_document_fields.dart index 09e6f11..8340294 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_change_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_change_document_fields.dart @@ -1,13 +1,32 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [SchedulingChange] embedded documents. abstract final class SchedulingChangeDocumentFields { + /// Stable storage field for `taskId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const taskId = 'taskId'; + + /// Stable storage field for `previousStart`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const previousStart = 'previousStart'; + + /// Stable storage field for `previousEnd`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const previousEnd = 'previousEnd'; + + /// Stable storage field for `nextStart`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const nextStart = 'nextStart'; + + /// Stable storage field for `nextEnd`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const nextEnd = 'nextEnd'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { taskId, previousStart, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_notice_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_notice_document_fields.dart index 7e4661b..2186fc5 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_notice_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_notice_document_fields.dart @@ -1,15 +1,40 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [SchedulingNotice] embedded documents. abstract final class SchedulingNoticeDocumentFields { + /// Stable storage field for `message`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const message = 'message'; + + /// Stable storage field for `type`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const type = 'type'; + + /// Stable storage field for `taskId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const taskId = 'taskId'; + + /// Stable storage field for `issueCode`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const issueCode = 'issueCode'; + + /// Stable storage field for `movementCode`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const movementCode = 'movementCode'; + + /// Stable storage field for `conflictCode`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const conflictCode = 'conflictCode'; + + /// Stable storage field for `parameters`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const parameters = 'parameters'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { message, type, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_overlap_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_overlap_document_fields.dart index 9263a60..e681ff7 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_overlap_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_overlap_document_fields.dart @@ -1,11 +1,24 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [SchedulingOverlap] embedded documents. abstract final class SchedulingOverlapDocumentFields { + /// Stable storage field for `taskId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const taskId = 'taskId'; + + /// Stable storage field for `taskInterval`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const taskInterval = 'taskInterval'; + + /// Stable storage field for `blockedInterval`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const blockedInterval = 'blockedInterval'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { taskId, taskInterval, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_snapshot_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_snapshot_document_fields.dart index f7e3b44..4fd0a13 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_snapshot_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_snapshot_document_fields.dart @@ -1,27 +1,88 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [SchedulingStateSnapshot] documents. abstract final class SchedulingSnapshotDocumentFields { + /// Stable storage field for `schemaVersion`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const schemaVersion = DocumentFields.schemaVersion; + + /// Stable storage field for `id`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const id = DocumentFields.id; + + /// Stable storage field for `ownerId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const ownerId = DocumentFields.ownerId; + + /// Stable storage field for `revision`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const revision = DocumentFields.revision; + + /// Stable storage field for `createdAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const createdAt = DocumentFields.createdAt; + + /// Stable storage field for `updatedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const updatedAt = DocumentFields.updatedAt; + + /// Stable storage field for `capturedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const capturedAt = 'capturedAt'; + + /// Stable storage field for `sourceDate`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const sourceDate = 'sourceDate'; + + /// Stable storage field for `targetDate`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const targetDate = 'targetDate'; + + /// Stable storage field for `window`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const window = 'window'; + + /// Stable storage field for `tasks`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const tasks = 'tasks'; + + /// Stable storage field for `lockedIntervals`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const lockedIntervals = 'lockedIntervals'; + + /// Stable storage field for `requiredVisibleIntervals`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const requiredVisibleIntervals = 'requiredVisibleIntervals'; + + /// Stable storage field for `notices`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const notices = 'notices'; + + /// Stable storage field for `changes`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const changes = 'changes'; + + /// Stable storage field for `overlaps`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const overlaps = 'overlaps'; + + /// Stable storage field for `operationName`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const operationName = 'operationName'; + + /// Stable storage field for `retentionExpiresAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const retentionExpiresAt = 'retentionExpiresAt'; + + /// Stable storage field for `truncated`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const truncated = 'truncated'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { ...DocumentFields.common, capturedAt, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_window_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_window_document_fields.dart index 54449b4..533495b 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_window_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/scheduling/scheduling_window_document_fields.dart @@ -1,10 +1,20 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [SchedulingWindow] embedded documents. abstract final class SchedulingWindowDocumentFields { + /// Stable storage field for `start`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const start = 'start'; + + /// Stable storage field for `end`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const end = 'end'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { start, end, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/tasks/task_activity_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/tasks/task_activity_document_fields.dart index 3c17092..f4381a6 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/tasks/task_activity_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/tasks/task_activity_document_fields.dart @@ -1,20 +1,60 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for internal [TaskActivity] documents. abstract final class TaskActivityDocumentFields { + /// Stable storage field for `schemaVersion`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const schemaVersion = DocumentFields.schemaVersion; + + /// Stable storage field for `id`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const id = DocumentFields.id; + + /// Stable storage field for `ownerId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const ownerId = DocumentFields.ownerId; + + /// Stable storage field for `revision`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const revision = DocumentFields.revision; + + /// Stable storage field for `createdAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const createdAt = DocumentFields.createdAt; + + /// Stable storage field for `updatedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const updatedAt = DocumentFields.updatedAt; + + /// Stable storage field for `operationId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const operationId = 'operationId'; + + /// Stable storage field for `code`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const code = 'code'; + + /// Stable storage field for `taskId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const taskId = 'taskId'; + + /// Stable storage field for `projectId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const projectId = 'projectId'; + + /// Stable storage field for `occurredAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const occurredAt = 'occurredAt'; + + /// Stable storage field for `metadata`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const metadata = 'metadata'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { ...DocumentFields.common, operationId, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/tasks/task_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/tasks/task_document_fields.dart index 1005526..dc76f03 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/tasks/task_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/tasks/task_document_fields.dart @@ -1,33 +1,112 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [Task] documents. abstract final class TaskDocumentFields { + /// Stable storage field for `schemaVersion`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const schemaVersion = DocumentFields.schemaVersion; + + /// Stable storage field for `id`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const id = DocumentFields.id; + + /// Stable storage field for `ownerId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const ownerId = DocumentFields.ownerId; + + /// Stable storage field for `revision`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const revision = DocumentFields.revision; + + /// Stable storage field for `title`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const title = 'title'; + + /// Stable storage field for `projectId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const projectId = 'projectId'; + + /// Stable storage field for `type`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const type = 'type'; + + /// Stable storage field for `status`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const status = 'status'; + + /// Stable storage field for `priority`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const priority = 'priority'; + + /// Stable storage field for `reward`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const reward = 'reward'; + + /// Stable storage field for `difficulty`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const difficulty = 'difficulty'; + + /// Stable storage field for `durationMinutes`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const durationMinutes = 'durationMinutes'; + + /// Stable storage field for `scheduledStart`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const scheduledStart = 'scheduledStart'; + + /// Stable storage field for `scheduledEnd`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const scheduledEnd = 'scheduledEnd'; + + /// Stable storage field for `actualStart`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const actualStart = 'actualStart'; + + /// Stable storage field for `actualEnd`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const actualEnd = 'actualEnd'; + + /// Stable storage field for `completedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const completedAt = 'completedAt'; + + /// Stable storage field for `parentTaskId`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const parentTaskId = 'parentTaskId'; + + /// Stable storage field for `backlogTags`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const backlogTags = 'backlogTags'; + + /// Stable storage field for `reminderOverride`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const reminderOverride = 'reminderOverride'; + + /// Stable storage field for `createdAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const createdAt = DocumentFields.createdAt; + + /// Stable storage field for `updatedAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const updatedAt = DocumentFields.updatedAt; + + /// Stable storage field for `stats`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const stats = 'stats'; + + /// Stable storage field for `backlogEnteredAt`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const backlogEnteredAt = 'backlogEnteredAt'; + + /// Stable storage field for `backlogEnteredAtProvenance`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const backlogEnteredAtProvenance = 'backlogEnteredAtProvenance'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { ...DocumentFields.common, title, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/tasks/task_statistics_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/tasks/task_statistics_document_fields.dart index be7f4f1..649d8fa 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/tasks/task_statistics_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/tasks/task_statistics_document_fields.dart @@ -1,23 +1,66 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [TaskStatistics] embedded documents. abstract final class TaskStatisticsDocumentFields { + /// Stable storage field for `skippedDuringBurnoutCount`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const skippedDuringBurnoutCount = 'skippedDuringBurnoutCount'; + + /// Stable storage field for `manuallyPushedCount`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const manuallyPushedCount = 'manuallyPushedCount'; + + /// Stable storage field for `autoPushedCount`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const autoPushedCount = 'autoPushedCount'; + + /// Stable storage field for `movedToBacklogCount`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const movedToBacklogCount = 'movedToBacklogCount'; + + /// Stable storage field for `restoredFromBacklogCount`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const restoredFromBacklogCount = 'restoredFromBacklogCount'; + + /// Stable storage field for `missedCount`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const missedCount = 'missedCount'; + + /// Stable storage field for `cancelledCount`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const cancelledCount = 'cancelledCount'; + + /// Stable storage field for `completedLateCount`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const completedLateCount = 'completedLateCount'; + + /// Stable storage field for `completedDuringLockedHoursCount`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const completedDuringLockedHoursCount = 'completedDuringLockedHoursCount'; + + /// Stable storage field for `completedDuringLockedHoursMinutes`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const completedDuringLockedHoursMinutes = 'completedDuringLockedHoursMinutes'; + + /// Stable storage field for `completedAfterShieldCount`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const completedAfterShieldCount = 'completedAfterShieldCount'; + + /// Stable storage field for `completedAfterPushCount`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const completedAfterPushCount = 'completedAfterPushCount'; + + /// Stable storage field for `totalPushesBeforeCompletion`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const totalPushesBeforeCompletion = 'totalPushesBeforeCompletion'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { skippedDuringBurnoutCount, manuallyPushedCount, diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/time/clock_time_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/time/clock_time_document_fields.dart index 24cfdd8..bfa044a 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/time/clock_time_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/time/clock_time_document_fields.dart @@ -1,9 +1,16 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [ClockTime] embedded documents. abstract final class ClockTimeDocumentFields { + /// Stable storage field for `value`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const value = 'value'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { value, }; diff --git a/packages/scheduler_core/lib/src/persistence_contract/fields/time/time_interval_document_fields.dart b/packages/scheduler_core/lib/src/persistence_contract/fields/time/time_interval_document_fields.dart index 3801ffc..5e87870 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/fields/time/time_interval_document_fields.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/fields/time/time_interval_document_fields.dart @@ -1,11 +1,24 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence_contract.dart'; /// Document field names for [TimeInterval] embedded documents. abstract final class TimeIntervalDocumentFields { + /// Stable storage field for `start`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const start = 'start'; + + /// Stable storage field for `end`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const end = 'end'; + + /// Stable storage field for `label`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const label = 'label'; + /// Stable storage field for `all`. + /// Keeping the key in one documented constant protects repository adapters, migrations, and tests from drifting string literals. static const all = { start, end, diff --git a/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_catalog.dart b/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_catalog.dart index 98cf617..d961cb1 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_catalog.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_catalog.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_contract.dart'; /// Required V1 index plan. abstract final class PersistenceIndexCatalog { + /// Shared constant value for `all`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const all = [ PersistenceIndexSpec( name: 'tasks_owner_id_unique', @@ -292,6 +297,8 @@ abstract final class PersistenceIndexCatalog { ), ]; + /// Returns the derived `supportedQueries` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. static Set get supportedQueries { return { for (final spec in all) ...spec.supportsQueries, diff --git a/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_direction.dart b/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_direction.dart index 1eec613..43edde9 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_direction.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_direction.dart @@ -1,7 +1,15 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_contract.dart'; /// Sort direction in an adapter-neutral index specification. enum PersistenceIndexDirection { + /// Selects the `ascending` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. ascending, + + /// Selects the `descending` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. descending, } diff --git a/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_field.dart b/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_field.dart index 03a2c49..6e69031 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_field.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_field.dart @@ -1,12 +1,22 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_contract.dart'; /// One field in a declarative index key. class PersistenceIndexField { + /// Creates a `PersistenceIndexField` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const PersistenceIndexField( this.fieldName, { this.direction = PersistenceIndexDirection.ascending, }); + /// Stores the `fieldName` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String fieldName; + + /// Stores the `direction` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final PersistenceIndexDirection direction; } diff --git a/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_spec.dart b/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_spec.dart index 791fc0f..525b807 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_spec.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/indexes/persistence_index_spec.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_contract.dart'; /// A stable index plan future adapters can translate to driver-specific calls. class PersistenceIndexSpec { + /// Creates a `PersistenceIndexSpec` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const PersistenceIndexSpec({ required this.name, required this.collection, @@ -11,10 +16,27 @@ class PersistenceIndexSpec { this.supportsQueries = const {}, }); + /// Stores the `name` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String name; + + /// Stores the `collection` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String collection; + + /// Stores the `keys` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final List keys; + + /// Stores the `unique` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool unique; + + /// Stores the `partialFilterFields` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Set partialFilterFields; + + /// Stores the `supportsQueries` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Set supportsQueries; } diff --git a/packages/scheduler_core/lib/src/persistence_contract/indexes/repository_query_names.dart b/packages/scheduler_core/lib/src/persistence_contract/indexes/repository_query_names.dart index 704b128..305b0ab 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/indexes/repository_query_names.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/indexes/repository_query_names.dart @@ -1,37 +1,111 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_contract.dart'; /// Stable repository query identifiers for index coverage tests. abstract final class RepositoryQueryNames { + /// Shared constant value for `taskById`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const taskById = 'TaskRepository.findById'; + + /// Shared constant value for `taskByOwner`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const taskByOwner = 'TaskRepository.findByOwner'; + + /// Shared constant value for `taskByStatus`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const taskByStatus = 'TaskRepository.findByStatus'; + + /// Shared constant value for `taskByProject`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const taskByProject = 'TaskRepository.findByProjectId'; + + /// Shared constant value for `taskByParent`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const taskByParent = 'TaskRepository.findByParentTaskId'; + + /// Shared constant value for `taskBacklogCandidates`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const taskBacklogCandidates = 'TaskRepository.findBacklogCandidates'; + + /// Shared constant value for `taskScheduledWindow`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const taskScheduledWindow = 'TaskRepository.findScheduledInWindowForOwner'; + + /// Shared constant value for `taskLocalDay`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const taskLocalDay = 'TaskRepository.findForLocalDay'; + + /// Shared constant value for `projectByOwner`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const projectByOwner = 'ProjectRepository.findByOwner'; + + /// Shared constant value for `projectById`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const projectById = 'ProjectRepository.findById'; + + /// Shared constant value for `lockedBlockByOwner`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const lockedBlockByOwner = 'LockedBlockRepository.findBlocksByOwner'; + + /// Shared constant value for `lockedBlockById`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const lockedBlockById = 'LockedBlockRepository.findBlockById'; + + /// Shared constant value for `lockedOverrideByDate`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const lockedOverrideByDate = 'LockedBlockRepository.findOverridesForDate'; + + /// Shared constant value for `taskActivityByOwner`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const taskActivityByOwner = 'TaskActivityRepository.findByOwner'; + + /// Shared constant value for `taskActivityByOperation`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const taskActivityByOperation = 'TaskActivityRepository.findByOperationId'; + + /// Shared constant value for `taskActivityByTask`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const taskActivityByTask = 'TaskActivityRepository.findByTaskId'; + + /// Shared constant value for `taskActivityByProject`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const taskActivityByProject = 'TaskActivityRepository.findByProjectId'; + + /// Shared constant value for `projectStatisticsByProject`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const projectStatisticsByProject = 'ProjectStatisticsRepository.findByProjectId'; + + /// Shared constant value for `ownerSettingsByOwner`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const ownerSettingsByOwner = 'OwnerSettingsRepository.findByOwnerId'; + + /// Shared constant value for `noticeAcknowledgementByOwner`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const noticeAcknowledgementByOwner = 'NoticeAcknowledgementRepository.findByOwner'; + + /// Shared constant value for `noticeAcknowledgementById`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const noticeAcknowledgementById = 'NoticeAcknowledgementRepository.findById'; + + /// Shared constant value for `operationByIdempotencyKey`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const operationByIdempotencyKey = 'ApplicationOperationRepository.findByIdempotencyKey'; + + /// Shared constant value for `schedulingSnapshotById`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const schedulingSnapshotById = 'SchedulingSnapshotRepository.findById'; + + /// Shared constant value for `schedulingSnapshotWindow`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const schedulingSnapshotWindow = 'SchedulingSnapshotRepository.findInWindow'; } diff --git a/packages/scheduler_core/lib/src/persistence_contract/payloads/persistence_guard_result.dart b/packages/scheduler_core/lib/src/persistence_contract/payloads/persistence_guard_result.dart index f5f5522..b534fea 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/payloads/persistence_guard_result.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/payloads/persistence_guard_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_contract.dart'; /// Guard result for bounded document payload checks. class PersistenceGuardResult { + /// Creates a `PersistenceGuardResult._` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const PersistenceGuardResult._({ required this.isValid, this.fieldName, @@ -9,10 +14,14 @@ class PersistenceGuardResult { this.actual, }); + /// Creates a `PersistenceGuardResult.valid` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. factory PersistenceGuardResult.valid() { return const PersistenceGuardResult._(isValid: true); } + /// Creates a `PersistenceGuardResult.tooLarge` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. factory PersistenceGuardResult.tooLarge({ required String fieldName, required int limit, @@ -26,8 +35,19 @@ class PersistenceGuardResult { ); } + /// Stores the `isValid` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool isValid; + + /// Stores the `fieldName` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? fieldName; + + /// Stores the `limit` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int? limit; + + /// Stores the `actual` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int? actual; } diff --git a/packages/scheduler_core/lib/src/persistence_contract/payloads/persistence_payload_guard.dart b/packages/scheduler_core/lib/src/persistence_contract/payloads/persistence_payload_guard.dart index b001494..fadd3a4 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/payloads/persistence_payload_guard.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/payloads/persistence_payload_guard.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_contract.dart'; /// Pure guard helpers for bounded embedded document payloads. abstract final class PersistencePayloadGuard { + /// Performs the `mapEntries` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static PersistenceGuardResult mapEntries({ required String fieldName, required Map value, @@ -17,6 +22,8 @@ abstract final class PersistencePayloadGuard { return PersistenceGuardResult.valid(); } + /// Performs the `listLength` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. static PersistenceGuardResult listLength({ required String fieldName, required Iterable value, diff --git a/packages/scheduler_core/lib/src/persistence_contract/payloads/persistence_payload_limits.dart b/packages/scheduler_core/lib/src/persistence_contract/payloads/persistence_payload_limits.dart index ebde4b1..c737e2c 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/payloads/persistence_payload_limits.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/payloads/persistence_payload_limits.dart @@ -1,13 +1,39 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_contract.dart'; /// Bounded payload and retention policy for non-authoritative documents. abstract final class PersistencePayloadLimits { + /// Shared constant value for `maxTaskActivityMetadataEntries`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const maxTaskActivityMetadataEntries = 50; + + /// Shared constant value for `maxSchedulingSnapshotTasks`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const maxSchedulingSnapshotTasks = 250; + + /// Shared constant value for `maxSchedulingSnapshotNotices`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const maxSchedulingSnapshotNotices = 100; + + /// Shared constant value for `maxSchedulingSnapshotChanges`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const maxSchedulingSnapshotChanges = 250; + + /// Shared constant value for `maxAppliedActivityIds`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const maxAppliedActivityIds = 1000; + + /// Shared constant value for `taskActivityRetention`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const taskActivityRetention = Duration(days: 365); + + /// Shared constant value for `applicationOperationRetention`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const applicationOperationRetention = Duration(days: 90); + + /// Shared constant value for `schedulingSnapshotRetention`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const schedulingSnapshotRetention = Duration(days: 30); } diff --git a/packages/scheduler_core/lib/src/persistence_contract/persistence_document_field_sets.dart b/packages/scheduler_core/lib/src/persistence_contract/persistence_document_field_sets.dart index 37c66ce..5431251 100644 --- a/packages/scheduler_core/lib/src/persistence_contract/persistence_document_field_sets.dart +++ b/packages/scheduler_core/lib/src/persistence_contract/persistence_document_field_sets.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../persistence_contract.dart'; /// Every field-name set currently committed for future document mapping. abstract final class PersistenceDocumentFieldSets { + /// Shared constant value for `all`. + /// The constant gives this repeated scheduler or UI value one documented source of truth instead of scattering literals across call sites. static const all = >[ DocumentFields.common, TaskDocumentFields.all, diff --git a/packages/scheduler_core/lib/src/project_statistics.dart b/packages/scheduler_core/lib/src/project_statistics.dart index 99feacb..a7a0d9e 100644 --- a/packages/scheduler_core/lib/src/project_statistics.dart +++ b/packages/scheduler_core/lib/src/project_statistics.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Project Statistics behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/project_statistics/enums/project_completion_time_bucket.dart b/packages/scheduler_core/lib/src/project_statistics/enums/project_completion_time_bucket.dart index 507d733..614b812 100644 --- a/packages/scheduler_core/lib/src/project_statistics/enums/project_completion_time_bucket.dart +++ b/packages/scheduler_core/lib/src/project_statistics/enums/project_completion_time_bucket.dart @@ -1,10 +1,27 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../project_statistics.dart'; /// Coarse completion-time buckets used for learned project suggestions. enum ProjectCompletionTimeBucket { + /// Selects the `overnight` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. overnight, + + /// Selects the `morning` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. morning, + + /// Selects the `afternoon` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. afternoon, + + /// Selects the `evening` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. evening, + + /// Selects the `night` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. night, } diff --git a/packages/scheduler_core/lib/src/project_statistics/enums/project_suggestion_confidence.dart b/packages/scheduler_core/lib/src/project_statistics/enums/project_suggestion_confidence.dart index 7509041..38a036b 100644 --- a/packages/scheduler_core/lib/src/project_statistics/enums/project_suggestion_confidence.dart +++ b/packages/scheduler_core/lib/src/project_statistics/enums/project_suggestion_confidence.dart @@ -1,8 +1,19 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../project_statistics.dart'; /// How concentrated the supporting observations are for a suggestion. enum ProjectSuggestionConfidence { + /// Selects the `low` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. low, + + /// Selects the `medium` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. medium, + + /// Selects the `high` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. high, } diff --git a/packages/scheduler_core/lib/src/project_statistics/enums/project_suggestion_type.dart b/packages/scheduler_core/lib/src/project_statistics/enums/project_suggestion_type.dart index 9742545..5a1f59d 100644 --- a/packages/scheduler_core/lib/src/project_statistics/enums/project_suggestion_type.dart +++ b/packages/scheduler_core/lib/src/project_statistics/enums/project_suggestion_type.dart @@ -1,10 +1,27 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../project_statistics.dart'; /// Suggestion categories derived from project observations. enum ProjectSuggestionType { + /// Selects the `durationMinutes` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. durationMinutes, + + /// Selects the `completionTimeBucket` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. completionTimeBucket, + + /// Selects the `reward` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. reward, + + /// Selects the `difficulty` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. difficulty, + + /// Selects the `reminderProfile` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. reminderProfile, } diff --git a/packages/scheduler_core/lib/src/project_statistics/models/project_default_resolution.dart b/packages/scheduler_core/lib/src/project_statistics/models/project_default_resolution.dart index 8587d5d..3147ebd 100644 --- a/packages/scheduler_core/lib/src/project_statistics/models/project_default_resolution.dart +++ b/packages/scheduler_core/lib/src/project_statistics/models/project_default_resolution.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../project_statistics.dart'; /// Configured project defaults plus optional suggestions kept separate. class ProjectDefaultResolution { + /// Creates a `ProjectDefaultResolution` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ProjectDefaultResolution({ required this.project, required this.suggestions, @@ -13,9 +18,20 @@ class ProjectDefaultResolution { /// Optional learned suggestions that UI can present explicitly. final ProjectSuggestionSet suggestions; + /// Returns the derived `configuredDurationMinutes` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. int? get configuredDurationMinutes => project.defaultDurationMinutes; + + /// Returns the derived `configuredReward` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. RewardLevel get configuredReward => project.defaultReward; + + /// Returns the derived `configuredDifficulty` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DifficultyLevel get configuredDifficulty => project.defaultDifficulty; + + /// Returns the derived `configuredReminderProfile` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. ReminderProfile get configuredReminderProfile => project.defaultReminderProfile; } diff --git a/packages/scheduler_core/lib/src/project_statistics/models/project_statistics.dart b/packages/scheduler_core/lib/src/project_statistics/models/project_statistics.dart index 4203f6b..9e955fa 100644 --- a/packages/scheduler_core/lib/src/project_statistics/models/project_statistics.dart +++ b/packages/scheduler_core/lib/src/project_statistics/models/project_statistics.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../project_statistics.dart'; /// Immutable project-level observations used for future filtering and hints. class ProjectStatistics { + /// Creates a `ProjectStatistics` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. ProjectStatistics({ required String projectId, this.completedTaskCount = 0, diff --git a/packages/scheduler_core/lib/src/project_statistics/models/project_statistics_application_result.dart b/packages/scheduler_core/lib/src/project_statistics/models/project_statistics_application_result.dart index d6576e0..88d7573 100644 --- a/packages/scheduler_core/lib/src/project_statistics/models/project_statistics_application_result.dart +++ b/packages/scheduler_core/lib/src/project_statistics/models/project_statistics_application_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../project_statistics.dart'; /// Result of applying project-statistic effects from activities. class ProjectStatisticsApplicationResult { + /// Creates a `ProjectStatisticsApplicationResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. ProjectStatisticsApplicationResult({ required this.statistics, List appliedActivityIds = const [], diff --git a/packages/scheduler_core/lib/src/project_statistics/services/project_statistics_aggregation_service.dart b/packages/scheduler_core/lib/src/project_statistics/services/project_statistics_aggregation_service.dart index b5950ee..5b2920f 100644 --- a/packages/scheduler_core/lib/src/project_statistics/services/project_statistics_aggregation_service.dart +++ b/packages/scheduler_core/lib/src/project_statistics/services/project_statistics_aggregation_service.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../project_statistics.dart'; /// Updates project statistics from canonical task activities exactly once. class ProjectStatisticsAggregationService { + /// Creates a `ProjectStatisticsAggregationService` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ProjectStatisticsAggregationService(); /// Apply completion [activities] to [statistics]. diff --git a/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion.dart b/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion.dart index 5d6342e..73c2b69 100644 --- a/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion.dart +++ b/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../project_statistics.dart'; /// One optional learned suggestion with provenance. class ProjectSuggestion { + /// Creates a `ProjectSuggestion` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ProjectSuggestion({ required this.type, required this.value, diff --git a/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion_policy.dart b/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion_policy.dart index 4ab32b1..4286b30 100644 --- a/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion_policy.dart +++ b/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion_policy.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../project_statistics.dart'; /// Minimum sample sizes for deterministic project suggestions. class ProjectSuggestionPolicy { + /// Creates a `ProjectSuggestionPolicy` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ProjectSuggestionPolicy({ this.minimumDurationSamples = 3, this.minimumCompletionTimeSamples = 3, @@ -10,9 +15,23 @@ class ProjectSuggestionPolicy { this.minimumReminderSamples = 3, }); + /// Stores the `minimumDurationSamples` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int minimumDurationSamples; + + /// Stores the `minimumCompletionTimeSamples` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int minimumCompletionTimeSamples; + + /// Stores the `minimumRewardSamples` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int minimumRewardSamples; + + /// Stores the `minimumDifficultySamples` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int minimumDifficultySamples; + + /// Stores the `minimumReminderSamples` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int minimumReminderSamples; } diff --git a/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion_service.dart b/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion_service.dart index 615aae3..7561933 100644 --- a/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion_service.dart +++ b/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion_service.dart @@ -1,11 +1,18 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../project_statistics.dart'; /// Derives deterministic project suggestions from aggregate observations. class ProjectSuggestionService { + /// Creates a `ProjectSuggestionService` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ProjectSuggestionService({ this.policy = const ProjectSuggestionPolicy(), }); + /// Stores the `policy` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ProjectSuggestionPolicy policy; /// Build optional suggestions for [statistics]. @@ -47,6 +54,8 @@ class ProjectSuggestionService { ); } + /// Runs the `_durationSuggestion` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. ProjectSuggestion? _durationSuggestion(ProjectStatistics statistics) { final sampleSize = statistics.knownDurationSampleCount; if (sampleSize < policy.minimumDurationSamples) { @@ -71,6 +80,8 @@ class ProjectSuggestionService { ); } + /// Performs the `Object>` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. ProjectSuggestion? _modeSuggestion({ required ProjectSuggestionType type, required Map counts, @@ -98,6 +109,8 @@ class ProjectSuggestionService { } } +/// Runs the `Object>` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Map _incrementCount(Map counts, K key) { return { ...counts, @@ -105,6 +118,8 @@ Map _incrementCount(Map counts, K key) { }; } +/// Top-level helper that performs the `_positiveIntKeyCounts` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _positiveIntKeyCounts(Map counts, String name) { final normalized = {}; for (final entry in counts.entries) { @@ -119,6 +134,8 @@ Map _positiveIntKeyCounts(Map counts, String name) { return normalized; } +/// Runs the `Enum>` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Map _enumCounts(Map counts, String name) { final normalized = {}; for (final entry in counts.entries) { @@ -130,12 +147,16 @@ Map _enumCounts(Map counts, String name) { return normalized; } +/// Top-level helper that performs the `_validateNonNegative` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. void _validateNonNegative(int value, String name) { if (value < 0) { throw ArgumentError.value(value, name, 'Count cannot be negative.'); } } +/// Runs the `Object>` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. int _countTotal(Map counts) { var total = 0; for (final value in counts.values) { @@ -144,6 +165,8 @@ int _countTotal(Map counts) { return total; } +/// Top-level helper that performs the `_weightedLowerMedian` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int? _weightedLowerMedian(Map counts) { if (counts.isEmpty) { return null; @@ -161,6 +184,8 @@ int? _weightedLowerMedian(Map counts) { return null; } +/// Runs the `Object>` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. T? _uniqueMode(Map counts) { T? bestKey; var bestCount = 0; @@ -181,6 +206,8 @@ T? _uniqueMode(Map counts) { return tied ? null : bestKey; } +/// Top-level helper that performs the `_confidence` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. ProjectSuggestionConfidence _confidence(int support, int sampleSize) { if (sampleSize <= 0) { return ProjectSuggestionConfidence.low; @@ -194,6 +221,8 @@ ProjectSuggestionConfidence _confidence(int support, int sampleSize) { return ProjectSuggestionConfidence.low; } +/// Top-level helper that performs the `_withoutNotSetReward` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _withoutNotSetReward(Map counts) { return { for (final entry in counts.entries) @@ -201,6 +230,8 @@ Map _withoutNotSetReward(Map counts) { }; } +/// Top-level helper that performs the `_withoutNotSetDifficulty` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _withoutNotSetDifficulty( Map counts, ) { @@ -210,6 +241,8 @@ Map _withoutNotSetDifficulty( }; } +/// Top-level helper that performs the `_dateTimeMetadata` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. DateTime? _dateTimeMetadata(Object? value) { if (value is DateTime) { return value; @@ -220,10 +253,14 @@ DateTime? _dateTimeMetadata(Object? value) { return null; } +/// Top-level helper that performs the `_intMetadata` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int? _intMetadata(Object? value) { return value is int && value >= 0 ? value : null; } +/// Top-level helper that performs the `_durationMinutes` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int? _durationMinutes(TaskActivity activity, Task? task) { final metadataDuration = _intMetadata(activity.metadata['durationMinutes']); if (metadataDuration != null && metadataDuration > 0) { @@ -246,6 +283,8 @@ int? _durationMinutes(TaskActivity activity, Task? task) { return task?.durationMinutes; } +/// Top-level helper that performs the `_pushesBeforeCompletion` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _pushesBeforeCompletion(Task? task) { if (task == null) { return 0; @@ -253,6 +292,8 @@ int _pushesBeforeCompletion(Task? task) { return task.stats.manuallyPushedCount + task.stats.autoPushedCount; } +/// Top-level helper that performs the `_rewardLevel` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. RewardLevel? _rewardLevel(Object? value) { if (value is RewardLevel) { return value; @@ -263,6 +304,8 @@ RewardLevel? _rewardLevel(Object? value) { return null; } +/// Top-level helper that performs the `_difficultyLevel` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. DifficultyLevel? _difficultyLevel(Object? value) { if (value is DifficultyLevel) { return value; @@ -273,6 +316,8 @@ DifficultyLevel? _difficultyLevel(Object? value) { return null; } +/// Top-level helper that performs the `_reminderProfile` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. ReminderProfile? _reminderProfile(Object? value) { if (value is ReminderProfile) { return value; @@ -283,6 +328,8 @@ ReminderProfile? _reminderProfile(Object? value) { return null; } +/// Runs the `Enum>` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. T? _enumByName(Iterable values, String name) { for (final value in values) { if (value.name == name) { @@ -292,6 +339,8 @@ T? _enumByName(Iterable values, String name) { return null; } +/// Top-level helper that performs the `_requiredTrimmed` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredTrimmed(String value, String name) { final trimmed = value.trim(); if (trimmed.isEmpty) { diff --git a/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion_set.dart b/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion_set.dart index 5fdd1f1..a4b299b 100644 --- a/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion_set.dart +++ b/packages/scheduler_core/lib/src/project_statistics/suggestions/project_suggestion_set.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../project_statistics.dart'; /// Optional suggestion set derived from one project's observations. class ProjectSuggestionSet { + /// Creates a `ProjectSuggestionSet` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ProjectSuggestionSet({ required this.statistics, this.durationMinutes, @@ -11,10 +16,27 @@ class ProjectSuggestionSet { this.reminderProfile, }); + /// Stores the `statistics` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ProjectStatistics statistics; + + /// Stores the `durationMinutes` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ProjectSuggestion? durationMinutes; + + /// Stores the `completionTimeBucket` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ProjectSuggestion? completionTimeBucket; + + /// Stores the `reward` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ProjectSuggestion? reward; + + /// Stores the `difficulty` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ProjectSuggestion? difficulty; + + /// Stores the `reminderProfile` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ProjectSuggestion? reminderProfile; } diff --git a/packages/scheduler_core/lib/src/quick_capture.dart b/packages/scheduler_core/lib/src/quick_capture.dart index 34a3078..f271926 100644 --- a/packages/scheduler_core/lib/src/quick_capture.dart +++ b/packages/scheduler_core/lib/src/quick_capture.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Quick Capture behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/quick_capture/quick_capture_request.dart b/packages/scheduler_core/lib/src/quick_capture/quick_capture_request.dart index f854260..d6af0c0 100644 --- a/packages/scheduler_core/lib/src/quick_capture/quick_capture_request.dart +++ b/packages/scheduler_core/lib/src/quick_capture/quick_capture_request.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../quick_capture.dart'; /// Input for low-friction task capture. @@ -7,6 +10,8 @@ part of '../quick_capture.dart'; /// possible, but the user can optionally provide enough detail to immediately /// schedule it into the next open flexible slot. class QuickCaptureRequest { + /// Creates a `QuickCaptureRequest` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. QuickCaptureRequest({ required this.id, required this.title, diff --git a/packages/scheduler_core/lib/src/quick_capture/quick_capture_result.dart b/packages/scheduler_core/lib/src/quick_capture/quick_capture_result.dart index 65ea65c..c380746 100644 --- a/packages/scheduler_core/lib/src/quick_capture/quick_capture_result.dart +++ b/packages/scheduler_core/lib/src/quick_capture/quick_capture_result.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../quick_capture.dart'; /// Result of a quick-capture request. @@ -7,6 +10,8 @@ part of '../quick_capture.dart'; /// was attempted, [schedulingResult] exposes the lower-level engine notices and /// changes for debugging or timeline updates. class QuickCaptureResult { + /// Creates a `QuickCaptureResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. QuickCaptureResult({ required this.task, required this.status, diff --git a/packages/scheduler_core/lib/src/quick_capture/quick_capture_service.dart b/packages/scheduler_core/lib/src/quick_capture/quick_capture_service.dart index 92f1129..6e205fc 100644 --- a/packages/scheduler_core/lib/src/quick_capture/quick_capture_service.dart +++ b/packages/scheduler_core/lib/src/quick_capture/quick_capture_service.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../quick_capture.dart'; /// Coordinates quick capture defaults and optional scheduling. @@ -7,6 +10,8 @@ part of '../quick_capture.dart'; /// [SchedulingEngine]. It keeps quick-capture UI code from needing to understand /// every scheduler precondition. class QuickCaptureService { + /// Creates a `QuickCaptureService` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const QuickCaptureService({ this.engine = const SchedulingEngine(), this.clock = const SystemClock(), diff --git a/packages/scheduler_core/lib/src/quick_capture/quick_capture_status.dart b/packages/scheduler_core/lib/src/quick_capture/quick_capture_status.dart index 423d0c7..908ce20 100644 --- a/packages/scheduler_core/lib/src/quick_capture/quick_capture_status.dart +++ b/packages/scheduler_core/lib/src/quick_capture/quick_capture_status.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../quick_capture.dart'; /// Outcome of a quick-capture request. diff --git a/packages/scheduler_core/lib/src/reminder_policy.dart b/packages/scheduler_core/lib/src/reminder_policy.dart index 7997f79..88b0aa4 100644 --- a/packages/scheduler_core/lib/src/reminder_policy.dart +++ b/packages/scheduler_core/lib/src/reminder_policy.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Reminder Policy behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/reminder_policy/directives/reminder_directive.dart b/packages/scheduler_core/lib/src/reminder_policy/directives/reminder_directive.dart index 6ecfda7..801e3c2 100644 --- a/packages/scheduler_core/lib/src/reminder_policy/directives/reminder_directive.dart +++ b/packages/scheduler_core/lib/src/reminder_policy/directives/reminder_directive.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../reminder_policy.dart'; /// UI/platform-independent directive for one task reminder check. class ReminderDirective { + /// Creates a `ReminderDirective` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ReminderDirective({ required this.taskId, required this.action, diff --git a/packages/scheduler_core/lib/src/reminder_policy/directives/reminder_directive_action.dart b/packages/scheduler_core/lib/src/reminder_policy/directives/reminder_directive_action.dart index d449a3a..4a93115 100644 --- a/packages/scheduler_core/lib/src/reminder_policy/directives/reminder_directive_action.dart +++ b/packages/scheduler_core/lib/src/reminder_policy/directives/reminder_directive_action.dart @@ -1,9 +1,23 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../reminder_policy.dart'; /// High-level reminder directive for application/platform layers. enum ReminderDirectiveAction { + /// Selects the `deliver` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. deliver, + + /// Selects the `suppress` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. suppress, + + /// Selects the `defer` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. defer, + + /// Selects the `requireAcknowledgement` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. requireAcknowledgement, } diff --git a/packages/scheduler_core/lib/src/reminder_policy/directives/reminder_directive_reason.dart b/packages/scheduler_core/lib/src/reminder_policy/directives/reminder_directive_reason.dart index 0539c35..2c7cd82 100644 --- a/packages/scheduler_core/lib/src/reminder_policy/directives/reminder_directive_reason.dart +++ b/packages/scheduler_core/lib/src/reminder_policy/directives/reminder_directive_reason.dart @@ -1,16 +1,51 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../reminder_policy.dart'; /// Stable reason codes for reminder directives. enum ReminderDirectiveReason { + /// Selects the `deliverNormal` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. deliverNormal, + + /// Selects the `requireRequiredAcknowledgement` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. requireRequiredAcknowledgement, + + /// Selects the `deferUntilTaskWindow` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. deferUntilTaskWindow, + + /// Selects the `deferRequiredDuringProtectedRest` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. deferRequiredDuringProtectedRest, + + /// Selects the `suppressSilentProfile` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. suppressSilentProfile, + + /// Selects the `suppressProtectedRest` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. suppressProtectedRest, + + /// Selects the `suppressNoScheduledWindow` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. suppressNoScheduledWindow, + + /// Selects the `suppressUnsupportedTaskType` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. suppressUnsupportedTaskType, + + /// Selects the `suppressInactiveStatus` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. suppressInactiveStatus, + + /// Selects the `suppressHiddenLockedTime` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. suppressHiddenLockedTime, + + /// Selects the `suppressFreeSlotRecord` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. suppressFreeSlotRecord, } diff --git a/packages/scheduler_core/lib/src/reminder_policy/profiles/effective_reminder_profile.dart b/packages/scheduler_core/lib/src/reminder_policy/profiles/effective_reminder_profile.dart index 8433179..a509204 100644 --- a/packages/scheduler_core/lib/src/reminder_policy/profiles/effective_reminder_profile.dart +++ b/packages/scheduler_core/lib/src/reminder_policy/profiles/effective_reminder_profile.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../reminder_policy.dart'; /// Result of resolving the effective reminder profile for one task. class EffectiveReminderProfile { + /// Creates a `EffectiveReminderProfile` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const EffectiveReminderProfile({ required this.profile, required this.source, diff --git a/packages/scheduler_core/lib/src/reminder_policy/profiles/effective_reminder_profile_source.dart b/packages/scheduler_core/lib/src/reminder_policy/profiles/effective_reminder_profile_source.dart index 164b2cb..d9754c6 100644 --- a/packages/scheduler_core/lib/src/reminder_policy/profiles/effective_reminder_profile_source.dart +++ b/packages/scheduler_core/lib/src/reminder_policy/profiles/effective_reminder_profile_source.dart @@ -1,8 +1,19 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../reminder_policy.dart'; /// Source for an effective reminder profile. enum EffectiveReminderProfileSource { + /// Selects the `taskOverride` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. taskOverride, + + /// Selects the `projectDefault` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. projectDefault, + + /// Selects the `fallback` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. fallback, } diff --git a/packages/scheduler_core/lib/src/reminder_policy/services/reminder_policy_service.dart b/packages/scheduler_core/lib/src/reminder_policy/services/reminder_policy_service.dart index 9fc305a..f60bf11 100644 --- a/packages/scheduler_core/lib/src/reminder_policy/services/reminder_policy_service.dart +++ b/packages/scheduler_core/lib/src/reminder_policy/services/reminder_policy_service.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../reminder_policy.dart'; /// Resolves reminder profiles and reminder directives. class ReminderPolicyService { + /// Creates a `ReminderPolicyService` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ReminderPolicyService({ this.fallbackProfile = ReminderProfile.gentle, this.occupancyPolicy = const OccupancyPolicy(), @@ -60,6 +65,8 @@ class ReminderPolicyService { ); } + /// Runs the `_directiveForTask` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. ReminderDirective _directiveForTask({ required Task task, required DateTime now, @@ -170,6 +177,8 @@ class ReminderPolicyService { ); } + /// Runs the `_requiredDuringProtectedRest` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. ReminderDirective _requiredDuringProtectedRest({ required Task task, required EffectiveReminderProfile effective, @@ -203,6 +212,8 @@ class ReminderPolicyService { ); } + /// Runs the `_activeProtectedFreeSlot` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. OccupancyEntry? _activeProtectedFreeSlot({ required DateTime now, required Iterable contextTasks, @@ -226,10 +237,14 @@ class ReminderPolicyService { } } +/// Top-level helper that performs the `_isReminderEligibleStatus` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _isReminderEligibleStatus(TaskStatus status) { return status == TaskStatus.planned || status == TaskStatus.active; } +/// Top-level helper that performs the `_isReminderEligibleType` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _isReminderEligibleType(TaskType type) { return type == TaskType.flexible || type == TaskType.critical || diff --git a/packages/scheduler_core/lib/src/repositories.dart b/packages/scheduler_core/lib/src/repositories.dart index a08fa1e..7cebdba 100644 --- a/packages/scheduler_core/lib/src/repositories.dart +++ b/packages/scheduler_core/lib/src/repositories.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Repositories behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/repositories/failures/repository_failure.dart b/packages/scheduler_core/lib/src/repositories/failures/repository_failure.dart index 42331f8..e3e783b 100644 --- a/packages/scheduler_core/lib/src/repositories/failures/repository_failure.dart +++ b/packages/scheduler_core/lib/src/repositories/failures/repository_failure.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// Typed repository failure for optimistic writes and uniqueness checks. class RepositoryFailure { + /// Creates a `RepositoryFailure` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const RepositoryFailure({ required this.code, this.entityId, @@ -9,8 +14,19 @@ class RepositoryFailure { this.actualRevision, }); + /// Stores the `code` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final RepositoryFailureCode code; + + /// Stores the `entityId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? entityId; + + /// Stores the `expectedRevision` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int? expectedRevision; + + /// Stores the `actualRevision` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int? actualRevision; } diff --git a/packages/scheduler_core/lib/src/repositories/failures/repository_failure_code.dart b/packages/scheduler_core/lib/src/repositories/failures/repository_failure_code.dart index 4aa0f55..f9d1c88 100644 --- a/packages/scheduler_core/lib/src/repositories/failures/repository_failure_code.dart +++ b/packages/scheduler_core/lib/src/repositories/failures/repository_failure_code.dart @@ -1,11 +1,31 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// Stable repository mutation failure categories. enum RepositoryFailureCode { + /// Selects the `notFound` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. notFound, + + /// Selects the `staleRevision` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. staleRevision, + + /// Selects the `invalidRevision` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidRevision, + + /// Selects the `ownerMismatch` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. ownerMismatch, + + /// Selects the `duplicateId` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. duplicateId, + + /// Selects the `duplicateOperation` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. duplicateOperation, } diff --git a/packages/scheduler_core/lib/src/repositories/failures/repository_mutation_result.dart b/packages/scheduler_core/lib/src/repositories/failures/repository_mutation_result.dart index ee0b79b..8bb383c 100644 --- a/packages/scheduler_core/lib/src/repositories/failures/repository_mutation_result.dart +++ b/packages/scheduler_core/lib/src/repositories/failures/repository_mutation_result.dart @@ -1,22 +1,38 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// Mutation result that avoids throwing for expected repository conflicts. class RepositoryMutationResult { + /// Creates a `RepositoryMutationResult._` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const RepositoryMutationResult._({ this.revision, this.failure, }); + /// Creates a `RepositoryMutationResult.success` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. factory RepositoryMutationResult.success({required int revision}) { return RepositoryMutationResult._(revision: revision); } + /// Creates a `RepositoryMutationResult.failure` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. factory RepositoryMutationResult.failure(RepositoryFailure failure) { return RepositoryMutationResult._(failure: failure); } + /// Stores the `revision` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int? revision; + + /// Stores the `failure` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final RepositoryFailure? failure; + /// Returns the derived `isSuccess` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. bool get isSuccess => failure == null; } diff --git a/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_locked_block_repository.dart b/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_locked_block_repository.dart index c81eb3f..4c8ced5 100644 --- a/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_locked_block_repository.dart +++ b/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_locked_block_repository.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// In-memory locked-time repository useful for tests and early wiring. class InMemoryLockedBlockRepository implements LockedBlockRepository { + /// Creates a `InMemoryLockedBlockRepository` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. InMemoryLockedBlockRepository({ Iterable initialBlocks = const [], Iterable initialOverrides = const [], @@ -25,19 +30,43 @@ class InMemoryLockedBlockRepository implements LockedBlockRepository { for (final override in initialOverrides) override.id: 1, }; + /// Private state stored as `_blocksById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _blocksById; + + /// Private state stored as `_blockOwnersById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _blockOwnersById; + + /// Private state stored as `_blockRevisionsById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _blockRevisionsById; + + /// Private state stored as `_overridesById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _overridesById; + + /// Private state stored as `_overrideOwnersById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _overrideOwnersById; + + /// Private state stored as `_overrideRevisionsById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _overrideRevisionsById; + + /// Stores the `defaultOwnerId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String defaultOwnerId; + /// Runs the `findBlockById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findBlockById(String id) async { return _blocksById[id]; } + /// Runs the `findBlockRecordById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future?> findBlockRecordById(String id) async { final block = _blocksById[id]; @@ -52,11 +81,15 @@ class InMemoryLockedBlockRepository implements LockedBlockRepository { ); } + /// Runs the `findAllBlocks` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findAllBlocks() async { return List.unmodifiable(_blocksById.values); } + /// Runs the `findBlocksByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findBlocksByOwner({ required String ownerId, @@ -74,11 +107,15 @@ class InMemoryLockedBlockRepository implements LockedBlockRepository { return _page(blocks, page); } + /// Runs the `findOverrideById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findOverrideById(String id) async { return _overridesById[id]; } + /// Runs the `findOverrideRecordById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future?> findOverrideRecordById( String id, @@ -94,11 +131,15 @@ class InMemoryLockedBlockRepository implements LockedBlockRepository { ); } + /// Runs the `findAllOverrides` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findAllOverrides() async { return List.unmodifiable(_overridesById.values); } + /// Runs the `findOverridesForDate` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findOverridesForDate({ required String ownerId, @@ -116,6 +157,8 @@ class InMemoryLockedBlockRepository implements LockedBlockRepository { return _page(overrides, page); } + /// Runs the `saveBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveBlock(LockedBlock block) async { _blocksById[block.id] = block; @@ -123,6 +166,8 @@ class InMemoryLockedBlockRepository implements LockedBlockRepository { _blockRevisionsById[block.id] = _blockRevisionFor(block.id) + 1; } + /// Runs the `saveOverride` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveOverride(LockedBlockOverride override) async { _overridesById[override.id] = override; @@ -130,6 +175,8 @@ class InMemoryLockedBlockRepository implements LockedBlockRepository { _overrideRevisionsById[override.id] = _overrideRevisionFor(override.id) + 1; } + /// Runs the `insertBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future insertBlock({ required LockedBlock block, @@ -149,6 +196,8 @@ class InMemoryLockedBlockRepository implements LockedBlockRepository { return RepositoryMutationResult.success(revision: 1); } + /// Runs the `saveBlockIfRevision` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveBlockIfRevision({ required LockedBlock block, @@ -199,6 +248,8 @@ class InMemoryLockedBlockRepository implements LockedBlockRepository { return RepositoryMutationResult.success(revision: nextRevision); } + /// Runs the `archiveBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future archiveBlock({ required String blockId, @@ -222,6 +273,8 @@ class InMemoryLockedBlockRepository implements LockedBlockRepository { ); } + /// Runs the `insertOverride` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future insertOverride({ required LockedBlockOverride override, @@ -241,6 +294,8 @@ class InMemoryLockedBlockRepository implements LockedBlockRepository { return RepositoryMutationResult.success(revision: 1); } + /// Runs the `saveOverrideIfRevision` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveOverrideIfRevision({ required LockedBlockOverride override, @@ -291,12 +346,20 @@ class InMemoryLockedBlockRepository implements LockedBlockRepository { return RepositoryMutationResult.success(revision: nextRevision); } + /// Runs the `_blockOwnerFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. String _blockOwnerFor(String id) => _blockOwnersById[id] ?? defaultOwnerId; + /// Runs the `_blockRevisionFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. int _blockRevisionFor(String id) => _blockRevisionsById[id] ?? 1; + /// Runs the `_overrideOwnerFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. String _overrideOwnerFor(String id) => _overrideOwnersById[id] ?? defaultOwnerId; + /// Runs the `_overrideRevisionFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. int _overrideRevisionFor(String id) => _overrideRevisionsById[id] ?? 1; } diff --git a/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_project_repository.dart b/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_project_repository.dart index 85b8021..0c5fc4b 100644 --- a/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_project_repository.dart +++ b/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_project_repository.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// In-memory project repository useful for tests and early application wiring. class InMemoryProjectRepository implements ProjectRepository { + /// Creates a `InMemoryProjectRepository` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. InMemoryProjectRepository( [Iterable initialProjects = const [], this.defaultOwnerId = 'owner-1']) @@ -15,16 +20,31 @@ class InMemoryProjectRepository implements ProjectRepository { for (final project in initialProjects) project.id: 1, }; + /// Private state stored as `_projectsById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _projectsById; + + /// Private state stored as `_ownersById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _ownersById; + + /// Private state stored as `_revisionsById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _revisionsById; + + /// Stores the `defaultOwnerId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String defaultOwnerId; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findById(String id) async { return _projectsById[id]; } + /// Runs the `findRecordById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future?> findRecordById(String id) async { final project = _projectsById[id]; @@ -39,11 +59,15 @@ class InMemoryProjectRepository implements ProjectRepository { ); } + /// Runs the `findAll` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findAll() async { return List.unmodifiable(_projectsById.values); } + /// Runs the `findByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByOwner({ required String ownerId, @@ -61,6 +85,8 @@ class InMemoryProjectRepository implements ProjectRepository { return _page(projects, page); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future save(ProjectProfile project) async { _projectsById[project.id] = project; @@ -68,6 +94,8 @@ class InMemoryProjectRepository implements ProjectRepository { _revisionsById[project.id] = _revisionFor(project.id) + 1; } + /// Runs the `insert` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future insert({ required ProjectProfile project, @@ -87,6 +115,8 @@ class InMemoryProjectRepository implements ProjectRepository { return RepositoryMutationResult.success(revision: 1); } + /// Runs the `saveIfRevision` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveIfRevision({ required ProjectProfile project, @@ -137,6 +167,8 @@ class InMemoryProjectRepository implements ProjectRepository { return RepositoryMutationResult.success(revision: nextRevision); } + /// Runs the `archive` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future archive({ required String projectId, @@ -160,7 +192,11 @@ class InMemoryProjectRepository implements ProjectRepository { ); } + /// Runs the `_ownerFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. String _ownerFor(String id) => _ownersById[id] ?? defaultOwnerId; + /// Runs the `_revisionFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. int _revisionFor(String id) => _revisionsById[id] ?? 1; } diff --git a/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_scheduling_snapshot_repository.dart b/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_scheduling_snapshot_repository.dart index 10a0981..ce264ff 100644 --- a/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_scheduling_snapshot_repository.dart +++ b/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_scheduling_snapshot_repository.dart @@ -1,21 +1,32 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// In-memory snapshot repository useful for tests and early application wiring. class InMemorySchedulingSnapshotRepository implements SchedulingSnapshotRepository { + /// Creates a `InMemorySchedulingSnapshotRepository` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. InMemorySchedulingSnapshotRepository([ Iterable initialSnapshots = const [], ]) : _snapshotsById = { for (final snapshot in initialSnapshots) snapshot.id: snapshot, }; + /// Private state stored as `_snapshotsById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _snapshotsById; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findById(String id) async { return _snapshotsById[id]; } + /// Runs the `findInWindow` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findInWindow( SchedulingWindow window, @@ -27,12 +38,16 @@ class InMemorySchedulingSnapshotRepository ); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future save(SchedulingStateSnapshot snapshot) async { _snapshotsById[snapshot.id] = snapshot; } } +/// Top-level helper that performs the `_page` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. RepositoryPage _page(List sortedItems, RepositoryPageRequest request) { final offset = int.tryParse(request.cursor ?? '') ?? 0; final safeOffset = offset.clamp(0, sortedItems.length); @@ -45,6 +60,8 @@ RepositoryPage _page(List sortedItems, RepositoryPageRequest request) { ); } +/// Top-level helper that performs the `_taskOverlapsWindow` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _taskOverlapsWindow(Task task, SchedulingWindow window) { final start = task.scheduledStart; final end = task.scheduledEnd; @@ -54,8 +71,12 @@ bool _taskOverlapsWindow(Task task, SchedulingWindow window) { return TimeInterval(start: start, end: end).overlaps(window.interval); } +/// Top-level helper that performs the `_compareTaskIds` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareTaskIds(Task left, Task right) => left.id.compareTo(right.id); +/// Top-level helper that performs the `_compareScheduledTasks` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareScheduledTasks(Task left, Task right) { final leftStart = left.scheduledStart; final rightStart = right.scheduledStart; @@ -68,6 +89,8 @@ int _compareScheduledTasks(Task left, Task right) { return left.id.compareTo(right.id); } +/// Top-level helper that performs the `_compareBacklogCandidates` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareBacklogCandidates(Task left, Task right) { final createdComparison = left.createdAt.compareTo(right.createdAt); if (createdComparison != 0) { @@ -76,6 +99,8 @@ int _compareBacklogCandidates(Task left, Task right) { return left.id.compareTo(right.id); } +/// Top-level helper that performs the `_compareProjects` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareProjects(ProjectProfile left, ProjectProfile right) { final nameComparison = left.name.compareTo(right.name); if (nameComparison != 0) { @@ -84,6 +109,8 @@ int _compareProjects(ProjectProfile left, ProjectProfile right) { return left.id.compareTo(right.id); } +/// Top-level helper that performs the `_compareLockedBlocks` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareLockedBlocks(LockedBlock left, LockedBlock right) { final nameComparison = left.name.compareTo(right.name); if (nameComparison != 0) { @@ -92,6 +119,8 @@ int _compareLockedBlocks(LockedBlock left, LockedBlock right) { return left.id.compareTo(right.id); } +/// Top-level helper that performs the `_compareLockedOverrides` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareLockedOverrides( LockedBlockOverride left, LockedBlockOverride right, diff --git a/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_task_repository.dart b/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_task_repository.dart index f67f986..952608a 100644 --- a/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_task_repository.dart +++ b/packages/scheduler_core/lib/src/repositories/in_memory/in_memory_task_repository.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// In-memory task repository useful for tests and early application wiring. class InMemoryTaskRepository implements TaskRepository { + /// Creates a `InMemoryTaskRepository` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. InMemoryTaskRepository([ Iterable initialTasks = const [], this.defaultOwnerId = 'owner-1', @@ -15,16 +20,31 @@ class InMemoryTaskRepository implements TaskRepository { for (final task in initialTasks) task.id: 1, }; + /// Private state stored as `_tasksById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _tasksById; + + /// Private state stored as `_ownersById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _ownersById; + + /// Private state stored as `_revisionsById` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _revisionsById; + + /// Stores the `defaultOwnerId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String defaultOwnerId; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future findById(String id) async { return _tasksById[id]; } + /// Runs the `findRecordById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future?> findRecordById(String id) async { final task = _tasksById[id]; @@ -38,11 +58,15 @@ class InMemoryTaskRepository implements TaskRepository { ); } + /// Runs the `findAll` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findAll() async { return List.unmodifiable(_tasksById.values); } + /// Runs the `findByStatus` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByStatus(TaskStatus status) async { return List.unmodifiable( @@ -50,6 +74,8 @@ class InMemoryTaskRepository implements TaskRepository { ); } + /// Runs the `findByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByOwner({ required String ownerId, @@ -62,6 +88,8 @@ class InMemoryTaskRepository implements TaskRepository { return _page(tasks, page); } + /// Runs the `findByProjectId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByProjectId({ required String ownerId, @@ -78,6 +106,8 @@ class InMemoryTaskRepository implements TaskRepository { return _page(tasks, page); } + /// Runs the `findByParentTaskId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByParentTaskId({ required String ownerId, @@ -95,6 +125,8 @@ class InMemoryTaskRepository implements TaskRepository { return _page(tasks, page); } + /// Runs the `findBacklogCandidates` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findBacklogCandidates( BacklogCandidateQuery query, @@ -112,6 +144,8 @@ class InMemoryTaskRepository implements TaskRepository { return _page(tasks, query.page); } + /// Runs the `findScheduledInWindow` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findScheduledInWindow(SchedulingWindow window) async { return List.unmodifiable( @@ -121,6 +155,8 @@ class InMemoryTaskRepository implements TaskRepository { ); } + /// Runs the `findScheduledInWindowForOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findScheduledInWindowForOwner({ required String ownerId, @@ -141,6 +177,8 @@ class InMemoryTaskRepository implements TaskRepository { return _page(tasks, page); } + /// Runs the `findForLocalDay` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findForLocalDay({ required String ownerId, @@ -155,6 +193,8 @@ class InMemoryTaskRepository implements TaskRepository { ); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future save(Task task) async { _tasksById[task.id] = task; @@ -162,6 +202,8 @@ class InMemoryTaskRepository implements TaskRepository { _revisionsById[task.id] = _revisionFor(task.id) + 1; } + /// Runs the `saveAll` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveAll(Iterable tasks) async { for (final task in tasks) { @@ -169,6 +211,8 @@ class InMemoryTaskRepository implements TaskRepository { } } + /// Runs the `insert` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future insert({ required Task task, @@ -188,6 +232,8 @@ class InMemoryTaskRepository implements TaskRepository { return RepositoryMutationResult.success(revision: 1); } + /// Runs the `saveIfRevision` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future saveIfRevision({ required Task task, @@ -238,7 +284,11 @@ class InMemoryTaskRepository implements TaskRepository { return RepositoryMutationResult.success(revision: nextRevision); } + /// Runs the `_ownerFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. String _ownerFor(String id) => _ownersById[id] ?? defaultOwnerId; + /// Runs the `_revisionFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. int _revisionFor(String id) => _revisionsById[id] ?? 1; } diff --git a/packages/scheduler_core/lib/src/repositories/interfaces/locked_block_repository.dart b/packages/scheduler_core/lib/src/repositories/interfaces/locked_block_repository.dart index 16345e7..0178653 100644 --- a/packages/scheduler_core/lib/src/repositories/interfaces/locked_block_repository.dart +++ b/packages/scheduler_core/lib/src/repositories/interfaces/locked_block_repository.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// Repository contract for locked-block and one-day override documents. @@ -42,17 +45,23 @@ abstract interface class LockedBlockRepository { /// Save or replace [override] by stable id. Future saveOverride(LockedBlockOverride override); + /// Runs the `insertBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future insertBlock({ required LockedBlock block, required String ownerId, }); + /// Runs the `saveBlockIfRevision` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future saveBlockIfRevision({ required LockedBlock block, required String ownerId, required int expectedRevision, }); + /// Runs the `archiveBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future archiveBlock({ required String blockId, required String ownerId, @@ -60,11 +69,15 @@ abstract interface class LockedBlockRepository { required DateTime archivedAt, }); + /// Runs the `insertOverride` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future insertOverride({ required LockedBlockOverride override, required String ownerId, }); + /// Runs the `saveOverrideIfRevision` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future saveOverrideIfRevision({ required LockedBlockOverride override, required String ownerId, diff --git a/packages/scheduler_core/lib/src/repositories/interfaces/project_repository.dart b/packages/scheduler_core/lib/src/repositories/interfaces/project_repository.dart index d633730..e4d5963 100644 --- a/packages/scheduler_core/lib/src/repositories/interfaces/project_repository.dart +++ b/packages/scheduler_core/lib/src/repositories/interfaces/project_repository.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// Repository contract for project profile documents. diff --git a/packages/scheduler_core/lib/src/repositories/interfaces/scheduling_snapshot_repository.dart b/packages/scheduler_core/lib/src/repositories/interfaces/scheduling_snapshot_repository.dart index 662f436..49fdaff 100644 --- a/packages/scheduler_core/lib/src/repositories/interfaces/scheduling_snapshot_repository.dart +++ b/packages/scheduler_core/lib/src/repositories/interfaces/scheduling_snapshot_repository.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// Repository contract for scheduling operation/state snapshot documents. diff --git a/packages/scheduler_core/lib/src/repositories/interfaces/task_repository.dart b/packages/scheduler_core/lib/src/repositories/interfaces/task_repository.dart index 9f1c316..d479d6a 100644 --- a/packages/scheduler_core/lib/src/repositories/interfaces/task_repository.dart +++ b/packages/scheduler_core/lib/src/repositories/interfaces/task_repository.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// Repository contract for task documents. diff --git a/packages/scheduler_core/lib/src/repositories/pagination/repository_page.dart b/packages/scheduler_core/lib/src/repositories/pagination/repository_page.dart index 5a83dc4..7072fff 100644 --- a/packages/scheduler_core/lib/src/repositories/pagination/repository_page.dart +++ b/packages/scheduler_core/lib/src/repositories/pagination/repository_page.dart @@ -1,14 +1,26 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// One bounded page of repository query results. class RepositoryPage { + /// Creates a `RepositoryPage` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const RepositoryPage({ required this.items, this.nextCursor, }); + /// Stores the `items` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final List items; + + /// Stores the `nextCursor` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? nextCursor; + /// Returns the derived `hasMore` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. bool get hasMore => nextCursor != null; } diff --git a/packages/scheduler_core/lib/src/repositories/pagination/repository_page_request.dart b/packages/scheduler_core/lib/src/repositories/pagination/repository_page_request.dart index a2d5b54..b38d50a 100644 --- a/packages/scheduler_core/lib/src/repositories/pagination/repository_page_request.dart +++ b/packages/scheduler_core/lib/src/repositories/pagination/repository_page_request.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// Cursor contract for bounded repository queries. class RepositoryPageRequest { + /// Creates a `RepositoryPageRequest` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const RepositoryPageRequest({ this.cursor, this.limit = 100, diff --git a/packages/scheduler_core/lib/src/repositories/pagination/repository_record.dart b/packages/scheduler_core/lib/src/repositories/pagination/repository_record.dart index 8b74e89..5bb81f4 100644 --- a/packages/scheduler_core/lib/src/repositories/pagination/repository_record.dart +++ b/packages/scheduler_core/lib/src/repositories/pagination/repository_record.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// Repository value plus adapter-neutral metadata. class RepositoryRecord { + /// Creates a `RepositoryRecord` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const RepositoryRecord({ required this.value, required this.ownerId, @@ -9,10 +14,23 @@ class RepositoryRecord { this.archivedAt, }); + /// Stores the `value` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final T value; + + /// Stores the `ownerId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String ownerId; + + /// Stores the `revision` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int revision; + + /// Stores the `archivedAt` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DateTime? archivedAt; + /// Returns the derived `isArchived` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. bool get isArchived => archivedAt != null; } diff --git a/packages/scheduler_core/lib/src/repositories/queries/backlog_candidate_query.dart b/packages/scheduler_core/lib/src/repositories/queries/backlog_candidate_query.dart index 133cefd..f8d03f6 100644 --- a/packages/scheduler_core/lib/src/repositories/queries/backlog_candidate_query.dart +++ b/packages/scheduler_core/lib/src/repositories/queries/backlog_candidate_query.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// Status/project filters for backlog candidate queries. class BacklogCandidateQuery { + /// Creates a `BacklogCandidateQuery` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const BacklogCandidateQuery({ required this.ownerId, this.projectId, @@ -9,8 +14,19 @@ class BacklogCandidateQuery { this.page = const RepositoryPageRequest(), }); + /// Stores the `ownerId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String ownerId; + + /// Stores the `projectId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String? projectId; + + /// Stores the `tags` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Set tags; + + /// Stores the `page` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final RepositoryPageRequest page; } diff --git a/packages/scheduler_core/lib/src/repositories/queries/scheduling_state_snapshot.dart b/packages/scheduler_core/lib/src/repositories/queries/scheduling_state_snapshot.dart index e026759..4f323d9 100644 --- a/packages/scheduler_core/lib/src/repositories/queries/scheduling_state_snapshot.dart +++ b/packages/scheduler_core/lib/src/repositories/queries/scheduling_state_snapshot.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../repositories.dart'; /// Snapshot of one scheduling operation or persisted planning state. class SchedulingStateSnapshot { + /// Creates a `SchedulingStateSnapshot` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. SchedulingStateSnapshot({ required this.id, required this.capturedAt, diff --git a/packages/scheduler_core/lib/src/repository_values.dart b/packages/scheduler_core/lib/src/repository_values.dart index 95a523a..23802a2 100644 --- a/packages/scheduler_core/lib/src/repository_values.dart +++ b/packages/scheduler_core/lib/src/repository_values.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Shared repository value objects used by persistence adapters. /// /// These types are deliberately small and database-agnostic. They live in the diff --git a/packages/scheduler_core/lib/src/repository_values/owner_id.dart b/packages/scheduler_core/lib/src/repository_values/owner_id.dart index dddd783..01163c0 100644 --- a/packages/scheduler_core/lib/src/repository_values/owner_id.dart +++ b/packages/scheduler_core/lib/src/repository_values/owner_id.dart @@ -1,20 +1,31 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../repository_values.dart'; /// Stable owner scope for repository operations. class OwnerId { + /// Creates a `OwnerId` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. OwnerId(String value) : value = _requiredTrimmed(value, 'ownerId'); /// Raw owner identifier. final String value; + /// Converts scheduler data for `toString` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. @override String toString() => value; + /// Performs the `operator ==` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override bool operator ==(Object other) { return other is OwnerId && other.value == value; } + /// Returns the derived `hashCode` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override int get hashCode => value.hashCode; } diff --git a/packages/scheduler_core/lib/src/repository_values/page.dart b/packages/scheduler_core/lib/src/repository_values/page.dart index fa35079..cfc5da6 100644 --- a/packages/scheduler_core/lib/src/repository_values/page.dart +++ b/packages/scheduler_core/lib/src/repository_values/page.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../repository_values.dart'; /// One bounded page of repository query results. class Page { + /// Creates a `Page` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. Page({ required Iterable items, this.nextCursor, @@ -17,6 +22,8 @@ class Page { bool get hasMore => nextCursor != null; } +/// Top-level helper that performs the `_requiredTrimmed` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredTrimmed(String value, String name) { final trimmed = value.trim(); if (trimmed.isEmpty) { diff --git a/packages/scheduler_core/lib/src/repository_values/page_request.dart b/packages/scheduler_core/lib/src/repository_values/page_request.dart index d249de2..5dc598a 100644 --- a/packages/scheduler_core/lib/src/repository_values/page_request.dart +++ b/packages/scheduler_core/lib/src/repository_values/page_request.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../repository_values.dart'; /// Cursor contract for bounded repository queries. class PageRequest { + /// Creates a `PageRequest` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const PageRequest({ this.cursor, this.limit = 100, diff --git a/packages/scheduler_core/lib/src/repository_values/revision.dart b/packages/scheduler_core/lib/src/repository_values/revision.dart index aebda11..8fe5227 100644 --- a/packages/scheduler_core/lib/src/repository_values/revision.dart +++ b/packages/scheduler_core/lib/src/repository_values/revision.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../repository_values.dart'; /// Optimistic concurrency revision for mutable repository records. class Revision implements Comparable { + /// Creates a `Revision` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const Revision(this.value) : assert(value >= 0); /// First revision assigned to a newly inserted record. @@ -13,17 +18,25 @@ class Revision implements Comparable { /// Return the next monotonically increasing revision. Revision next() => Revision(value + 1); + /// Performs the `compareTo` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override int compareTo(Revision other) => value.compareTo(other.value); + /// Converts scheduler data for `toString` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. @override String toString() => value.toString(); + /// Performs the `operator ==` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override bool operator ==(Object other) { return other is Revision && other.value == value; } + /// Returns the derived `hashCode` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override int get hashCode => value.hashCode; } diff --git a/packages/scheduler_core/lib/src/scheduling_engine.dart b/packages/scheduler_core/lib/src/scheduling_engine.dart index 6388276..63646f2 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Scheduling Engine behavior for the Scheduler Core package. library; @@ -35,7 +38,15 @@ part 'scheduling_engine/engine/scheduling_engine.dart'; part 'scheduling_engine/planning/placement_item.dart'; part 'scheduling_engine/planning/backlog_insertion_plan.dart'; +/// Private file-level value for `_occupancyPolicy`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const OccupancyPolicy _occupancyPolicy = OccupancyPolicy(); + +/// Private file-level value for `_transitionService`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const TaskTransitionService _transitionService = TaskTransitionService(); + +/// Private file-level value for `_activityAccountingService`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const TaskActivityAccountingService _activityAccountingService = TaskActivityAccountingService(); diff --git a/packages/scheduler_core/lib/src/scheduling_engine/codes/conflicts/scheduling_conflict_code.dart b/packages/scheduler_core/lib/src/scheduling_engine/codes/conflicts/scheduling_conflict_code.dart index b5df4a7..f9d41ae 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/codes/conflicts/scheduling_conflict_code.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/codes/conflicts/scheduling_conflict_code.dart @@ -1,8 +1,19 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduling_engine.dart'; /// Stable conflict identifiers for overlap/interrupt notices. enum SchedulingConflictCode { + /// Selects the `flexibleTaskOverlapsBlockedTime` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. flexibleTaskOverlapsBlockedTime, + + /// Selects the `surpriseTaskOverlapsRequiredVisibleTime` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. surpriseTaskOverlapsRequiredVisibleTime, + + /// Selects the `requiredCommitmentOverlapsProtectedFreeSlot` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. requiredCommitmentOverlapsProtectedFreeSlot, } diff --git a/packages/scheduler_core/lib/src/scheduling_engine/codes/notices/scheduling_issue_code.dart b/packages/scheduler_core/lib/src/scheduling_engine/codes/notices/scheduling_issue_code.dart index 529657e..021c4d6 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/codes/notices/scheduling_issue_code.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/codes/notices/scheduling_issue_code.dart @@ -1,14 +1,43 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduling_engine.dart'; /// Stable issue identifiers for validation, no-slot, and no-op notices. enum SchedulingIssueCode { + /// Selects the `taskNotFound` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. taskNotFound, + + /// Selects the `invalidTaskState` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidTaskState, + + /// Selects the `missingDuration` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. missingDuration, + + /// Selects the `missingScheduledSlot` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. missingScheduledSlot, + + /// Selects the `nonPositiveDuration` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. nonPositiveDuration, + + /// Selects the `noAvailableSlot` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. noAvailableSlot, + + /// Selects the `unfinishedTasksCouldNotFit` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. unfinishedTasksCouldNotFit, + + /// Selects the `noUnfinishedFlexibleTasks` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. noUnfinishedFlexibleTasks, + + /// Selects the `duplicateSurpriseLog` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. duplicateSurpriseLog, } diff --git a/packages/scheduler_core/lib/src/scheduling_engine/codes/notices/scheduling_notice_type.dart b/packages/scheduler_core/lib/src/scheduling_engine/codes/notices/scheduling_notice_type.dart index 0403491..14041bd 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/codes/notices/scheduling_notice_type.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/codes/notices/scheduling_notice_type.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduling_engine.dart'; /// Category for scheduler notices. diff --git a/packages/scheduler_core/lib/src/scheduling_engine/codes/operations/scheduling_movement_code.dart b/packages/scheduler_core/lib/src/scheduling_engine/codes/operations/scheduling_movement_code.dart index 1d91e4b..852bc61 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/codes/operations/scheduling_movement_code.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/codes/operations/scheduling_movement_code.dart @@ -1,12 +1,35 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduling_engine.dart'; /// Stable movement identifiers for task placement changes. enum SchedulingMovementCode { + /// Selects the `backlogTaskInserted` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. backlogTaskInserted, + + /// Selects the `flexibleTaskMovedToMakeRoom` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. flexibleTaskMovedToMakeRoom, + + /// Selects the `flexibleTaskPushedToNextAvailableSlot` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. flexibleTaskPushedToNextAvailableSlot, + + /// Selects the `flexibleTaskMovedToTomorrow` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. flexibleTaskMovedToTomorrow, + + /// Selects the `unfinishedFlexibleTasksRolledOver` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. unfinishedFlexibleTasksRolledOver, + + /// Selects the `flexibleTaskMovedToBacklog` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. flexibleTaskMovedToBacklog, + + /// Selects the `requiredCommitmentScheduled` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. requiredCommitmentScheduled, } diff --git a/packages/scheduler_core/lib/src/scheduling_engine/codes/operations/scheduling_operation_code.dart b/packages/scheduler_core/lib/src/scheduling_engine/codes/operations/scheduling_operation_code.dart index f24a19e..fa3b4e8 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/codes/operations/scheduling_operation_code.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/codes/operations/scheduling_operation_code.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduling_engine.dart'; /// Stable scheduler operation identifiers. diff --git a/packages/scheduler_core/lib/src/scheduling_engine/codes/operations/scheduling_outcome_code.dart b/packages/scheduler_core/lib/src/scheduling_engine/codes/operations/scheduling_outcome_code.dart index ecd5e38..e12a4b1 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/codes/operations/scheduling_outcome_code.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/codes/operations/scheduling_outcome_code.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduling_engine.dart'; /// Stable high-level outcome categories for scheduling operations. diff --git a/packages/scheduler_core/lib/src/scheduling_engine/engine/scheduling_engine.dart b/packages/scheduler_core/lib/src/scheduling_engine/engine/scheduling_engine.dart index d9646d8..abb5d5b 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/engine/scheduling_engine.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/engine/scheduling_engine.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../scheduling_engine.dart'; /// Starter scheduling engine. @@ -19,6 +22,8 @@ part of '../../scheduling_engine.dart'; /// - `queue` is the ordered set of flexible tasks that may be placed or shifted. /// - `placement` is a map from task id to the interval chosen by the planner. class SchedulingEngine { + /// Creates a `SchedulingEngine` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const SchedulingEngine({ this.clock = const SystemClock(), }); @@ -1227,6 +1232,8 @@ bool _sameDateTime(DateTime? first, DateTime? second) { return first.isAtSameMomentAs(second); } +/// Top-level helper that performs the `_applySchedulingActivity` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Task _applySchedulingActivity({ required Task originalTask, required Task updatedTask, diff --git a/packages/scheduler_core/lib/src/scheduling_engine/models/changes/scheduling_change.dart b/packages/scheduler_core/lib/src/scheduling_engine/models/changes/scheduling_change.dart index 81a576b..0b5e536 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/models/changes/scheduling_change.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/models/changes/scheduling_change.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduling_engine.dart'; /// Exact placement change made by a scheduling operation. @@ -6,6 +9,8 @@ part of '../../../scheduling_engine.dart'; /// display text, but persistence, undo, analytics, or tests should inspect these /// fields to know exactly which task moved and where. class SchedulingChange { + /// Creates a `SchedulingChange` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const SchedulingChange({ required this.taskId, required this.previousStart, diff --git a/packages/scheduler_core/lib/src/scheduling_engine/models/changes/scheduling_overlap.dart b/packages/scheduler_core/lib/src/scheduling_engine/models/changes/scheduling_overlap.dart index 98ce7e4..2d843ff 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/models/changes/scheduling_overlap.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/models/changes/scheduling_overlap.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduling_engine.dart'; /// Overlap between a scheduled task and blocked time. @@ -6,6 +9,8 @@ part of '../../../scheduling_engine.dart'; /// when loading persisted data, debugging imports, or validating a day before the /// UI presents it as clean. class SchedulingOverlap { + /// Creates a `SchedulingOverlap` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const SchedulingOverlap({ required this.taskId, required this.taskInterval, diff --git a/packages/scheduler_core/lib/src/scheduling_engine/models/inputs/scheduling_input.dart b/packages/scheduler_core/lib/src/scheduling_engine/models/inputs/scheduling_input.dart index 03c247b..98173a0 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/models/inputs/scheduling_input.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/models/inputs/scheduling_input.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduling_engine.dart'; /// In-memory input for scheduling operations. @@ -7,6 +10,8 @@ part of '../../../scheduling_engine.dart'; /// not know where the data came from: UI state, a database, tests, or generated /// examples can all build this same object. class SchedulingInput { + /// Creates a `SchedulingInput` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. SchedulingInput({ required List tasks, required this.window, diff --git a/packages/scheduler_core/lib/src/scheduling_engine/models/inputs/scheduling_window.dart b/packages/scheduler_core/lib/src/scheduling_engine/models/inputs/scheduling_window.dart index 61b9510..76c09dd 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/models/inputs/scheduling_window.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/models/inputs/scheduling_window.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduling_engine.dart'; /// Window of time available to a scheduling operation. @@ -7,6 +10,8 @@ part of '../../../scheduling_engine.dart'; /// flexible tasks can be placed. Anything outside this range is treated as out of /// scope for the operation. class SchedulingWindow { + /// Creates a `SchedulingWindow` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. SchedulingWindow({ required this.start, required this.end, diff --git a/packages/scheduler_core/lib/src/scheduling_engine/models/notices/scheduling_notice.dart b/packages/scheduler_core/lib/src/scheduling_engine/models/notices/scheduling_notice.dart index a6fcaa3..6f2fa1a 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/models/notices/scheduling_notice.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/models/notices/scheduling_notice.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduling_engine.dart'; /// Starter notice type returned by scheduling operations. @@ -6,6 +9,8 @@ part of '../../../scheduling_engine.dart'; /// carries both text and a structured [type] so the UI can decide whether to show /// it as neutral info, movement, overlap, or failure. class SchedulingNotice { + /// Creates a `SchedulingNotice` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. SchedulingNotice( this.message, { this.type = SchedulingNoticeType.info, diff --git a/packages/scheduler_core/lib/src/scheduling_engine/models/results/scheduling_result.dart b/packages/scheduler_core/lib/src/scheduling_engine/models/results/scheduling_result.dart index 6c56678..b133259 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/models/results/scheduling_result.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/models/results/scheduling_result.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduling_engine.dart'; /// Starter result wrapper for scheduling operations. @@ -6,6 +9,8 @@ part of '../../../scheduling_engine.dart'; /// This keeps the call pattern predictable: always inspect `tasks`, then surface /// any `notices`, `changes`, or `overlaps` relevant to the UI. class SchedulingResult { + /// Creates a `SchedulingResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. SchedulingResult({ required List tasks, this.operationCode = SchedulingOperationCode.unspecified, @@ -41,6 +46,8 @@ class SchedulingResult { final List overlaps; } +/// Top-level helper that performs the `_noticeCodesAreSinglePurpose` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _noticeCodesAreSinglePurpose(Iterable notices) { for (final notice in notices) { final codeCount = [ diff --git a/packages/scheduler_core/lib/src/scheduling_engine/planning/backlog_insertion_plan.dart b/packages/scheduler_core/lib/src/scheduling_engine/planning/backlog_insertion_plan.dart index 7783b18..f5c1fa7 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/planning/backlog_insertion_plan.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/planning/backlog_insertion_plan.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../scheduling_engine.dart'; /// Planned task intervals keyed by task id. @@ -6,6 +9,8 @@ part of '../../scheduling_engine.dart'; /// push and rollover placement plans. It remains private so it can be renamed or /// expanded later without affecting callers. class _BacklogInsertionPlan { + /// Creates a `_BacklogInsertionPlan` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _BacklogInsertionPlan({required this.placements}); /// Chosen interval for each task that should be scheduled or moved. diff --git a/packages/scheduler_core/lib/src/scheduling_engine/planning/placement_item.dart b/packages/scheduler_core/lib/src/scheduling_engine/planning/placement_item.dart index 68aa65d..702ac2c 100644 --- a/packages/scheduler_core/lib/src/scheduling_engine/planning/placement_item.dart +++ b/packages/scheduler_core/lib/src/scheduling_engine/planning/placement_item.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../scheduling_engine.dart'; /// One item in a placement queue. @@ -6,6 +9,8 @@ part of '../../scheduling_engine.dart'; /// scheduled tasks, this is usually their current start; for a pushed task, it is /// the earliest time the push operation allows. class _PlacementItem { + /// Creates a `_PlacementItem` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _PlacementItem({ required this.task, required this.duration, diff --git a/packages/scheduler_core/lib/src/task_actions.dart b/packages/scheduler_core/lib/src/task_actions.dart index 4fc18b6..580ff8a 100644 --- a/packages/scheduler_core/lib/src/task_actions.dart +++ b/packages/scheduler_core/lib/src/task_actions.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Task Actions behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/task_actions/actions/flexible_task_quick_action.dart b/packages/scheduler_core/lib/src/task_actions/actions/flexible_task_quick_action.dart index 209b06c..fe5ef3b 100644 --- a/packages/scheduler_core/lib/src/task_actions/actions/flexible_task_quick_action.dart +++ b/packages/scheduler_core/lib/src/task_actions/actions/flexible_task_quick_action.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_actions.dart'; /// Quick actions available from a flexible task card. diff --git a/packages/scheduler_core/lib/src/task_actions/actions/push_destination.dart b/packages/scheduler_core/lib/src/task_actions/actions/push_destination.dart index a811418..1131bac 100644 --- a/packages/scheduler_core/lib/src/task_actions/actions/push_destination.dart +++ b/packages/scheduler_core/lib/src/task_actions/actions/push_destination.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_actions.dart'; /// Explicit push destinations shown after choosing the push quick action. diff --git a/packages/scheduler_core/lib/src/task_actions/actions/required_task_action.dart b/packages/scheduler_core/lib/src/task_actions/actions/required_task_action.dart index 58187cf..7c565b8 100644 --- a/packages/scheduler_core/lib/src/task_actions/actions/required_task_action.dart +++ b/packages/scheduler_core/lib/src/task_actions/actions/required_task_action.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_actions.dart'; /// State transitions available from required visible task cards. diff --git a/packages/scheduler_core/lib/src/task_actions/requests/surprise_task_log_request.dart b/packages/scheduler_core/lib/src/task_actions/requests/surprise_task_log_request.dart index abe1b73..dcdabfc 100644 --- a/packages/scheduler_core/lib/src/task_actions/requests/surprise_task_log_request.dart +++ b/packages/scheduler_core/lib/src/task_actions/requests/surprise_task_log_request.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_actions.dart'; /// Input for logging work the user already did outside the plan. @@ -6,6 +9,8 @@ part of '../../task_actions.dart'; /// long it took. When time data is present, the resulting surprise task occupies /// that interval and flexible work overlapping it is pushed out of the way. class SurpriseTaskLogRequest { + /// Creates a `SurpriseTaskLogRequest` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const SurpriseTaskLogRequest({ required this.id, required this.title, diff --git a/packages/scheduler_core/lib/src/task_actions/results/flexible_task_action_result.dart b/packages/scheduler_core/lib/src/task_actions/results/flexible_task_action_result.dart index 829617a..0bcc94f 100644 --- a/packages/scheduler_core/lib/src/task_actions/results/flexible_task_action_result.dart +++ b/packages/scheduler_core/lib/src/task_actions/results/flexible_task_action_result.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_actions.dart'; /// Domain result for a flexible task quick action. @@ -6,6 +9,8 @@ part of '../../task_actions.dart'; /// must choose a push destination, or the UI should start the child-task flow. /// That keeps card code from guessing how to interpret each action. class FlexibleTaskActionResult { + /// Creates a `FlexibleTaskActionResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. FlexibleTaskActionResult({ required this.action, required this.task, diff --git a/packages/scheduler_core/lib/src/task_actions/results/push_destination_result.dart b/packages/scheduler_core/lib/src/task_actions/results/push_destination_result.dart index 8ef80d0..557cda9 100644 --- a/packages/scheduler_core/lib/src/task_actions/results/push_destination_result.dart +++ b/packages/scheduler_core/lib/src/task_actions/results/push_destination_result.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_actions.dart'; /// Result from applying a selected push destination. @@ -6,6 +9,8 @@ part of '../../task_actions.dart'; /// tests can distinguish "moved later today" from "moved to tomorrow" even if /// the low-level scheduling change shape is similar. class PushDestinationResult { + /// Creates a `PushDestinationResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. PushDestinationResult({ required this.destination, required this.schedulingResult, diff --git a/packages/scheduler_core/lib/src/task_actions/results/required_task_action_result.dart b/packages/scheduler_core/lib/src/task_actions/results/required_task_action_result.dart index d8d627f..c24e7e4 100644 --- a/packages/scheduler_core/lib/src/task_actions/results/required_task_action_result.dart +++ b/packages/scheduler_core/lib/src/task_actions/results/required_task_action_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_actions.dart'; /// Result from applying a required task state transition. class RequiredTaskActionResult { + /// Creates a `RequiredTaskActionResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. RequiredTaskActionResult({ required this.action, required this.task, diff --git a/packages/scheduler_core/lib/src/task_actions/results/surprise_task_log_result.dart b/packages/scheduler_core/lib/src/task_actions/results/surprise_task_log_result.dart index c5baec8..1b73a28 100644 --- a/packages/scheduler_core/lib/src/task_actions/results/surprise_task_log_result.dart +++ b/packages/scheduler_core/lib/src/task_actions/results/surprise_task_log_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_actions.dart'; /// Result from logging a surprise task. class SurpriseTaskLogResult { + /// Creates a `SurpriseTaskLogResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const SurpriseTaskLogResult({ required this.surpriseTask, required this.schedulingResult, diff --git a/packages/scheduler_core/lib/src/task_actions/services/flexible_task_action_service.dart b/packages/scheduler_core/lib/src/task_actions/services/flexible_task_action_service.dart index 8d84e50..12870b9 100644 --- a/packages/scheduler_core/lib/src/task_actions/services/flexible_task_action_service.dart +++ b/packages/scheduler_core/lib/src/task_actions/services/flexible_task_action_service.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_actions.dart'; /// Applies low-friction quick actions for flexible task cards. @@ -7,6 +10,8 @@ part of '../../task_actions.dart'; /// should have their own action rules so the UI cannot accidentally apply a /// flexible-only behavior to a fixed commitment. class FlexibleTaskActionService { + /// Creates a `FlexibleTaskActionService` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const FlexibleTaskActionService({ this.schedulingEngine = const SchedulingEngine(), this.transitionService = const TaskTransitionService(), diff --git a/packages/scheduler_core/lib/src/task_actions/services/required_task_action_service.dart b/packages/scheduler_core/lib/src/task_actions/services/required_task_action_service.dart index f9acabe..35874f2 100644 --- a/packages/scheduler_core/lib/src/task_actions/services/required_task_action_service.dart +++ b/packages/scheduler_core/lib/src/task_actions/services/required_task_action_service.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_actions.dart'; /// Applies lifecycle actions for required visible task cards. @@ -6,6 +9,8 @@ part of '../../task_actions.dart'; /// scheduling constraints, not normal task cards, and flexible tasks use /// [FlexibleTaskActionService]. class RequiredTaskActionService { + /// Creates a `RequiredTaskActionService` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const RequiredTaskActionService({ this.schedulingEngine = const SchedulingEngine(), this.transitionService = const TaskTransitionService(), diff --git a/packages/scheduler_core/lib/src/task_actions/services/surprise_task_log_service.dart b/packages/scheduler_core/lib/src/task_actions/services/surprise_task_log_service.dart index a49b4d9..7af04ec 100644 --- a/packages/scheduler_core/lib/src/task_actions/services/surprise_task_log_service.dart +++ b/packages/scheduler_core/lib/src/task_actions/services/surprise_task_log_service.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_actions.dart'; /// Logs surprise completed work and repairs affected flexible tasks. @@ -7,6 +10,8 @@ part of '../../task_actions.dart'; /// the existing push scheduler with the surprise interval treated as blocked /// time. Required visible and locked time is never moved. class SurpriseTaskLogService { + /// Creates a `SurpriseTaskLogService` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const SurpriseTaskLogService({ this.schedulingEngine = const SchedulingEngine(), this.accountingService = const TaskActivityAccountingService(), @@ -214,6 +219,8 @@ class SurpriseTaskLogService { ); } + /// Runs the `_createSurpriseTask` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. Task _createSurpriseTask( SurpriseTaskLogRequest request, { required DateTime updatedAt, @@ -250,6 +257,8 @@ class SurpriseTaskLogService { } } +/// Top-level helper that performs the `_activitiesForPushDestination` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _activitiesForPushDestination({ required PushDestination destination, required SchedulingInput input, @@ -308,6 +317,8 @@ List _activitiesForPushDestination({ return List.unmodifiable(activities); } +/// Top-level helper that performs the `_activityCodeForPushChange` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TaskActivityCode _activityCodeForPushChange({ required PushDestination destination, required bool isSelectedTask, @@ -321,6 +332,8 @@ TaskActivityCode _activityCodeForPushChange({ : TaskActivityCode.automaticallyPushed; } +/// Top-level helper that performs the `_operationCodeForPushDestination` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. SchedulingOperationCode _operationCodeForPushDestination( PushDestination destination, ) { @@ -334,6 +347,8 @@ SchedulingOperationCode _operationCodeForPushDestination( }; } +/// Top-level helper that performs the `_surpriseCompletedActivity` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TaskActivity _surpriseCompletedActivity({ required Task task, required String operationId, @@ -362,6 +377,8 @@ TaskActivity _surpriseCompletedActivity({ ); } +/// Top-level helper that performs the `_lockedIntervalsForAccounting` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _lockedIntervalsForAccounting(SchedulingInput input) { return input.occupancyEntries .where( @@ -372,6 +389,8 @@ List _lockedIntervalsForAccounting(SchedulingInput input) { .toList(growable: false); } +/// Top-level helper that performs the `_hasDuplicateActivity` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _hasDuplicateActivity({ required Iterable existingActivities, required String operationId, @@ -386,11 +405,15 @@ bool _hasDuplicateActivity({ return false; } +/// Top-level helper that performs the `_defaultOperationId` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _defaultOperationId( String actionName, String taskId, DateTime occurredAt) { return '$actionName:$taskId:${occurredAt.toIso8601String()}'; } +/// Top-level helper that performs the `_activityId` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _activityId( String operationId, String taskId, diff --git a/packages/scheduler_core/lib/src/task_lifecycle.dart b/packages/scheduler_core/lib/src/task_lifecycle.dart index 91977ea..7356540 100644 --- a/packages/scheduler_core/lib/src/task_lifecycle.dart +++ b/packages/scheduler_core/lib/src/task_lifecycle.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Task Lifecycle behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/task_lifecycle/codes/task_activity_code.dart b/packages/scheduler_core/lib/src/task_lifecycle/codes/task_activity_code.dart index 1bb9d66..0af7725 100644 --- a/packages/scheduler_core/lib/src/task_lifecycle/codes/task_activity_code.dart +++ b/packages/scheduler_core/lib/src/task_lifecycle/codes/task_activity_code.dart @@ -1,14 +1,43 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_lifecycle.dart'; /// Stable internal activity categories derived from transitions. enum TaskActivityCode { + /// Selects the `completed` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. completed, + + /// Selects the `missed` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. missed, + + /// Selects the `cancelled` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. cancelled, + + /// Selects the `noLongerRelevant` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. noLongerRelevant, + + /// Selects the `manuallyPushed` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. manuallyPushed, + + /// Selects the `automaticallyPushed` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. automaticallyPushed, + + /// Selects the `movedToBacklog` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. movedToBacklog, + + /// Selects the `restoredFromBacklog` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. restoredFromBacklog, + + /// Selects the `activated` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. activated, } diff --git a/packages/scheduler_core/lib/src/task_lifecycle/codes/task_transition_code.dart b/packages/scheduler_core/lib/src/task_lifecycle/codes/task_transition_code.dart index 5a98cca..2a37721 100644 --- a/packages/scheduler_core/lib/src/task_lifecycle/codes/task_transition_code.dart +++ b/packages/scheduler_core/lib/src/task_lifecycle/codes/task_transition_code.dart @@ -1,14 +1,43 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_lifecycle.dart'; /// Canonical task transition commands. enum TaskTransitionCode { + /// Selects the `complete` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. complete, + + /// Selects the `miss` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. miss, + + /// Selects the `cancel` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. cancel, + + /// Selects the `noLongerRelevant` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. noLongerRelevant, + + /// Selects the `manualPush` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. manualPush, + + /// Selects the `automaticPush` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. automaticPush, + + /// Selects the `moveToBacklog` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. moveToBacklog, + + /// Selects the `restoreFromBacklog` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. restoreFromBacklog, + + /// Selects the `activate` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. activate, } diff --git a/packages/scheduler_core/lib/src/task_lifecycle/codes/task_transition_outcome_code.dart b/packages/scheduler_core/lib/src/task_lifecycle/codes/task_transition_outcome_code.dart index 359f87c..4d3298b 100644 --- a/packages/scheduler_core/lib/src/task_lifecycle/codes/task_transition_outcome_code.dart +++ b/packages/scheduler_core/lib/src/task_lifecycle/codes/task_transition_outcome_code.dart @@ -1,9 +1,23 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_lifecycle.dart'; /// Typed result categories for expected transition states. enum TaskTransitionOutcomeCode { + /// Selects the `applied` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. applied, + + /// Selects the `noOp` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. noOp, + + /// Selects the `duplicateOperation` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. duplicateOperation, + + /// Selects the `invalidState` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. invalidState, } diff --git a/packages/scheduler_core/lib/src/task_lifecycle/models/task_activity.dart b/packages/scheduler_core/lib/src/task_lifecycle/models/task_activity.dart index 0cd1214..4937f75 100644 --- a/packages/scheduler_core/lib/src/task_lifecycle/models/task_activity.dart +++ b/packages/scheduler_core/lib/src/task_lifecycle/models/task_activity.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_lifecycle.dart'; /// Immutable internal activity fact. @@ -6,6 +9,8 @@ part of '../../task_lifecycle.dart'; /// They carry enough stable structure for idempotency, statistics, and future /// persistence adapters. class TaskActivity { + /// Creates a `TaskActivity` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. TaskActivity({ required String id, required String operationId, diff --git a/packages/scheduler_core/lib/src/task_lifecycle/models/task_activity_application_result.dart b/packages/scheduler_core/lib/src/task_lifecycle/models/task_activity_application_result.dart index 5ff72f2..6c46629 100644 --- a/packages/scheduler_core/lib/src/task_lifecycle/models/task_activity_application_result.dart +++ b/packages/scheduler_core/lib/src/task_lifecycle/models/task_activity_application_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_lifecycle.dart'; /// Result of applying activity-derived task statistics. class TaskActivityApplicationResult { + /// Creates a `TaskActivityApplicationResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. TaskActivityApplicationResult({ required this.task, List appliedActivityIds = const [], diff --git a/packages/scheduler_core/lib/src/task_lifecycle/models/task_transition_result.dart b/packages/scheduler_core/lib/src/task_lifecycle/models/task_transition_result.dart index c204f02..4d0b409 100644 --- a/packages/scheduler_core/lib/src/task_lifecycle/models/task_transition_result.dart +++ b/packages/scheduler_core/lib/src/task_lifecycle/models/task_transition_result.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_lifecycle.dart'; /// Result of applying one canonical transition. class TaskTransitionResult { + /// Creates a `TaskTransitionResult` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. TaskTransitionResult({ required this.transitionCode, required this.outcomeCode, diff --git a/packages/scheduler_core/lib/src/task_lifecycle/services/task_activity_accounting_service.dart b/packages/scheduler_core/lib/src/task_lifecycle/services/task_activity_accounting_service.dart index ab9970e..68cbe47 100644 --- a/packages/scheduler_core/lib/src/task_lifecycle/services/task_activity_accounting_service.dart +++ b/packages/scheduler_core/lib/src/task_lifecycle/services/task_activity_accounting_service.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_lifecycle.dart'; /// Applies task-statistic effects from internal activities exactly once. class TaskActivityAccountingService { + /// Creates a `TaskActivityAccountingService` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const TaskActivityAccountingService(); /// Apply [activities] to [task], skipping ids already present in diff --git a/packages/scheduler_core/lib/src/task_lifecycle/services/task_transition_service.dart b/packages/scheduler_core/lib/src/task_lifecycle/services/task_transition_service.dart index a6fdef2..3425815 100644 --- a/packages/scheduler_core/lib/src/task_lifecycle/services/task_transition_service.dart +++ b/packages/scheduler_core/lib/src/task_lifecycle/services/task_transition_service.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../task_lifecycle.dart'; /// Canonical lifecycle transition service. class TaskTransitionService { + /// Creates a `TaskTransitionService` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const TaskTransitionService({ this.clock = const SystemClock(), this.accountingService = const TaskActivityAccountingService(), @@ -153,6 +158,8 @@ class TaskTransitionService { }; } + /// Runs the `_complete` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. TaskTransitionResult _complete({ required Task task, required String operationId, @@ -216,6 +223,8 @@ class TaskTransitionService { ); } + /// Runs the `_miss` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. TaskTransitionResult _miss({ required Task task, required String operationId, @@ -283,6 +292,8 @@ class TaskTransitionService { ); } + /// Runs the `_cancel` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. TaskTransitionResult _cancel({ required Task task, required String operationId, @@ -327,6 +338,8 @@ class TaskTransitionService { ); } + /// Runs the `_noLongerRelevant` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. TaskTransitionResult _noLongerRelevant({ required Task task, required String operationId, @@ -372,6 +385,8 @@ class TaskTransitionService { ); } + /// Runs the `_movementOnly` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. TaskTransitionResult _movementOnly({ required Task task, required TaskTransitionCode transitionCode, @@ -411,6 +426,8 @@ class TaskTransitionService { ); } + /// Runs the `_moveToBacklog` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. TaskTransitionResult _moveToBacklog({ required Task task, required String operationId, @@ -454,6 +471,8 @@ class TaskTransitionService { ); } + /// Runs the `_restoreFromBacklog` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. TaskTransitionResult _restoreFromBacklog({ required Task task, required String operationId, @@ -495,6 +514,8 @@ class TaskTransitionService { ); } + /// Runs the `_activate` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. TaskTransitionResult _activate({ required Task task, required String operationId, @@ -540,6 +561,8 @@ class TaskTransitionService { } } +/// Top-level helper that performs the `_applyActivityStats` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TaskStatistics _applyActivityStats({ required Task task, required TaskActivity activity, @@ -564,6 +587,8 @@ TaskStatistics _applyActivityStats({ }; } +/// Top-level helper that performs the `_applyCompletionStats` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TaskStatistics _applyCompletionStats({ required Task task, required TaskActivity activity, @@ -592,6 +617,8 @@ TaskStatistics _applyCompletionStats({ return stats.recordPushesBeforeCompletion(pushesBeforeCompletion); } +/// Top-level helper that performs the `_actualLockedOverlapMinutes` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _actualLockedOverlapMinutes({ required Task task, required List lockedIntervals, @@ -644,10 +671,14 @@ int _actualLockedOverlapMinutes({ return total.inMinutes; } +/// Top-level helper that performs the `_pushesBeforeCompletion` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _pushesBeforeCompletion(Task task) { return task.stats.manuallyPushedCount + task.stats.autoPushedCount; } +/// Top-level helper that performs the `_knownDurationMinutes` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int? _knownDurationMinutes( Task task, DateTime? actualStart, @@ -665,18 +696,26 @@ int? _knownDurationMinutes( return task.durationMinutes; } +/// Top-level helper that performs the `_intMetadata` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int? _intMetadata(Object? value) { return value is int ? value : null; } +/// Top-level helper that performs the `_earliest` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. DateTime _earliest(DateTime first, DateTime second) { return first.isBefore(second) ? first : second; } +/// Top-level helper that performs the `_latest` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. DateTime _latest(DateTime first, DateTime second) { return first.isAfter(second) ? first : second; } +/// Top-level helper that performs the `_applied` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TaskTransitionResult _applied({ required TaskTransitionCode transitionCode, required Task task, @@ -690,6 +729,8 @@ TaskTransitionResult _applied({ ); } +/// Top-level helper that performs the `_invalid` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TaskTransitionResult _invalid(Task task, TaskTransitionCode transitionCode) { return TaskTransitionResult( transitionCode: transitionCode, @@ -698,6 +739,8 @@ TaskTransitionResult _invalid(Task task, TaskTransitionCode transitionCode) { ); } +/// Top-level helper that performs the `_noOp` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TaskTransitionResult _noOp(Task task, TaskTransitionCode transitionCode) { return TaskTransitionResult( transitionCode: transitionCode, @@ -706,6 +749,8 @@ TaskTransitionResult _noOp(Task task, TaskTransitionCode transitionCode) { ); } +/// Top-level helper that performs the `_activity` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TaskActivity _activity({ required String id, required String operationId, @@ -730,6 +775,8 @@ TaskActivity _activity({ ); } +/// Top-level helper that performs the `_duplicateActivity` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TaskActivity? _duplicateActivity({ required Iterable existingActivities, required String taskId, @@ -744,6 +791,8 @@ TaskActivity? _duplicateActivity({ return null; } +/// Top-level helper that performs the `_actualIntervalShapeIsValid` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _actualIntervalShapeIsValid(DateTime? actualStart, DateTime? actualEnd) { if (actualStart == null && actualEnd == null) { return true; @@ -753,6 +802,8 @@ bool _actualIntervalShapeIsValid(DateTime? actualStart, DateTime? actualEnd) { actualStart.isBefore(actualEnd); } +/// Top-level helper that performs the `_isNoOpTerminalRepeat` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _isNoOpTerminalRepeat(Task task, TaskTransitionCode transitionCode) { return (task.status == TaskStatus.completed && transitionCode == TaskTransitionCode.complete) || @@ -762,6 +813,8 @@ bool _isNoOpTerminalRepeat(Task task, TaskTransitionCode transitionCode) { transitionCode == TaskTransitionCode.noLongerRelevant); } +/// Top-level helper that performs the `_isBlockedByTerminalState` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _isBlockedByTerminalState(Task task, TaskTransitionCode transitionCode) { if (!_isTerminal(task.status)) { return false; @@ -769,12 +822,16 @@ bool _isBlockedByTerminalState(Task task, TaskTransitionCode transitionCode) { return !_isNoOpTerminalRepeat(task, transitionCode); } +/// Top-level helper that performs the `_isTerminal` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _isTerminal(TaskStatus status) { return status == TaskStatus.completed || status == TaskStatus.cancelled || status == TaskStatus.noLongerRelevant; } +/// Top-level helper that performs the `_canRemoveFromActivePlan` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _canRemoveFromActivePlan(Task task) { return task.status == TaskStatus.planned || task.status == TaskStatus.active || @@ -782,6 +839,8 @@ bool _canRemoveFromActivePlan(Task task) { task.status == TaskStatus.missed; } +/// Top-level helper that performs the `_requiredTrimmed` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredTrimmed(String value, String name) { final trimmed = value.trim(); if (trimmed.isEmpty) { diff --git a/packages/scheduler_core/lib/src/task_statistics.dart b/packages/scheduler_core/lib/src/task_statistics.dart index c48b4bd..3240a07 100644 --- a/packages/scheduler_core/lib/src/task_statistics.dart +++ b/packages/scheduler_core/lib/src/task_statistics.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Task Statistics behavior for the Scheduler Core package. library; @@ -19,6 +22,8 @@ library; /// [TaskStatistics] value so calling code can update a task through `copyWith` /// while retaining predictable before/after behavior. class TaskStatistics { + /// Creates a `TaskStatistics` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const TaskStatistics({ this.skippedDuringBurnoutCount = 0, this.manuallyPushedCount = 0, diff --git a/packages/scheduler_core/lib/src/time_contracts.dart b/packages/scheduler_core/lib/src/time_contracts.dart index b2f4dcd..7e50e7c 100644 --- a/packages/scheduler_core/lib/src/time_contracts.dart +++ b/packages/scheduler_core/lib/src/time_contracts.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Time Contracts behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/time_contracts/civil/civil_date.dart b/packages/scheduler_core/lib/src/time_contracts/civil/civil_date.dart index a385d78..8142bfb 100644 --- a/packages/scheduler_core/lib/src/time_contracts/civil/civil_date.dart +++ b/packages/scheduler_core/lib/src/time_contracts/civil/civil_date.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../time_contracts.dart'; /// Calendar date without a time or timezone. class CivilDate implements Comparable { + /// Creates a `CivilDate` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. CivilDate(this.year, this.month, this.day) { final normalized = DateTime.utc(year, month, day); if (normalized.year != year || @@ -16,10 +21,14 @@ class CivilDate implements Comparable { } } + /// Creates a `CivilDate.fromDateTime` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. factory CivilDate.fromDateTime(DateTime value) { return CivilDate(value.year, value.month, value.day); } + /// Creates a `CivilDate.fromIsoString` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. factory CivilDate.fromIsoString(String value) { if (!RegExp(r'^\d{4}-\d{2}-\d{2}$').hasMatch(value)) { throw DomainValidationException( @@ -37,23 +46,39 @@ class CivilDate implements Comparable { ); } + /// Stores the `year` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int year; + + /// Stores the `month` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int month; + + /// Stores the `day` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int day; + /// Returns the derived `weekday` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. int get weekday => DateTime.utc(year, month, day).weekday; + /// Performs the `addDays` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. CivilDate addDays(int days) { final shifted = DateTime.utc(year, month, day).add(Duration(days: days)); return CivilDate(shifted.year, shifted.month, shifted.day); } + /// Converts scheduler data for `toIsoString` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. String toIsoString() { final monthText = month.toString().padLeft(2, '0'); final dayText = day.toString().padLeft(2, '0'); return '$year-$monthText-$dayText'; } + /// Performs the `compareTo` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override int compareTo(CivilDate other) { final yearComparison = year.compareTo(other.year); @@ -67,6 +92,8 @@ class CivilDate implements Comparable { return day.compareTo(other.day); } + /// Performs the `operator ==` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override bool operator ==(Object other) { return other is CivilDate && @@ -75,9 +102,13 @@ class CivilDate implements Comparable { other.day == day; } + /// Returns the derived `hashCode` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override int get hashCode => Object.hash(year, month, day); + /// Converts scheduler data for `toString` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. @override String toString() => toIsoString(); } diff --git a/packages/scheduler_core/lib/src/time_contracts/civil/wall_time.dart b/packages/scheduler_core/lib/src/time_contracts/civil/wall_time.dart index 2a32686..37656b5 100644 --- a/packages/scheduler_core/lib/src/time_contracts/civil/wall_time.dart +++ b/packages/scheduler_core/lib/src/time_contracts/civil/wall_time.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../time_contracts.dart'; /// Wall-clock time without a date or timezone. class WallTime implements Comparable { + /// Creates a `WallTime` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. WallTime({ required this.hour, required this.minute, @@ -16,6 +21,8 @@ class WallTime implements Comparable { } } + /// Creates a `WallTime.fromIsoString` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. factory WallTime.fromIsoString(String value) { if (!RegExp(r'^\d{2}:\d{2}$').hasMatch(value)) { throw DomainValidationException( @@ -29,29 +36,46 @@ class WallTime implements Comparable { return WallTime(hour: int.parse(parts[0]), minute: int.parse(parts[1])); } + /// Stores the `hour` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int hour; + + /// Stores the `minute` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int minute; + /// Returns the derived `minutesSinceMidnight` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. int get minutesSinceMidnight => hour * 60 + minute; + /// Converts scheduler data for `toIsoString` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. String toIsoString() { return '${hour.toString().padLeft(2, '0')}:' '${minute.toString().padLeft(2, '0')}'; } + /// Performs the `compareTo` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override int compareTo(WallTime other) { return minutesSinceMidnight.compareTo(other.minutesSinceMidnight); } + /// Performs the `operator ==` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override bool operator ==(Object other) { return other is WallTime && other.hour == hour && other.minute == minute; } + /// Returns the derived `hashCode` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override int get hashCode => Object.hash(hour, minute); + /// Converts scheduler data for `toString` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. @override String toString() => toIsoString(); } diff --git a/packages/scheduler_core/lib/src/time_contracts/clocks/clock.dart b/packages/scheduler_core/lib/src/time_contracts/clocks/clock.dart index 70600d6..3a6cc52 100644 --- a/packages/scheduler_core/lib/src/time_contracts/clocks/clock.dart +++ b/packages/scheduler_core/lib/src/time_contracts/clocks/clock.dart @@ -1,6 +1,11 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../time_contracts.dart'; /// Deterministic source of the current instant. abstract interface class Clock { + /// Performs the `now` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. DateTime now(); } diff --git a/packages/scheduler_core/lib/src/time_contracts/clocks/fixed_clock.dart b/packages/scheduler_core/lib/src/time_contracts/clocks/fixed_clock.dart index 00dad8c..0a0d9b6 100644 --- a/packages/scheduler_core/lib/src/time_contracts/clocks/fixed_clock.dart +++ b/packages/scheduler_core/lib/src/time_contracts/clocks/fixed_clock.dart @@ -1,11 +1,20 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../time_contracts.dart'; /// Test/application clock with a fixed instant. class FixedClock implements Clock { + /// Creates a `FixedClock` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const FixedClock(this.instant); + /// Stores the `instant` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DateTime instant; + /// Performs the `now` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override DateTime now() => instant; } diff --git a/packages/scheduler_core/lib/src/time_contracts/clocks/system_clock.dart b/packages/scheduler_core/lib/src/time_contracts/clocks/system_clock.dart index 12b4468..7fd3314 100644 --- a/packages/scheduler_core/lib/src/time_contracts/clocks/system_clock.dart +++ b/packages/scheduler_core/lib/src/time_contracts/clocks/system_clock.dart @@ -1,10 +1,17 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../time_contracts.dart'; /// Production clock boundary. Domain services should receive this through /// constructors rather than reading wall time directly. class SystemClock implements Clock { + /// Creates a `SystemClock` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const SystemClock(); + /// Performs the `now` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override DateTime now() => DateTime.now(); } diff --git a/packages/scheduler_core/lib/src/time_contracts/ids/id_generator.dart b/packages/scheduler_core/lib/src/time_contracts/ids/id_generator.dart index e85fca0..f6ba0ee 100644 --- a/packages/scheduler_core/lib/src/time_contracts/ids/id_generator.dart +++ b/packages/scheduler_core/lib/src/time_contracts/ids/id_generator.dart @@ -1,6 +1,11 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../time_contracts.dart'; /// Deterministic ID source for application/domain convenience entry points. abstract interface class IdGenerator { + /// Performs the `nextId` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. String nextId(); } diff --git a/packages/scheduler_core/lib/src/time_contracts/ids/sequential_id_generator.dart b/packages/scheduler_core/lib/src/time_contracts/ids/sequential_id_generator.dart index 6270506..6b886fa 100644 --- a/packages/scheduler_core/lib/src/time_contracts/ids/sequential_id_generator.dart +++ b/packages/scheduler_core/lib/src/time_contracts/ids/sequential_id_generator.dart @@ -1,15 +1,27 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../time_contracts.dart'; /// Simple deterministic ID generator useful for tests and local wiring. class SequentialIdGenerator implements IdGenerator { + /// Creates a `SequentialIdGenerator` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. SequentialIdGenerator({ this.prefix = 'id', int start = 1, }) : _next = start; + /// Stores the `prefix` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String prefix; + + /// Private state stored as `_next` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. int _next; + /// Performs the `nextId` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override String nextId() { final id = '$prefix-$_next'; diff --git a/packages/scheduler_core/lib/src/time_contracts/zones/policies/nonexistent_local_time_policy.dart b/packages/scheduler_core/lib/src/time_contracts/zones/policies/nonexistent_local_time_policy.dart index d208544..638c336 100644 --- a/packages/scheduler_core/lib/src/time_contracts/zones/policies/nonexistent_local_time_policy.dart +++ b/packages/scheduler_core/lib/src/time_contracts/zones/policies/nonexistent_local_time_policy.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../time_contracts.dart'; +/// Closed set of `NonexistentLocalTimePolicy` choices used by the pure scheduler domain package. +/// Using named enum values keeps scheduling, persistence, and UI branching explicit instead of passing raw strings through the codebase. enum NonexistentLocalTimePolicy { /// Move through a daylight-saving gap to the first valid local instant after it. shiftForward, diff --git a/packages/scheduler_core/lib/src/time_contracts/zones/policies/repeated_local_time_policy.dart b/packages/scheduler_core/lib/src/time_contracts/zones/policies/repeated_local_time_policy.dart index 57aab99..df15935 100644 --- a/packages/scheduler_core/lib/src/time_contracts/zones/policies/repeated_local_time_policy.dart +++ b/packages/scheduler_core/lib/src/time_contracts/zones/policies/repeated_local_time_policy.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../time_contracts.dart'; +/// Closed set of `RepeatedLocalTimePolicy` choices used by the pure scheduler domain package. +/// Using named enum values keeps scheduling, persistence, and UI branching explicit instead of passing raw strings through the codebase. enum RepeatedLocalTimePolicy { /// Use the first instant for a repeated local time during a fall-back transition. earlier, diff --git a/packages/scheduler_core/lib/src/time_contracts/zones/policies/time_zone_resolution_options.dart b/packages/scheduler_core/lib/src/time_contracts/zones/policies/time_zone_resolution_options.dart index 867f2a0..94244a2 100644 --- a/packages/scheduler_core/lib/src/time_contracts/zones/policies/time_zone_resolution_options.dart +++ b/packages/scheduler_core/lib/src/time_contracts/zones/policies/time_zone_resolution_options.dart @@ -1,11 +1,23 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../time_contracts.dart'; +/// Represents `TimeZoneResolutionOptions` within the pure scheduler domain package. +/// The type groups related data and behavior behind a named API so readers can understand this part of the scheduler without relying on tribal knowledge about the surrounding files. class TimeZoneResolutionOptions { + /// Creates a `TimeZoneResolutionOptions` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const TimeZoneResolutionOptions({ this.nonexistentLocalTimePolicy = NonexistentLocalTimePolicy.shiftForward, this.repeatedLocalTimePolicy = RepeatedLocalTimePolicy.earlier, }); + /// Stores the `nonexistentLocalTimePolicy` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final NonexistentLocalTimePolicy nonexistentLocalTimePolicy; + + /// Stores the `repeatedLocalTimePolicy` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final RepeatedLocalTimePolicy repeatedLocalTimePolicy; } diff --git a/packages/scheduler_core/lib/src/time_contracts/zones/resolution/local_time_resolution.dart b/packages/scheduler_core/lib/src/time_contracts/zones/resolution/local_time_resolution.dart index cd43a75..0d49cfc 100644 --- a/packages/scheduler_core/lib/src/time_contracts/zones/resolution/local_time_resolution.dart +++ b/packages/scheduler_core/lib/src/time_contracts/zones/resolution/local_time_resolution.dart @@ -1,8 +1,24 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../time_contracts.dart'; +/// Closed set of `LocalTimeResolution` choices used by the pure scheduler domain package. +/// Using named enum values keeps scheduling, persistence, and UI branching explicit instead of passing raw strings through the codebase. enum LocalTimeResolution { + /// Selects the `exact` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. exact, + + /// Selects the `shiftedForward` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. shiftedForward, + + /// Selects the `repeatedEarlier` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. repeatedEarlier, + + /// Selects the `repeatedLater` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. repeatedLater, } diff --git a/packages/scheduler_core/lib/src/time_contracts/zones/resolution/resolved_local_date_time.dart b/packages/scheduler_core/lib/src/time_contracts/zones/resolution/resolved_local_date_time.dart index 8eb18e0..d1d3bd7 100644 --- a/packages/scheduler_core/lib/src/time_contracts/zones/resolution/resolved_local_date_time.dart +++ b/packages/scheduler_core/lib/src/time_contracts/zones/resolution/resolved_local_date_time.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../time_contracts.dart'; +/// Represents `ResolvedLocalDateTime` within the pure scheduler domain package. +/// The type groups related data and behavior behind a named API so readers can understand this part of the scheduler without relying on tribal knowledge about the surrounding files. class ResolvedLocalDateTime { + /// Creates a `ResolvedLocalDateTime` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const ResolvedLocalDateTime({ required this.date, required this.wallTime, @@ -10,10 +17,27 @@ class ResolvedLocalDateTime { required this.utcOffset, }); + /// Stores the `date` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final CivilDate date; + + /// Stores the `wallTime` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final WallTime wallTime; + + /// Stores the `timeZoneId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String timeZoneId; + + /// Stores the `instant` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DateTime instant; + + /// Stores the `resolution` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final LocalTimeResolution resolution; + + /// Stores the `utcOffset` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Duration utcOffset; } diff --git a/packages/scheduler_core/lib/src/time_contracts/zones/resolvers/fixed_offset_time_zone_resolver.dart b/packages/scheduler_core/lib/src/time_contracts/zones/resolvers/fixed_offset_time_zone_resolver.dart index 11d519d..04f77eb 100644 --- a/packages/scheduler_core/lib/src/time_contracts/zones/resolvers/fixed_offset_time_zone_resolver.dart +++ b/packages/scheduler_core/lib/src/time_contracts/zones/resolvers/fixed_offset_time_zone_resolver.dart @@ -1,13 +1,24 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../time_contracts.dart'; /// Resolver for zones whose offset is already known by the application boundary. class FixedOffsetTimeZoneResolver implements TimeZoneResolver { + /// Creates a `FixedOffsetTimeZoneResolver.utc` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const FixedOffsetTimeZoneResolver.utc() : offset = Duration.zero; + /// Creates a `FixedOffsetTimeZoneResolver` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const FixedOffsetTimeZoneResolver({required this.offset}); + /// Stores the `offset` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Duration offset; + /// Performs the `resolve` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override ResolvedLocalDateTime resolve({ required CivilDate date, diff --git a/packages/scheduler_core/lib/src/time_contracts/zones/resolvers/time_zone_resolver.dart b/packages/scheduler_core/lib/src/time_contracts/zones/resolvers/time_zone_resolver.dart index efe4bed..b948e6a 100644 --- a/packages/scheduler_core/lib/src/time_contracts/zones/resolvers/time_zone_resolver.dart +++ b/packages/scheduler_core/lib/src/time_contracts/zones/resolvers/time_zone_resolver.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../time_contracts.dart'; /// Boundary for converting local civil date/time values to instants. abstract interface class TimeZoneResolver { + /// Performs the `resolve` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. ResolvedLocalDateTime resolve({ required CivilDate date, required WallTime wallTime, diff --git a/packages/scheduler_core/lib/src/timeline_state.dart b/packages/scheduler_core/lib/src/timeline_state.dart index 9f582b5..d29d8aa 100644 --- a/packages/scheduler_core/lib/src/timeline_state.dart +++ b/packages/scheduler_core/lib/src/timeline_state.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Timeline State behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/timeline_state/mapping/timeline_item_mapper.dart b/packages/scheduler_core/lib/src/timeline_state/mapping/timeline_item_mapper.dart index d2283e7..4d4a927 100644 --- a/packages/scheduler_core/lib/src/timeline_state/mapping/timeline_item_mapper.dart +++ b/packages/scheduler_core/lib/src/timeline_state/mapping/timeline_item_mapper.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../timeline_state.dart'; /// Converts domain tasks into Today timeline items. class TimelineItemMapper { + /// Creates a `TimelineItemMapper` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. TimelineItemMapper({ Map projectColorTokensById = const {}, }) : projectColorTokensById = @@ -131,6 +136,8 @@ class TimelineItemMapper { ); } + /// Runs the `_canAppearInCompactMode` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. bool _canAppearInCompactMode(Task task) { return !task.isLocked && task.status != TaskStatus.backlog && @@ -141,6 +148,8 @@ class TimelineItemMapper { task.scheduledEnd != null; } + /// Runs the `_containsTime` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. bool _containsTime(Task task, DateTime now) { final start = task.scheduledStart; final end = task.scheduledEnd; @@ -150,11 +159,15 @@ class TimelineItemMapper { return !now.isBefore(start) && now.isBefore(end); } + /// Runs the `_startsAtOrAfter` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. bool _startsAtOrAfter(Task task, DateTime now) { final start = task.scheduledStart; return start != null && !start.isBefore(now); } + /// Runs the `_compareTasksByStart` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. int _compareTasksByStart(Task left, Task right) { final leftStart = left.scheduledStart; final rightStart = right.scheduledStart; @@ -170,6 +183,8 @@ class TimelineItemMapper { return leftStart.compareTo(rightStart); } + /// Runs the `_lockedOccurrenceId` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. String _lockedOccurrenceId( LockedBlockOccurrence occurrence, { CivilDate? occurrenceDate, @@ -188,6 +203,8 @@ class TimelineItemMapper { '${occurrence.interval.start.toIso8601String()}'; } + /// Runs the `_projectColorTokenFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. String _projectColorTokenFor(String? projectId) { if (projectId == null) { return 'locked'; @@ -195,12 +212,16 @@ class TimelineItemMapper { return projectColorTokensById[projectId] ?? projectId; } + /// Runs the `_showsExplicitTime` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. bool _showsExplicitTime(TaskType type) { return type == TaskType.inflexible || type == TaskType.critical || type == TaskType.locked; } + /// Runs the `_durationMinutesFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. int? _durationMinutesFor(Task task) { if (!task.isFlexible) { return null; @@ -216,6 +237,8 @@ class TimelineItemMapper { return end.difference(start).inMinutes; } + /// Runs the `_quickActionsFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. List _quickActionsFor(TaskType type) { switch (type) { case TaskType.flexible: @@ -240,6 +263,8 @@ class TimelineItemMapper { } } + /// Runs the `_backgroundTokenFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. TimelineBackgroundToken _backgroundTokenFor(TaskType type) { switch (type) { case TaskType.flexible: @@ -257,6 +282,8 @@ class TimelineItemMapper { } } + /// Runs the `_rewardIconTokenFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. TimelineRewardIconToken _rewardIconTokenFor(RewardLevel reward) { switch (reward) { case RewardLevel.notSet: @@ -274,6 +301,8 @@ class TimelineItemMapper { } } + /// Runs the `_difficultyIconTokenFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. TimelineDifficultyIconToken _difficultyIconTokenFor( DifficultyLevel difficulty, ) { diff --git a/packages/scheduler_core/lib/src/timeline_state/models/compact_timeline_state.dart b/packages/scheduler_core/lib/src/timeline_state/models/compact_timeline_state.dart index bf3615d..d9a6b50 100644 --- a/packages/scheduler_core/lib/src/timeline_state/models/compact_timeline_state.dart +++ b/packages/scheduler_core/lib/src/timeline_state/models/compact_timeline_state.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../timeline_state.dart'; /// Reduced Today timeline state for manual compact mode. class CompactTimelineState { + /// Creates a `CompactTimelineState` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const CompactTimelineState({ required this.manualCompactModeEnabled, required this.fullTimelineExpanded, diff --git a/packages/scheduler_core/lib/src/timeline_state/models/timeline_item.dart b/packages/scheduler_core/lib/src/timeline_state/models/timeline_item.dart index 528c331..79913f9 100644 --- a/packages/scheduler_core/lib/src/timeline_state/models/timeline_item.dart +++ b/packages/scheduler_core/lib/src/timeline_state/models/timeline_item.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../timeline_state.dart'; /// Display-ready timeline item derived from a domain [Task]. class TimelineItem { + /// Creates a `TimelineItem` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. TimelineItem({ required this.id, required this.displayTitle, diff --git a/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_background_token.dart b/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_background_token.dart index f7eb8b5..f6454ea 100644 --- a/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_background_token.dart +++ b/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_background_token.dart @@ -1,11 +1,31 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../timeline_state.dart'; /// Background style token derived from the scheduling behavior type. enum TimelineBackgroundToken { + /// Selects the `flexible` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. flexible, + + /// Selects the `inflexible` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. inflexible, + + /// Selects the `critical` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. critical, + + /// Selects the `locked` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. locked, + + /// Selects the `surprise` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. surprise, + + /// Selects the `freeSlot` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. freeSlot, } diff --git a/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_difficulty_icon_token.dart b/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_difficulty_icon_token.dart index 5f15c18..9a0c533 100644 --- a/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_difficulty_icon_token.dart +++ b/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_difficulty_icon_token.dart @@ -1,11 +1,31 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../timeline_state.dart'; /// Difficulty icon token for the second timeline card icon. enum TimelineDifficultyIconToken { + /// Selects the `notSet` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. notSet, + + /// Selects the `veryEasy` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. veryEasy, + + /// Selects the `easy` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. easy, + + /// Selects the `medium` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. medium, + + /// Selects the `hard` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. hard, + + /// Selects the `veryHard` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. veryHard, } diff --git a/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_item_category.dart b/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_item_category.dart index 60b2753..e921eb3 100644 --- a/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_item_category.dart +++ b/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_item_category.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../timeline_state.dart'; /// Broad display category for an item placed on the Today timeline. diff --git a/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_quick_action.dart b/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_quick_action.dart index 3f900cf..d1e0787 100644 --- a/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_quick_action.dart +++ b/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_quick_action.dart @@ -1,12 +1,35 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../timeline_state.dart'; /// Quick actions the timeline can expose without depending on a UI framework. enum TimelineQuickAction { + /// Selects the `done` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. done, + + /// Selects the `push` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. push, + + /// Selects the `backlog` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. backlog, + + /// Selects the `breakUp` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. breakUp, + + /// Selects the `missed` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. missed, + + /// Selects the `cancel` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. cancel, + + /// Selects the `noLongerRelevant` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. noLongerRelevant, } diff --git a/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_reward_icon_token.dart b/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_reward_icon_token.dart index c9feeba..f85bf65 100644 --- a/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_reward_icon_token.dart +++ b/packages/scheduler_core/lib/src/timeline_state/tokens/timeline_reward_icon_token.dart @@ -1,11 +1,31 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../timeline_state.dart'; /// Reward icon token for the first timeline card icon. enum TimelineRewardIconToken { + /// Selects the `notSet` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. notSet, + + /// Selects the `veryLow` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. veryLow, + + /// Selects the `low` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. low, + + /// Selects the `medium` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. medium, + + /// Selects the `high` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. high, + + /// Selects the `veryHigh` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. veryHigh, } diff --git a/packages/scheduler_core/lib/src/today_state.dart b/packages/scheduler_core/lib/src/today_state.dart index a589a61..c250030 100644 --- a/packages/scheduler_core/lib/src/today_state.dart +++ b/packages/scheduler_core/lib/src/today_state.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Today State behavior for the Scheduler Core package. library; diff --git a/packages/scheduler_core/lib/src/today_state/models/today_compact_state.dart b/packages/scheduler_core/lib/src/today_state/models/today_compact_state.dart index 63256f8..018d9fa 100644 --- a/packages/scheduler_core/lib/src/today_state/models/today_compact_state.dart +++ b/packages/scheduler_core/lib/src/today_state/models/today_compact_state.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../today_state.dart'; /// Compact projection derived from the same Today item list. class TodayCompactState { + /// Creates a `TodayCompactState` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const TodayCompactState({ required this.manualCompactModeEnabled, required this.fullTimelineExpanded, diff --git a/packages/scheduler_core/lib/src/today_state/models/today_pending_notice.dart b/packages/scheduler_core/lib/src/today_state/models/today_pending_notice.dart index dd3bbae..3bea855 100644 --- a/packages/scheduler_core/lib/src/today_state/models/today_pending_notice.dart +++ b/packages/scheduler_core/lib/src/today_state/models/today_pending_notice.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../today_state.dart'; /// Pending notice data surfaced through Today state. class TodayPendingNotice { + /// Creates a `TodayPendingNotice` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. TodayPendingNotice({ required this.noticeId, required this.snapshotId, diff --git a/packages/scheduler_core/lib/src/today_state/models/today_state.dart b/packages/scheduler_core/lib/src/today_state/models/today_state.dart index f08dfb2..8b3670b 100644 --- a/packages/scheduler_core/lib/src/today_state/models/today_state.dart +++ b/packages/scheduler_core/lib/src/today_state/models/today_state.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../today_state.dart'; /// Complete V1 Today state for one owner-local date. class TodayState { + /// Creates a `TodayState` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. TodayState({ required this.date, required this.ownerId, diff --git a/packages/scheduler_core/lib/src/today_state/models/today_timeline_item.dart b/packages/scheduler_core/lib/src/today_state/models/today_timeline_item.dart index 07e22df..40f00b6 100644 --- a/packages/scheduler_core/lib/src/today_state/models/today_timeline_item.dart +++ b/packages/scheduler_core/lib/src/today_state/models/today_timeline_item.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../today_state.dart'; /// One item in the Today read model, with task status/source metadata. class TodayTimelineItem { + /// Creates a `TodayTimelineItem` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. TodayTimelineItem({ required this.item, required this.source, diff --git a/packages/scheduler_core/lib/src/today_state/models/today_timeline_item_source.dart b/packages/scheduler_core/lib/src/today_state/models/today_timeline_item_source.dart index 905e58d..be845fc 100644 --- a/packages/scheduler_core/lib/src/today_state/models/today_timeline_item_source.dart +++ b/packages/scheduler_core/lib/src/today_state/models/today_timeline_item_source.dart @@ -1,7 +1,15 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../today_state.dart'; /// Source category for one Today timeline item. enum TodayTimelineItemSource { + /// Selects the `task` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. task, + + /// Selects the `lockedOccurrence` option from this enum. + /// Code should use this named value when it needs this exact scheduler state, presentation token, or persistence meaning. lockedOccurrence, } diff --git a/packages/scheduler_core/lib/src/today_state/queries/get_today_state_query.dart b/packages/scheduler_core/lib/src/today_state/queries/get_today_state_query.dart index 698f9e1..256b296 100644 --- a/packages/scheduler_core/lib/src/today_state/queries/get_today_state_query.dart +++ b/packages/scheduler_core/lib/src/today_state/queries/get_today_state_query.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../today_state.dart'; /// Builds Today state from application repositories. class GetTodayStateQuery { + /// Creates a `GetTodayStateQuery` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const GetTodayStateQuery({ required this.applicationStore, required this.timeZoneResolver, @@ -161,6 +166,8 @@ class GetTodayStateQuery { ); } + /// Runs the `_resolve` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. DateTime _resolve({ required CivilDate date, required WallTime wallTime, @@ -176,6 +183,8 @@ class GetTodayStateQuery { .instant; } + /// Runs the `_taskAppearsInToday` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static bool _taskAppearsInToday(Task task, bool revealHiddenLockedBlocks) { if (task.status == TaskStatus.backlog || task.status == TaskStatus.cancelled || @@ -189,6 +198,8 @@ class GetTodayStateQuery { return task.scheduledStart != null && task.scheduledEnd != null; } + /// Runs the `_currentItem` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static TodayTimelineItem? _currentItem( List items, DateTime now, @@ -212,6 +223,8 @@ class GetTodayStateQuery { ); } + /// Runs the `_nextRequiredItem` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static TodayTimelineItem? _nextRequiredItem( List items, DateTime now, @@ -226,6 +239,8 @@ class GetTodayStateQuery { ); } + /// Runs the `_nextFlexibleItem` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static TodayTimelineItem? _nextFlexibleItem( List items, DateTime now, { @@ -242,14 +257,20 @@ class GetTodayStateQuery { ); } + /// Runs the `_isActionable` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static bool _isActionable(TaskStatus? status) { return status == TaskStatus.planned || status == TaskStatus.active; } + /// Runs the `_isRequired` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static bool _isRequired(TaskType type) { return type == TaskType.inflexible || type == TaskType.critical; } + /// Runs the `_containsTime` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static bool _containsTime(TodayTimelineItem item, DateTime now) { final start = item.start; final end = item.end; @@ -260,11 +281,15 @@ class GetTodayStateQuery { return !now.isBefore(start) && now.isBefore(end); } + /// Runs the `_startsAtOrAfter` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static bool _startsAtOrAfter(TodayTimelineItem item, DateTime now) { final start = item.start; return start != null && !start.isBefore(now); } + /// Runs the `_findById` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static TodayTimelineItem? _findById( List items, String? id, @@ -276,6 +301,8 @@ class GetTodayStateQuery { return _firstOrNull(items.where((item) => item.id == id)); } + /// Runs the `_pendingNoticesFromSnapshots` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. static List _pendingNoticesFromSnapshots( List snapshots, { Set acknowledgedNoticeIds = const {}, @@ -318,6 +345,8 @@ class GetTodayStateQuery { } } +/// Runs the `schedulingNoticeId` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. String schedulingNoticeId({ required String snapshotId, required int noticeIndex, @@ -325,10 +354,14 @@ String schedulingNoticeId({ return _noticeId(snapshotId, noticeIndex); } +/// Top-level helper that performs the `_noticeId` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _noticeId(String snapshotId, int noticeIndex) { return '$snapshotId:$noticeIndex'; } +/// Top-level helper that performs the `_compareTodayItems` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareTodayItems(TodayTimelineItem left, TodayTimelineItem right) { final startComparison = _compareNullableInstants(left.start, right.start); if (startComparison != 0) { @@ -348,6 +381,8 @@ int _compareTodayItems(TodayTimelineItem left, TodayTimelineItem right) { return left.id.compareTo(right.id); } +/// Top-level helper that performs the `_compareNullableInstants` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _compareNullableInstants(DateTime? left, DateTime? right) { if (left == null && right == null) { return 0; @@ -362,6 +397,8 @@ int _compareNullableInstants(DateTime? left, DateTime? right) { return left.compareTo(right); } +/// Top-level helper that performs the `_firstOrNull` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. T? _firstOrNull(Iterable values) { final iterator = values.iterator; if (!iterator.moveNext()) { diff --git a/packages/scheduler_core/lib/src/today_state/requests/get_today_state_request.dart b/packages/scheduler_core/lib/src/today_state/requests/get_today_state_request.dart index 0cc85cb..27afd0e 100644 --- a/packages/scheduler_core/lib/src/today_state/requests/get_today_state_request.dart +++ b/packages/scheduler_core/lib/src/today_state/requests/get_today_state_request.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../today_state.dart'; /// Request for the V1 Today read model. class GetTodayStateRequest { + /// Creates a `GetTodayStateRequest` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const GetTodayStateRequest({ required this.context, required this.date, diff --git a/packages/scheduler_core/pubspec.yaml b/packages/scheduler_core/pubspec.yaml index d87a90c..c9dca2a 100644 --- a/packages/scheduler_core/pubspec.yaml +++ b/packages/scheduler_core/pubspec.yaml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + name: scheduler_core description: A pure Dart scheduling core starter for an ADHD-focused scheduling app. version: 0.1.0 diff --git a/packages/scheduler_core/test/application_commands_test.dart b/packages/scheduler_core/test/application_commands_test.dart index bf93be9..b95e931 100644 --- a/packages/scheduler_core/test/application_commands_test.dart +++ b/packages/scheduler_core/test/application_commands_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Application Commands behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('V1 application commands', () { final day = CivilDate(2026, 6, 25); @@ -522,6 +527,8 @@ void main() { }); } +/// Runs the `commands` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. V1ApplicationCommandUseCases commands(InMemoryApplicationUnitOfWork store) { return V1ApplicationCommandUseCases( applicationStore: store, @@ -529,6 +536,8 @@ V1ApplicationCommandUseCases commands(InMemoryApplicationUnitOfWork store) { ); } +/// Runs the `storeWithSettings` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. InMemoryApplicationUnitOfWork storeWithSettings({ List tasks = const [], }) { @@ -545,6 +554,8 @@ InMemoryApplicationUnitOfWork storeWithSettings({ ); } +/// Runs the `appContext` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. ApplicationOperationContext appContext(String operationId, DateTime now) { return ApplicationOperationContext.start( operationId: operationId, @@ -554,6 +565,8 @@ ApplicationOperationContext appContext(String operationId, DateTime now) { ); } +/// Runs the `task` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task task({ required String id, required String title, @@ -588,6 +601,8 @@ Task task({ ); } +/// Runs the `taskById` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task taskById(List tasks, String taskId) { return tasks.singleWhere((task) => task.id == taskId); } diff --git a/packages/scheduler_core/test/application_layer_test.dart b/packages/scheduler_core/test/application_layer_test.dart index dbbaf99..0f13f8a 100644 --- a/packages/scheduler_core/test/application_layer_test.dart +++ b/packages/scheduler_core/test/application_layer_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Application Layer behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('Application unit of work', () { final now = DateTime.utc(2026, 6, 25, 16); @@ -360,6 +365,8 @@ void main() { }); } +/// Runs the `appContext` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. ApplicationOperationContext appContext({ required String operationId, required DateTime now, @@ -375,6 +382,8 @@ ApplicationOperationContext appContext({ ); } +/// Runs the `task` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task task({ required String id, required TaskStatus status, @@ -396,6 +405,8 @@ Task task({ ); } +/// Runs the `activityFor` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. TaskActivity activityFor({ required String id, required String operationId, diff --git a/packages/scheduler_core/test/application_management_test.dart b/packages/scheduler_core/test/application_management_test.dart index 0af3111..92750d8 100644 --- a/packages/scheduler_core/test/application_management_test.dart +++ b/packages/scheduler_core/test/application_management_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Application Management behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('V1ApplicationManagementUseCases', () { final now = DateTime.utc(2026, 6, 25, 12); @@ -316,6 +321,8 @@ void main() { }); } +/// Runs the `appContext` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. ApplicationOperationContext appContext({ required String operationId, required DateTime now, @@ -328,6 +335,8 @@ ApplicationOperationContext appContext({ ); } +/// Runs the `backlogTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task backlogTask({ required String id, required DateTime createdAt, diff --git a/packages/scheduler_core/test/application_recovery_test.dart b/packages/scheduler_core/test/application_recovery_test.dart index ae451ee..a5666ae 100644 --- a/packages/scheduler_core/test/application_recovery_test.dart +++ b/packages/scheduler_core/test/application_recovery_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Application Recovery behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('V1AppOpenRecoveryUseCases', () { final sourceDay = CivilDate(2026, 6, 25); @@ -194,6 +199,8 @@ void main() { }); } +/// Runs the `commands` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. V1ApplicationCommandUseCases commands(InMemoryApplicationUnitOfWork store) { return V1ApplicationCommandUseCases( applicationStore: store, @@ -201,6 +208,8 @@ V1ApplicationCommandUseCases commands(InMemoryApplicationUnitOfWork store) { ); } +/// Runs the `recovery` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. V1AppOpenRecoveryUseCases recovery(InMemoryApplicationUnitOfWork store) { return V1AppOpenRecoveryUseCases( applicationStore: store, @@ -208,6 +217,8 @@ V1AppOpenRecoveryUseCases recovery(InMemoryApplicationUnitOfWork store) { ); } +/// Runs the `today` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. GetTodayStateQuery today(InMemoryApplicationUnitOfWork store) { return GetTodayStateQuery( applicationStore: store, @@ -215,6 +226,8 @@ GetTodayStateQuery today(InMemoryApplicationUnitOfWork store) { ); } +/// Runs the `storeWithSettings` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. InMemoryApplicationUnitOfWork storeWithSettings({ List tasks = const [], }) { @@ -231,6 +244,8 @@ InMemoryApplicationUnitOfWork storeWithSettings({ ); } +/// Runs the `appContext` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. ApplicationOperationContext appContext(String operationId, DateTime now) { return ApplicationOperationContext.start( operationId: operationId, @@ -240,6 +255,8 @@ ApplicationOperationContext appContext(String operationId, DateTime now) { ); } +/// Runs the `task` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task task({ required String id, required String title, @@ -264,6 +281,8 @@ Task task({ ); } +/// Runs the `taskById` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task taskById(List tasks, String taskId) { return tasks.singleWhere((task) => task.id == taskId); } diff --git a/packages/scheduler_core/test/child_tasks_test.dart b/packages/scheduler_core/test/child_tasks_test.dart index fa0d81e..14daddd 100644 --- a/packages/scheduler_core/test/child_tasks_test.dart +++ b/packages/scheduler_core/test/child_tasks_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Child Tasks behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Runs the `and` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. void main() { group('Child task ownership', () { final now = DateTime(2026, 6, 19, 12); @@ -875,6 +880,8 @@ void main() { }); } +/// Runs the `task` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task task({ required String id, required String title, @@ -899,6 +906,8 @@ Task task({ ); } +/// Runs the `scheduledTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task scheduledTask({ required String id, required String title, @@ -919,6 +928,8 @@ Task scheduledTask({ ); } +/// Runs the `childEntry` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. ChildTaskEntry childEntry({ required String id, required String title, @@ -933,6 +944,8 @@ ChildTaskEntry childEntry({ ); } +/// Runs the `taskById` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task taskById(List tasks, String id) { return tasks.singleWhere((task) => task.id == id); } diff --git a/packages/scheduler_core/test/document_mapping_test.dart b/packages/scheduler_core/test/document_mapping_test.dart index e942063..5de95f5 100644 --- a/packages/scheduler_core/test/document_mapping_test.dart +++ b/packages/scheduler_core/test/document_mapping_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Document Mapping behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('V1 document codecs', () { final createdAt = DateTime.utc(2026, 6, 23, 8); @@ -523,6 +528,8 @@ void main() { }); } +/// Runs the `throwsMapping` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Matcher throwsMapping( DocumentMappingFailureCode code, [ String? fieldName, @@ -542,6 +549,8 @@ Matcher throwsMapping( return throwsA(matcher); } +/// Runs the `scheduledTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task scheduledTask({ required String id, required DateTime createdAt, diff --git a/packages/scheduler_core/test/document_migration_test.dart b/packages/scheduler_core/test/document_migration_test.dart index 65a1c53..1455c63 100644 --- a/packages/scheduler_core/test/document_migration_test.dart +++ b/packages/scheduler_core/test/document_migration_test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Document Migration behavior for the Scheduler Core package. library; @@ -7,6 +10,8 @@ import 'dart:io'; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('V0 to V1 document migrations', () { final migratedAt = DateTime.utc(2026, 6, 25, 12); @@ -233,6 +238,8 @@ void main() { }); } +/// Runs the `fixture` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Map fixture(String name) { var file = File('test/fixtures/migration/$name'); if (!file.existsSync()) { diff --git a/packages/scheduler_core/test/domain_contracts_test.dart b/packages/scheduler_core/test/domain_contracts_test.dart index 9ee7f9d..336ff67 100644 --- a/packages/scheduler_core/test/domain_contracts_test.dart +++ b/packages/scheduler_core/test/domain_contracts_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Domain Contracts behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('V1 lifecycle contracts', () { final now = DateTime(2026, 6, 24, 9); @@ -109,6 +114,8 @@ void main() { }); } +/// Top-level helper that performs the `_scheduledRequiredTask` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Task _scheduledRequiredTask({ required String id, required TaskType type, diff --git a/packages/scheduler_core/test/domain_invariants_test.dart b/packages/scheduler_core/test/domain_invariants_test.dart index 2da8cb4..e0f270f 100644 --- a/packages/scheduler_core/test/domain_invariants_test.dart +++ b/packages/scheduler_core/test/domain_invariants_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Domain Invariants behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('Domain invariants', () { final now = DateTime(2026, 6, 24, 9); @@ -310,6 +315,8 @@ void main() { }); } +/// Runs the `expectValidationCode` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. void expectValidationCode( Object? Function() callback, DomainValidationCode code, @@ -326,6 +333,8 @@ void expectValidationCode( ); } +/// Top-level helper that performs the `_task` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Task _task({ required DateTime now, String id = 'task-1', diff --git a/packages/scheduler_core/test/edge_case_regression_test.dart b/packages/scheduler_core/test/edge_case_regression_test.dart index 889e064..58c6485 100644 --- a/packages/scheduler_core/test/edge_case_regression_test.dart +++ b/packages/scheduler_core/test/edge_case_regression_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Edge Case Regression behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Runs the `sorts` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. void main() { group('Block 06.3 domain model regressions', () { final now = DateTime(2026, 6, 19, 12); @@ -730,6 +735,8 @@ void main() { }); } +/// Runs the `backlogTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task backlogTask({ required String id, required String title, @@ -753,6 +760,8 @@ Task backlogTask({ ).copyWith(durationMinutes: durationMinutes); } +/// Runs the `plannedFlexibleTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task plannedFlexibleTask({ required String id, required String title, @@ -772,6 +781,8 @@ Task plannedFlexibleTask({ ); } +/// Runs the `fixedTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task fixedTask({ required String id, required TaskType type, @@ -794,6 +805,8 @@ Task fixedTask({ ); } +/// Runs the `taskById` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task taskById(List tasks, String id) { return tasks.singleWhere((task) => task.id == id); } diff --git a/packages/scheduler_core/test/free_slots_test.dart b/packages/scheduler_core/test/free_slots_test.dart index c187994..d895ec5 100644 --- a/packages/scheduler_core/test/free_slots_test.dart +++ b/packages/scheduler_core/test/free_slots_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Free Slots behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('FreeSlotService', () { final now = DateTime(2026, 6, 19, 8); @@ -311,6 +316,8 @@ void main() { }); } +/// Runs the `inputFor` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. SchedulingInput inputFor(List tasks) { return SchedulingInput( tasks: tasks, @@ -321,6 +328,8 @@ SchedulingInput inputFor(List tasks) { ); } +/// Runs the `flexibleTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task flexibleTask({ required String id, required DateTime createdAt, @@ -339,6 +348,8 @@ Task flexibleTask({ ); } +/// Runs the `requiredTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task requiredTask({ required String id, required TaskType type, @@ -356,6 +367,8 @@ Task requiredTask({ ); } +/// Runs the `taskById` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task taskById(List tasks, String id) { return tasks.singleWhere((task) => task.id == id); } diff --git a/packages/scheduler_core/test/occupancy_policy_test.dart b/packages/scheduler_core/test/occupancy_policy_test.dart index ad94dd7..e7f1261 100644 --- a/packages/scheduler_core/test/occupancy_policy_test.dart +++ b/packages/scheduler_core/test/occupancy_policy_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Occupancy Policy behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('OccupancyPolicy', () { const policy = OccupancyPolicy(); @@ -167,6 +172,8 @@ void main() { }); } +/// Runs the `matrixTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task matrixTask({ required TaskType type, required TaskStatus status, @@ -192,6 +199,8 @@ Task matrixTask({ ); } +/// Runs the `expectationFor` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. OccupancyExpectation expectationFor({ required TaskType type, required TaskStatus status, @@ -247,7 +256,11 @@ OccupancyExpectation expectationFor({ return const OccupancyExpectation.nonOccupying(); } +/// Represents `OccupancyExpectation` within the pure scheduler domain package. +/// The type groups related data and behavior behind a named API so readers can understand this part of the scheduler without relying on tribal knowledge about the surrounding files. class OccupancyExpectation { + /// Creates a `OccupancyExpectation` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const OccupancyExpectation({ required this.category, required this.isImmovable, @@ -257,6 +270,8 @@ class OccupancyExpectation { required this.hiddenByDefault, }); + /// Creates a `OccupancyExpectation.nonOccupying` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const OccupancyExpectation.nonOccupying() : this( category: OccupancyCategory.nonOccupyingRecord, @@ -267,6 +282,8 @@ class OccupancyExpectation { hiddenByDefault: false, ); + /// Creates a `OccupancyExpectation.movableFlexible` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const OccupancyExpectation.movableFlexible() : this( category: OccupancyCategory.movablePlannedFlexible, @@ -277,6 +294,8 @@ class OccupancyExpectation { hiddenByDefault: false, ); + /// Creates a `OccupancyExpectation.blocking` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const OccupancyExpectation.blocking({ required OccupancyCategory category, bool mayBeExplicitlyOverlappedByRequiredCommitment = false, @@ -291,14 +310,33 @@ class OccupancyExpectation { hiddenByDefault: hiddenByDefault, ); + /// Stores the `category` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final OccupancyCategory category; + + /// Stores the `isImmovable` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool isImmovable; + + /// Stores the `blocksAutomaticFlexiblePlacement` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool blocksAutomaticFlexiblePlacement; + + /// Stores the `mayBeExplicitlyOverlappedByRequiredCommitment` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool mayBeExplicitlyOverlappedByRequiredCommitment; + + /// Stores the `reportsConflict` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool reportsConflict; + + /// Stores the `hiddenByDefault` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool hiddenByDefault; } +/// Runs the `taskById` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task taskById(List tasks, String id) { return tasks.singleWhere((task) => task.id == id); } diff --git a/packages/scheduler_core/test/persistence_edge_cases_test.dart b/packages/scheduler_core/test/persistence_edge_cases_test.dart index bbc192d..ab42224 100644 --- a/packages/scheduler_core/test/persistence_edge_cases_test.dart +++ b/packages/scheduler_core/test/persistence_edge_cases_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Persistence Edge Cases behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Runs the `values` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. void main() { group('Persistence edge-case regressions', () { final createdAt = DateTime.utc(2026, 6, 22, 8); @@ -372,6 +377,8 @@ void main() { }); } +/// Runs the `scheduledTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task scheduledTask({ required String id, required DateTime createdAt, diff --git a/packages/scheduler_core/test/persistence_index_contract_test.dart b/packages/scheduler_core/test/persistence_index_contract_test.dart index 11ba418..ce6ae1f 100644 --- a/packages/scheduler_core/test/persistence_index_contract_test.dart +++ b/packages/scheduler_core/test/persistence_index_contract_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Persistence Index Contract behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('Persistence index contract', () { test('index names and key fields are stable and adapter-neutral', () { @@ -159,6 +164,8 @@ void main() { }); } +/// Runs the `uniqueIndexNames` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Set get uniqueIndexNames { return { for (final spec in PersistenceIndexCatalog.all) @@ -166,6 +173,8 @@ Set get uniqueIndexNames { }; } +/// Runs the `indexByName` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. PersistenceIndexSpec indexByName(String name) { return PersistenceIndexCatalog.all.singleWhere((spec) => spec.name == name); } diff --git a/packages/scheduler_core/test/project_statistics_test.dart b/packages/scheduler_core/test/project_statistics_test.dart index 66de5a9..ed575b2 100644 --- a/packages/scheduler_core/test/project_statistics_test.dart +++ b/packages/scheduler_core/test/project_statistics_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Project Statistics behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('Project statistics aggregation', () { final createdAt = DateTime.utc(2026, 6, 25, 8); @@ -286,6 +291,8 @@ void main() { }); } +/// Runs the `scheduledTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task scheduledTask({ required String id, required String projectId, diff --git a/packages/scheduler_core/test/reminder_policy_test.dart b/packages/scheduler_core/test/reminder_policy_test.dart index 702b5b7..5d2264c 100644 --- a/packages/scheduler_core/test/reminder_policy_test.dart +++ b/packages/scheduler_core/test/reminder_policy_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Reminder Policy behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('Effective reminder profile resolution', () { const service = ReminderPolicyService(); @@ -283,6 +288,8 @@ void main() { }); } +/// Runs the `scheduledTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task scheduledTask({ required String id, required DateTime now, @@ -307,6 +314,8 @@ Task scheduledTask({ ); } +/// Runs the `freeSlotTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task freeSlotTask({ required String id, required DateTime start, diff --git a/packages/scheduler_core/test/repositories_test.dart b/packages/scheduler_core/test/repositories_test.dart index 3d070aa..6e33a52 100644 --- a/packages/scheduler_core/test/repositories_test.dart +++ b/packages/scheduler_core/test/repositories_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Repositories behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('Repository interfaces', () { final createdAt = DateTime(2026, 6, 21, 8); @@ -181,6 +186,8 @@ void main() { ); } +/// Runs the `runCoreRepositoryConformance` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. void runCoreRepositoryConformance({ required TaskRepository Function() createTaskRepository, required ProjectRepository Function() createProjectRepository, @@ -350,6 +357,8 @@ void runCoreRepositoryConformance({ }); } +/// Runs the `task` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task task({ required String id, required String title, diff --git a/packages/scheduler_core/test/required_task_actions_test.dart b/packages/scheduler_core/test/required_task_actions_test.dart index e804cef..a114e6c 100644 --- a/packages/scheduler_core/test/required_task_actions_test.dart +++ b/packages/scheduler_core/test/required_task_actions_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Required Task Actions behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('Required task action service', () { final now = DateTime(2026, 6, 19, 12); @@ -161,6 +166,8 @@ void main() { }); } +/// Runs the `requiredTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task requiredTask({ required String id, required TaskType type, diff --git a/packages/scheduler_core/test/scheduling_engine_test.dart b/packages/scheduler_core/test/scheduling_engine_test.dart index 512091d..5097dc5 100644 --- a/packages/scheduler_core/test/scheduling_engine_test.dart +++ b/packages/scheduler_core/test/scheduling_engine_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Scheduling Engine behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('Domain model', () { final now = DateTime(2026, 6, 19, 12); diff --git a/packages/scheduler_core/test/scheduling_invariants_test.dart b/packages/scheduler_core/test/scheduling_invariants_test.dart index 98eaa92..17338c3 100644 --- a/packages/scheduler_core/test/scheduling_invariants_test.dart +++ b/packages/scheduler_core/test/scheduling_invariants_test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Scheduling Invariants behavior for the Scheduler Core package. library; @@ -6,6 +9,8 @@ import 'dart:math'; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('Structured scheduling outcomes', () { final now = DateTime(2026, 6, 19, 8); @@ -236,6 +241,8 @@ void main() { }); } +/// Runs the `dayWindow` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. SchedulingWindow dayWindow() { return SchedulingWindow( start: DateTime(2026, 6, 19, 9), @@ -243,6 +250,8 @@ SchedulingWindow dayWindow() { ); } +/// Runs the `randomInsertionScenario` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. InsertionScenario randomInsertionScenario({ required int seed, required DateTime createdAt, @@ -308,6 +317,8 @@ InsertionScenario randomInsertionScenario({ ); } +/// Runs the `largeInsertionScenario` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. InsertionScenario largeInsertionScenario({required DateTime createdAt}) { final window = SchedulingWindow( start: DateTime(2026, 6, 19, 6), @@ -352,10 +363,14 @@ InsertionScenario largeInsertionScenario({required DateTime createdAt}) { ); } +/// Runs the `assertTaskIdsUnique` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. void assertTaskIdsUnique(List tasks) { expect(tasks.map((task) => task.id).toSet().length, tasks.length); } +/// Runs the `assertIntervalsValid` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. void assertIntervalsValid(List tasks) { for (final task in tasks) { final scheduledStart = task.scheduledStart; @@ -374,6 +389,8 @@ void assertIntervalsValid(List tasks) { } } +/// Runs the `assertNoMovableTaskOverlapsBlockers` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. void assertNoMovableTaskOverlapsBlockers({ required List resultTasks, required SchedulingInput originalInput, @@ -396,6 +413,8 @@ void assertNoMovableTaskOverlapsBlockers({ } } +/// Runs the `assertImmovablePlacementsUnchanged` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. void assertImmovablePlacementsUnchanged({ required SchedulingInput before, required List afterTasks, @@ -418,6 +437,8 @@ void assertImmovablePlacementsUnchanged({ } } +/// Runs the `assertFlexibleRelativeOrderPreserved` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. void assertFlexibleRelativeOrderPreserved({ required List beforeTasks, required List afterTasks, @@ -430,6 +451,8 @@ void assertFlexibleRelativeOrderPreserved({ expect(afterOrder, beforeOrder); } +/// Runs the `plannedFlexibleIdsByStart` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. List plannedFlexibleIdsByStart(List tasks) { final planned = tasks.where((task) { return task.type == TaskType.flexible && @@ -443,6 +466,8 @@ List plannedFlexibleIdsByStart(List tasks) { return planned.map((task) => task.id).toList(growable: false); } +/// Runs the `assertTaskSchedulesUnchanged` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. void assertTaskSchedulesUnchanged({ required List beforeTasks, required List afterTasks, @@ -461,6 +486,8 @@ void assertTaskSchedulesUnchanged({ } } +/// Runs the `scheduledInterval` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. TimeInterval? scheduledInterval(Task task) { final start = task.scheduledStart; final end = task.scheduledEnd; @@ -470,6 +497,8 @@ TimeInterval? scheduledInterval(Task task) { return TimeInterval(start: start, end: end, label: task.id); } +/// Runs the `backlogTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task backlogTask({ required String id, required DateTime createdAt, @@ -482,6 +511,8 @@ Task backlogTask({ ).copyWith(durationMinutes: durationMinutes); } +/// Runs the `flexibleTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task flexibleTask({ required String id, required DateTime createdAt, @@ -500,6 +531,8 @@ Task flexibleTask({ ); } +/// Runs the `fixedTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task fixedTask({ required String id, required TaskType type, @@ -522,17 +555,31 @@ Task fixedTask({ ); } +/// Represents `InsertionScenario` within the pure scheduler domain package. +/// The type groups related data and behavior behind a named API so readers can understand this part of the scheduler without relying on tribal knowledge about the surrounding files. class InsertionScenario { + /// Creates a `InsertionScenario` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const InsertionScenario({ required this.seed, required this.backlogTaskId, required this.input, }); + /// Stores the `seed` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final int seed; + + /// Stores the `backlogTaskId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String backlogTaskId; + + /// Stores the `input` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final SchedulingInput input; + /// Performs the `describe` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. String describe() { return 'seed=$seed tasks=${input.tasks.length} ' 'locked=${input.lockedIntervals.length} backlog=$backlogTaskId'; diff --git a/packages/scheduler_core/test/surprise_task_logging_test.dart b/packages/scheduler_core/test/surprise_task_logging_test.dart index fd16627..ea9d848 100644 --- a/packages/scheduler_core/test/surprise_task_logging_test.dart +++ b/packages/scheduler_core/test/surprise_task_logging_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Surprise Task Logging behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('Surprise task logging', () { final now = DateTime(2026, 6, 19, 12); @@ -516,6 +521,8 @@ void main() { }); } +/// Runs the `emptyInput` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. SchedulingInput emptyInput() { return SchedulingInput( tasks: const [], @@ -526,6 +533,8 @@ SchedulingInput emptyInput() { ); } +/// Runs the `plannedFlexibleTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task plannedFlexibleTask({ required String id, required String title, @@ -545,6 +554,8 @@ Task plannedFlexibleTask({ ); } +/// Runs the `fixedTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task fixedTask({ required String id, required TaskType type, @@ -567,10 +578,14 @@ Task fixedTask({ ); } +/// Runs the `taskById` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task taskById(List tasks, String id) { return tasks.singleWhere((task) => task.id == id); } +/// Runs the `sameScheduleAs` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Matcher sameScheduleAs(Task expected) { return predicate((actual) { return actual.scheduledStart == expected.scheduledStart && diff --git a/packages/scheduler_core/test/task_lifecycle_test.dart b/packages/scheduler_core/test/task_lifecycle_test.dart index 1992495..e2a861c 100644 --- a/packages/scheduler_core/test/task_lifecycle_test.dart +++ b/packages/scheduler_core/test/task_lifecycle_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Task Lifecycle behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('Task transition service', () { final now = DateTime(2026, 6, 25, 9); @@ -435,6 +440,8 @@ void main() { }); } +/// Runs the `scheduledTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task scheduledTask({ required String id, required DateTime now, @@ -457,6 +464,8 @@ Task scheduledTask({ ); } +/// Runs the `requiredTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task requiredTask({ required String id, required TaskType type, diff --git a/packages/scheduler_core/test/time_contracts_test.dart b/packages/scheduler_core/test/time_contracts_test.dart index a422029..c93542f 100644 --- a/packages/scheduler_core/test/time_contracts_test.dart +++ b/packages/scheduler_core/test/time_contracts_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Time Contracts behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('Civil date and wall-time contracts', () { test('civil dates preserve date-only boundaries', () { @@ -261,6 +266,8 @@ void main() { }); } +/// Runs the `expectValidationCode` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. void expectValidationCode( Object? Function() body, DomainValidationCode expectedCode, @@ -277,7 +284,11 @@ void expectValidationCode( ); } +/// Private implementation type for `_LosAngelesDstFixtureResolver` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _LosAngelesDstFixtureResolver implements TimeZoneResolver { + /// Performs the `resolve` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override ResolvedLocalDateTime resolve({ required CivilDate date, @@ -347,6 +358,8 @@ class _LosAngelesDstFixtureResolver implements TimeZoneResolver { ); } + /// Runs the `_offsetFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. Duration _offsetFor(CivilDate date, WallTime wallTime) { if (date == CivilDate(2026, 3, 8) && wallTime.hour >= 3) { return const Duration(hours: -7); @@ -357,6 +370,8 @@ class _LosAngelesDstFixtureResolver implements TimeZoneResolver { return const Duration(hours: -8); } + /// Runs the `_resolved` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. ResolvedLocalDateTime _resolved({ required CivilDate date, required WallTime wallTime, diff --git a/packages/scheduler_core/test/timeline_state_test.dart b/packages/scheduler_core/test/timeline_state_test.dart index 71e248f..ba43181 100644 --- a/packages/scheduler_core/test/timeline_state_test.dart +++ b/packages/scheduler_core/test/timeline_state_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Timeline State behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('Timeline item view model', () { final createdAt = DateTime(2026, 6, 20, 8); @@ -485,6 +490,8 @@ void main() { }); } +/// Runs the `scheduledTask` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task scheduledTask({ required String id, required String title, diff --git a/packages/scheduler_core/test/today_state_test.dart b/packages/scheduler_core/test/today_state_test.dart index 0151db5..da71eff 100644 --- a/packages/scheduler_core/test/today_state_test.dart +++ b/packages/scheduler_core/test/today_state_test.dart @@ -1,9 +1,14 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Today State behavior for the Scheduler Core package. library; import 'package:scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('GetTodayStateQuery', () { final day = CivilDate(2026, 6, 25); @@ -468,6 +473,8 @@ void main() { }); } +/// Runs the `todayQuery` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. GetTodayStateQuery todayQuery(InMemoryApplicationUnitOfWork store) { return GetTodayStateQuery( applicationStore: store, @@ -475,6 +482,8 @@ GetTodayStateQuery todayQuery(InMemoryApplicationUnitOfWork store) { ); } +/// Runs the `appContext` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. ApplicationOperationContext appContext({ required String operationId, required DateTime now, @@ -491,6 +500,8 @@ ApplicationOperationContext appContext({ ); } +/// Runs the `task` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. Task task({ required String id, required String title, @@ -516,7 +527,11 @@ Task task({ ); } +/// Private implementation type for `_LosAngelesDstFixtureResolver` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _LosAngelesDstFixtureResolver implements TimeZoneResolver { + /// Performs the `resolve` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override ResolvedLocalDateTime resolve({ required CivilDate date, @@ -552,6 +567,8 @@ class _LosAngelesDstFixtureResolver implements TimeZoneResolver { ); } + /// Runs the `_offsetFor` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. Duration _offsetFor(CivilDate date, WallTime wallTime) { if (date == CivilDate(2026, 3, 8) && wallTime.hour >= 3) { return const Duration(hours: -7); diff --git a/packages/scheduler_export/LICENSE.md b/packages/scheduler_export/LICENSE.md new file mode 100644 index 0000000..16fafd9 --- /dev/null +++ b/packages/scheduler_export/LICENSE.md @@ -0,0 +1,6 @@ + + + +# License + +This package uses the repository-level license at [../../LICENSE.md](../../LICENSE.md). diff --git a/packages/scheduler_export/analysis_options.yaml b/packages/scheduler_export/analysis_options.yaml index 572dd23..7df02e8 100644 --- a/packages/scheduler_export/analysis_options.yaml +++ b/packages/scheduler_export/analysis_options.yaml @@ -1 +1,4 @@ -include: package:lints/recommended.yaml +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + +include: ../../analysis_options.yaml diff --git a/packages/scheduler_export/lib/export.dart b/packages/scheduler_export/lib/export.dart index 21553e4..56c280f 100644 --- a/packages/scheduler_export/lib/export.dart +++ b/packages/scheduler_export/lib/export.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Readable export contracts and controller for scheduler data. library; diff --git a/packages/scheduler_export/lib/scheduler_export.dart b/packages/scheduler_export/lib/scheduler_export.dart index b46885b..123ab0c 100644 --- a/packages/scheduler_export/lib/scheduler_export.dart +++ b/packages/scheduler_export/lib/scheduler_export.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Package-name entry point for scheduler export contracts. library; diff --git a/packages/scheduler_export/lib/src/export_controller.dart b/packages/scheduler_export/lib/src/export_controller.dart index f833249..0a4d72f 100644 --- a/packages/scheduler_export/lib/src/export_controller.dart +++ b/packages/scheduler_export/lib/src/export_controller.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Export Controller behavior for the Scheduler Export package. library; diff --git a/packages/scheduler_export/lib/src/export_controller/context/export_context.dart b/packages/scheduler_export/lib/src/export_controller/context/export_context.dart index 1df6118..d94b036 100644 --- a/packages/scheduler_export/lib/src/export_controller/context/export_context.dart +++ b/packages/scheduler_export/lib/src/export_controller/context/export_context.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../export_controller.dart'; /// Export metadata shared with every writer. diff --git a/packages/scheduler_export/lib/src/export_controller/controller/export_controller.dart b/packages/scheduler_export/lib/src/export_controller/controller/export_controller.dart index 3a378f0..de85645 100644 --- a/packages/scheduler_export/lib/src/export_controller/controller/export_controller.dart +++ b/packages/scheduler_export/lib/src/export_controller/controller/export_controller.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../export_controller.dart'; /// Coordinates repository reads and export writer calls. @@ -9,7 +12,12 @@ final class ExportController { }) : _taskRepository = taskRepository, _writerRegistry = writerRegistry ?? ExportWriterRegistry.defaults(); + /// Private state stored as `_taskRepository` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final TaskRepository _taskRepository; + + /// Private state stored as `_writerRegistry` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final ExportWriterRegistry _writerRegistry; /// Create a writer for [format] and export owner-scoped tasks to [sink]. diff --git a/packages/scheduler_export/lib/src/export_controller/errors/export_exception.dart b/packages/scheduler_export/lib/src/export_controller/errors/export_exception.dart index bcb1799..05bf419 100644 --- a/packages/scheduler_export/lib/src/export_controller/errors/export_exception.dart +++ b/packages/scheduler_export/lib/src/export_controller/errors/export_exception.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../export_controller.dart'; /// Thrown when an export cannot complete. @@ -8,6 +11,8 @@ final class ExportException implements Exception { /// Diagnostic text for logs and tests. final String message; + /// Converts scheduler data for `toString` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. @override String toString() => 'ExportException: $message'; } diff --git a/packages/scheduler_export/lib/src/export_controller/errors/export_repository_exception.dart b/packages/scheduler_export/lib/src/export_controller/errors/export_repository_exception.dart index 88a824c..0fcfaa0 100644 --- a/packages/scheduler_export/lib/src/export_controller/errors/export_repository_exception.dart +++ b/packages/scheduler_export/lib/src/export_controller/errors/export_repository_exception.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../export_controller.dart'; /// Thrown when repository reads fail during export. diff --git a/packages/scheduler_export/lib/src/export_controller/writers/core/export_writer.dart b/packages/scheduler_export/lib/src/export_controller/writers/core/export_writer.dart index c856345..224f620 100644 --- a/packages/scheduler_export/lib/src/export_controller/writers/core/export_writer.dart +++ b/packages/scheduler_export/lib/src/export_controller/writers/core/export_writer.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../export_controller.dart'; /// Writer interface for readable exports. diff --git a/packages/scheduler_export/lib/src/export_controller/writers/csv/csv_cell_encoder.dart b/packages/scheduler_export/lib/src/export_controller/writers/csv/csv_cell_encoder.dart index c887d25..181dc3b 100644 --- a/packages/scheduler_export/lib/src/export_controller/writers/csv/csv_cell_encoder.dart +++ b/packages/scheduler_export/lib/src/export_controller/writers/csv/csv_cell_encoder.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../export_controller.dart'; +/// Top-level helper that performs the `_csvCell` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _csvCell(String value) { final needsQuotes = value.contains(',') || value.contains('"') || value.contains('\n'); diff --git a/packages/scheduler_export/lib/src/export_controller/writers/csv/csv_export_writer.dart b/packages/scheduler_export/lib/src/export_controller/writers/csv/csv_export_writer.dart index 55ac0b1..a1470ff 100644 --- a/packages/scheduler_export/lib/src/export_controller/writers/csv/csv_export_writer.dart +++ b/packages/scheduler_export/lib/src/export_controller/writers/csv/csv_export_writer.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../export_controller.dart'; /// Minimal CSV export writer stub. @@ -5,10 +8,20 @@ final class CsvExportWriter implements ExportWriter { /// Creates a CSV writer that writes to the provided string sink. CsvExportWriter(this._sink); + /// Private state stored as `_sink` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final StringSink _sink; + + /// Private state stored as `_started` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. bool _started = false; + + /// Private state stored as `_ended` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. bool _ended = false; + /// Runs the `begin` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future begin(ExportContext context) async { _assertNotEnded(); @@ -19,6 +32,8 @@ final class CsvExportWriter implements ExportWriter { ); } + /// Runs the `writeTask` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future writeTask(core.Task task) async { if (!_started) { @@ -45,6 +60,8 @@ final class CsvExportWriter implements ExportWriter { ].map(_csvCell).join(',')); } + /// Runs the `end` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future end() async { if (!_started) { @@ -54,6 +71,8 @@ final class CsvExportWriter implements ExportWriter { _ended = true; } + /// Runs the `_assertNotEnded` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. void _assertNotEnded() { if (_ended) { throw const ExportException('Writer has already ended.'); diff --git a/packages/scheduler_export/lib/src/export_controller/writers/formats/export_format_normalizer.dart b/packages/scheduler_export/lib/src/export_controller/writers/formats/export_format_normalizer.dart index aaa02e6..61d503a 100644 --- a/packages/scheduler_export/lib/src/export_controller/writers/formats/export_format_normalizer.dart +++ b/packages/scheduler_export/lib/src/export_controller/writers/formats/export_format_normalizer.dart @@ -1,9 +1,16 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../export_controller.dart'; +/// Top-level helper that performs the `_normalizeFormat` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _normalizeFormat(String format) { return _requiredTrimmed(format, 'format').toLowerCase(); } +/// Top-level helper that performs the `_requiredTrimmed` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredTrimmed(String value, String name) { final trimmed = value.trim(); if (trimmed.isEmpty) { diff --git a/packages/scheduler_export/lib/src/export_controller/writers/json/export_json_context_encoder.dart b/packages/scheduler_export/lib/src/export_controller/writers/json/export_json_context_encoder.dart index bda8605..50e27ab 100644 --- a/packages/scheduler_export/lib/src/export_controller/writers/json/export_json_context_encoder.dart +++ b/packages/scheduler_export/lib/src/export_controller/writers/json/export_json_context_encoder.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../export_controller.dart'; +/// Top-level helper that performs the `_contextToJson` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _contextToJson(ExportContext context) { return { 'ownerId': context.ownerId.value, diff --git a/packages/scheduler_export/lib/src/export_controller/writers/json/json_export_writer.dart b/packages/scheduler_export/lib/src/export_controller/writers/json/json_export_writer.dart index 09e9220..a0835b2 100644 --- a/packages/scheduler_export/lib/src/export_controller/writers/json/json_export_writer.dart +++ b/packages/scheduler_export/lib/src/export_controller/writers/json/json_export_writer.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../export_controller.dart'; /// Minimal JSON export writer stub. @@ -5,11 +8,24 @@ final class JsonExportWriter implements ExportWriter { /// Creates a JSON writer that writes to the provided string sink. JsonExportWriter(this._sink); + /// Private state stored as `_sink` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final StringSink _sink; + + /// Private state stored as `_context` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. ExportContext? _context; + + /// Private state stored as `_hasTask` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. bool _hasTask = false; + + /// Private state stored as `_ended` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. bool _ended = false; + /// Runs the `begin` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future begin(ExportContext context) async { _assertNotEnded(); @@ -19,6 +35,8 @@ final class JsonExportWriter implements ExportWriter { ); } + /// Runs the `writeTask` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future writeTask(core.Task task) async { final context = _requireContext(); @@ -32,6 +50,8 @@ final class JsonExportWriter implements ExportWriter { _hasTask = true; } + /// Runs the `end` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future end() async { _requireContext(); @@ -40,6 +60,8 @@ final class JsonExportWriter implements ExportWriter { _ended = true; } + /// Runs the `_requireContext` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. ExportContext _requireContext() { final context = _context; if (context == null) { @@ -48,6 +70,8 @@ final class JsonExportWriter implements ExportWriter { return context; } + /// Runs the `_assertNotEnded` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. void _assertNotEnded() { if (_ended) { throw const ExportException('Writer has already ended.'); diff --git a/packages/scheduler_export/lib/src/export_controller/writers/registry/export_writer_factory.dart b/packages/scheduler_export/lib/src/export_controller/writers/registry/export_writer_factory.dart index 032c698..653dfae 100644 --- a/packages/scheduler_export/lib/src/export_controller/writers/registry/export_writer_factory.dart +++ b/packages/scheduler_export/lib/src/export_controller/writers/registry/export_writer_factory.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../export_controller.dart'; /// Factory signature for sink-backed export writers. diff --git a/packages/scheduler_export/lib/src/export_controller/writers/registry/export_writer_registry.dart b/packages/scheduler_export/lib/src/export_controller/writers/registry/export_writer_registry.dart index 54a19d9..b70406b 100644 --- a/packages/scheduler_export/lib/src/export_controller/writers/registry/export_writer_registry.dart +++ b/packages/scheduler_export/lib/src/export_controller/writers/registry/export_writer_registry.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../export_controller.dart'; /// Registry that resolves export format names to writer factories. @@ -12,6 +15,8 @@ final class ExportWriterRegistry { ), ); + /// Private state stored as `_factories` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _factories; /// Default registry with JSON and CSV stub writers. diff --git a/packages/scheduler_export/pubspec.yaml b/packages/scheduler_export/pubspec.yaml index 9ed4597..ada4f30 100644 --- a/packages/scheduler_export/pubspec.yaml +++ b/packages/scheduler_export/pubspec.yaml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + name: scheduler_export description: Export controller and writer contracts for the ADHD scheduler. version: 0.1.0 diff --git a/packages/scheduler_export/test/export_controller_test.dart b/packages/scheduler_export/test/export_controller_test.dart index 1167cb1..64c95dd 100644 --- a/packages/scheduler_export/test/export_controller_test.dart +++ b/packages/scheduler_export/test/export_controller_test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Export Controller behavior for the Scheduler Export package. library; @@ -8,6 +11,8 @@ import 'package:scheduler_export/export.dart'; import 'package:scheduler_persistence_memory/persistence_memory.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { test('JSON writer exports owner-scoped tasks through controller', () async { final ownerId = core.OwnerId('owner-a'); @@ -72,6 +77,8 @@ void main() { }); } +/// Top-level helper that performs the `_task` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.Task _task(String id) { return core.Task( id: id, @@ -85,19 +92,31 @@ core.Task _task(String id) { ); } +/// Private implementation type for `_CountingWriter` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. final class _CountingWriter implements ExportWriter { + /// Creates a `_CountingWriter` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _CountingWriter(StringSink sink); + /// Stores the `count` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. var count = 0; + /// Runs the `begin` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future begin(ExportContext context) async {} + /// Runs the `writeTask` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future writeTask(core.Task task) async { count += 1; } + /// Runs the `end` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future end() async {} } diff --git a/packages/scheduler_export_json/LICENSE.md b/packages/scheduler_export_json/LICENSE.md new file mode 100644 index 0000000..16fafd9 --- /dev/null +++ b/packages/scheduler_export_json/LICENSE.md @@ -0,0 +1,6 @@ + + + +# License + +This package uses the repository-level license at [../../LICENSE.md](../../LICENSE.md). diff --git a/packages/scheduler_export_json/analysis_options.yaml b/packages/scheduler_export_json/analysis_options.yaml index 572dd23..7df02e8 100644 --- a/packages/scheduler_export_json/analysis_options.yaml +++ b/packages/scheduler_export_json/analysis_options.yaml @@ -1 +1,4 @@ -include: package:lints/recommended.yaml +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + +include: ../../analysis_options.yaml diff --git a/packages/scheduler_export_json/bin/export.dart b/packages/scheduler_export_json/bin/export.dart index 1e224f5..f06ee19 100644 --- a/packages/scheduler_export_json/bin/export.dart +++ b/packages/scheduler_export_json/bin/export.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Runs the Export command for the Scheduler Export Json package. library; @@ -8,6 +11,8 @@ import 'package:scheduler_export/export.dart'; import 'package:scheduler_export_json/export_json.dart'; import 'package:scheduler_persistence_memory/persistence_memory.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. Future main(List arguments) async { final format = _format(arguments); if (format == null) { @@ -34,6 +39,8 @@ Future main(List arguments) async { stdout.write(output.toString()); } +/// Top-level helper that performs the `_format` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _format(List arguments) { final wantsJson = arguments.contains('--json'); final wantsCsv = arguments.contains('--csv'); @@ -43,6 +50,8 @@ String? _format(List arguments) { return wantsJson ? 'json' : 'csv'; } +/// Top-level helper that performs the `_option` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _option(List arguments, String name) { final index = arguments.indexOf(name); if (index == -1 || index + 1 >= arguments.length) { diff --git a/packages/scheduler_export_json/lib/export_json.dart b/packages/scheduler_export_json/lib/export_json.dart index 03bb5a4..a0325ea 100644 --- a/packages/scheduler_export_json/lib/export_json.dart +++ b/packages/scheduler_export_json/lib/export_json.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// JSON and CSV readable export writers. library; diff --git a/packages/scheduler_export_json/lib/scheduler_export_json.dart b/packages/scheduler_export_json/lib/scheduler_export_json.dart index aa86deb..26a1702 100644 --- a/packages/scheduler_export_json/lib/scheduler_export_json.dart +++ b/packages/scheduler_export_json/lib/scheduler_export_json.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Package-name entry point for scheduler readable export writers. library; diff --git a/packages/scheduler_export_json/lib/src/json_csv_writers.dart b/packages/scheduler_export_json/lib/src/json_csv_writers.dart index 3b9c427..7fa4548 100644 --- a/packages/scheduler_export_json/lib/src/json_csv_writers.dart +++ b/packages/scheduler_export_json/lib/src/json_csv_writers.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Json Csv Writers behavior for the Scheduler Export Json package. library; diff --git a/packages/scheduler_export_json/lib/src/json_csv_writers/csv_cell_encoder.dart b/packages/scheduler_export_json/lib/src/json_csv_writers/csv_cell_encoder.dart index b439dd6..e2d8c23 100644 --- a/packages/scheduler_export_json/lib/src/json_csv_writers/csv_cell_encoder.dart +++ b/packages/scheduler_export_json/lib/src/json_csv_writers/csv_cell_encoder.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../json_csv_writers.dart'; +/// Top-level helper that performs the `_csvCell` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _csvCell(String value) { final needsQuotes = value.contains(',') || value.contains('"') || value.contains('\n'); diff --git a/packages/scheduler_export_json/lib/src/json_csv_writers/csv_export_writer.dart b/packages/scheduler_export_json/lib/src/json_csv_writers/csv_export_writer.dart index 4b25b1d..b5d60df 100644 --- a/packages/scheduler_export_json/lib/src/json_csv_writers/csv_export_writer.dart +++ b/packages/scheduler_export_json/lib/src/json_csv_writers/csv_export_writer.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../json_csv_writers.dart'; /// CSV export writer for scheduler tasks. @@ -5,10 +8,20 @@ final class CsvExportWriter implements ExportWriter { /// Creates a CSV writer that writes to the provided string sink. CsvExportWriter(this._sink); + /// Private state stored as `_sink` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final StringSink _sink; + + /// Private state stored as `_started` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. bool _started = false; + + /// Private state stored as `_ended` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. bool _ended = false; + /// Runs the `begin` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future begin(ExportContext context) async { _assertNotEnded(); @@ -19,6 +32,8 @@ final class CsvExportWriter implements ExportWriter { ); } + /// Runs the `writeTask` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future writeTask(core.Task task) async { if (!_started) { @@ -45,6 +60,8 @@ final class CsvExportWriter implements ExportWriter { ].map(_csvCell).join(',')); } + /// Runs the `end` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future end() async { if (!_started) { @@ -54,6 +71,8 @@ final class CsvExportWriter implements ExportWriter { _ended = true; } + /// Runs the `_assertNotEnded` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. void _assertNotEnded() { if (_ended) { throw const ExportException('Writer has already ended.'); diff --git a/packages/scheduler_export_json/lib/src/json_csv_writers/export_json_context_encoder.dart b/packages/scheduler_export_json/lib/src/json_csv_writers/export_json_context_encoder.dart index 98393a4..3bb9291 100644 --- a/packages/scheduler_export_json/lib/src/json_csv_writers/export_json_context_encoder.dart +++ b/packages/scheduler_export_json/lib/src/json_csv_writers/export_json_context_encoder.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../json_csv_writers.dart'; +/// Top-level helper that performs the `_contextToJson` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _contextToJson(ExportContext context) { return { 'ownerId': context.ownerId.value, diff --git a/packages/scheduler_export_json/lib/src/json_csv_writers/json_export_writer.dart b/packages/scheduler_export_json/lib/src/json_csv_writers/json_export_writer.dart index df3a45d..f04a7db 100644 --- a/packages/scheduler_export_json/lib/src/json_csv_writers/json_export_writer.dart +++ b/packages/scheduler_export_json/lib/src/json_csv_writers/json_export_writer.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../json_csv_writers.dart'; /// JSON export writer for scheduler tasks. @@ -5,11 +8,24 @@ final class JsonExportWriter implements ExportWriter { /// Creates a JSON writer that writes to the provided string sink. JsonExportWriter(this._sink); + /// Private state stored as `_sink` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final StringSink _sink; + + /// Private state stored as `_context` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. ExportContext? _context; + + /// Private state stored as `_hasTask` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. bool _hasTask = false; + + /// Private state stored as `_ended` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. bool _ended = false; + /// Runs the `begin` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future begin(ExportContext context) async { _assertNotEnded(); @@ -19,6 +35,8 @@ final class JsonExportWriter implements ExportWriter { ); } + /// Runs the `writeTask` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future writeTask(core.Task task) async { final context = _requireContext(); @@ -33,6 +51,8 @@ final class JsonExportWriter implements ExportWriter { _hasTask = true; } + /// Runs the `end` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future end() async { _requireContext(); @@ -41,6 +61,8 @@ final class JsonExportWriter implements ExportWriter { _ended = true; } + /// Runs the `_requireContext` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. ExportContext _requireContext() { final context = _context; if (context == null) { @@ -49,6 +71,8 @@ final class JsonExportWriter implements ExportWriter { return context; } + /// Runs the `_assertNotEnded` helper used inside this library. + /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. void _assertNotEnded() { if (_ended) { throw const ExportException('Writer has already ended.'); diff --git a/packages/scheduler_export_json/pubspec.yaml b/packages/scheduler_export_json/pubspec.yaml index 3c27b9c..bd00cd4 100644 --- a/packages/scheduler_export_json/pubspec.yaml +++ b/packages/scheduler_export_json/pubspec.yaml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + name: scheduler_export_json description: JSON and CSV readable export writers for the ADHD scheduler. version: 0.1.0 diff --git a/packages/scheduler_export_json/test/export_json_test.dart b/packages/scheduler_export_json/test/export_json_test.dart index cf787b3..9787aea 100644 --- a/packages/scheduler_export_json/test/export_json_test.dart +++ b/packages/scheduler_export_json/test/export_json_test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Export Json behavior for the Scheduler Export Json package. library; @@ -10,6 +13,8 @@ import 'package:scheduler_export_json/export_json.dart'; import 'package:scheduler_persistence_memory/persistence_memory.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { test('readable registry exports valid JSON through ExportController', () async { @@ -68,6 +73,8 @@ void main() { }, timeout: const Timeout(Duration(seconds: 20))); } +/// Top-level helper that performs the `_packageDirectory` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Directory _packageDirectory() { final currentPubspec = File('${Directory.current.path}${Platform.pathSeparator}pubspec.yaml'); @@ -83,6 +90,8 @@ Directory _packageDirectory() { ); } +/// Top-level helper that performs the `_task` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.Task _task(String id, {String? title}) { return core.Task( id: id, diff --git a/packages/scheduler_integration_tests/LICENSE.md b/packages/scheduler_integration_tests/LICENSE.md new file mode 100644 index 0000000..16fafd9 --- /dev/null +++ b/packages/scheduler_integration_tests/LICENSE.md @@ -0,0 +1,6 @@ + + + +# License + +This package uses the repository-level license at [../../LICENSE.md](../../LICENSE.md). diff --git a/packages/scheduler_integration_tests/analysis_options.yaml b/packages/scheduler_integration_tests/analysis_options.yaml index 572dd23..7df02e8 100644 --- a/packages/scheduler_integration_tests/analysis_options.yaml +++ b/packages/scheduler_integration_tests/analysis_options.yaml @@ -1 +1,4 @@ -include: package:lints/recommended.yaml +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + +include: ../../analysis_options.yaml diff --git a/packages/scheduler_integration_tests/integration/scheduler_flow_test.dart b/packages/scheduler_integration_tests/integration/scheduler_flow_test.dart index 26a7931..0eb900d 100644 --- a/packages/scheduler_integration_tests/integration/scheduler_flow_test.dart +++ b/packages/scheduler_integration_tests/integration/scheduler_flow_test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Exercises Scheduler Flow integration behavior for the Scheduler Integration Tests package. library; @@ -8,6 +11,8 @@ import 'package:scheduler_persistence_memory/persistence_memory.dart'; import 'package:scheduler_persistence_sqlite/sqlite.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { test('scheduler flow schedules, notifies, persists, and reloads', () async { final runtime = Stopwatch()..start(); @@ -116,6 +121,8 @@ void main() { }); } +/// Top-level helper that performs the `_taskById` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.Task _taskById(Iterable tasks, String id) { return tasks.singleWhere((task) => task.id == id); } diff --git a/packages/scheduler_integration_tests/pubspec.yaml b/packages/scheduler_integration_tests/pubspec.yaml index 50207eb..0a325c9 100644 --- a/packages/scheduler_integration_tests/pubspec.yaml +++ b/packages/scheduler_integration_tests/pubspec.yaml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + name: scheduler_integration_tests description: End-to-end scheduler integration tests. version: 0.1.0 diff --git a/packages/scheduler_integration_tests/test/scheduler_flow_test.dart b/packages/scheduler_integration_tests/test/scheduler_flow_test.dart index 6373b6c..98d8390 100644 --- a/packages/scheduler_integration_tests/test/scheduler_flow_test.dart +++ b/packages/scheduler_integration_tests/test/scheduler_flow_test.dart @@ -1,8 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Scheduler Flow behavior for the Scheduler Integration Tests package. library; import '../integration/scheduler_flow_test.dart' as scheduler_flow_test; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { scheduler_flow_test.main(); } diff --git a/packages/scheduler_notifications/LICENSE.md b/packages/scheduler_notifications/LICENSE.md new file mode 100644 index 0000000..16fafd9 --- /dev/null +++ b/packages/scheduler_notifications/LICENSE.md @@ -0,0 +1,6 @@ + + + +# License + +This package uses the repository-level license at [../../LICENSE.md](../../LICENSE.md). diff --git a/packages/scheduler_notifications/analysis_options.yaml b/packages/scheduler_notifications/analysis_options.yaml index 572dd23..7df02e8 100644 --- a/packages/scheduler_notifications/analysis_options.yaml +++ b/packages/scheduler_notifications/analysis_options.yaml @@ -1 +1,4 @@ -include: package:lints/recommended.yaml +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + +include: ../../analysis_options.yaml diff --git a/packages/scheduler_notifications/lib/notifications.dart b/packages/scheduler_notifications/lib/notifications.dart index 168d793..080cf0b 100644 --- a/packages/scheduler_notifications/lib/notifications.dart +++ b/packages/scheduler_notifications/lib/notifications.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Notification contracts for scheduler reminder delivery. library; diff --git a/packages/scheduler_notifications/lib/scheduler_notifications.dart b/packages/scheduler_notifications/lib/scheduler_notifications.dart index 5f7f907..a08e382 100644 --- a/packages/scheduler_notifications/lib/scheduler_notifications.dart +++ b/packages/scheduler_notifications/lib/scheduler_notifications.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Package-name entry point for scheduler notification contracts. library; diff --git a/packages/scheduler_notifications/lib/src/notification_adapter.dart b/packages/scheduler_notifications/lib/src/notification_adapter.dart index 48ece23..8105622 100644 --- a/packages/scheduler_notifications/lib/src/notification_adapter.dart +++ b/packages/scheduler_notifications/lib/src/notification_adapter.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Notification Adapter behavior for the Scheduler Notifications package. library; diff --git a/packages/scheduler_notifications/lib/src/notification_adapter/adapter/fake_notification_adapter.dart b/packages/scheduler_notifications/lib/src/notification_adapter/adapter/fake_notification_adapter.dart index b401b59..6eca676 100644 --- a/packages/scheduler_notifications/lib/src/notification_adapter/adapter/fake_notification_adapter.dart +++ b/packages/scheduler_notifications/lib/src/notification_adapter/adapter/fake_notification_adapter.dart @@ -1,11 +1,22 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../notification_adapter.dart'; /// Test fake for notification adapter behavior. final class FakeNotificationAdapter implements NotificationAdapter { + /// Private state stored as `_feedbackController` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final StreamController _feedbackController = StreamController.broadcast(); + + /// Private state stored as `_scheduled` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _scheduled = {}; + + /// Private state stored as `_cancelledIds` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final List _cancelledIds = []; /// Snapshot of currently scheduled requests by id. @@ -15,14 +26,20 @@ final class FakeNotificationAdapter implements NotificationAdapter { /// Snapshot of cancellation ids in call order. List get cancelledIds => List.unmodifiable(_cancelledIds); + /// Returns the derived `feedback` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override Stream get feedback => _feedbackController.stream; + /// Runs the `schedule` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future schedule(NotificationRequest request) async { _scheduled[request.id] = request; } + /// Runs the `cancel` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future cancel(String id) async { final trimmed = _requiredTrimmed(id, 'id'); @@ -41,6 +58,8 @@ final class FakeNotificationAdapter implements NotificationAdapter { } } +/// Top-level helper that performs the `_requiredTrimmed` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _requiredTrimmed(String value, String name) { final trimmed = value.trim(); if (trimmed.isEmpty) { diff --git a/packages/scheduler_notifications/lib/src/notification_adapter/adapter/notification_adapter.dart b/packages/scheduler_notifications/lib/src/notification_adapter/adapter/notification_adapter.dart index da98df1..37cc756 100644 --- a/packages/scheduler_notifications/lib/src/notification_adapter/adapter/notification_adapter.dart +++ b/packages/scheduler_notifications/lib/src/notification_adapter/adapter/notification_adapter.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../notification_adapter.dart'; /// Platform-neutral notification adapter boundary. diff --git a/packages/scheduler_notifications/lib/src/notification_adapter/feedback/notification_feedback.dart b/packages/scheduler_notifications/lib/src/notification_adapter/feedback/notification_feedback.dart index 26073cc..5ccfdd5 100644 --- a/packages/scheduler_notifications/lib/src/notification_adapter/feedback/notification_feedback.dart +++ b/packages/scheduler_notifications/lib/src/notification_adapter/feedback/notification_feedback.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../notification_adapter.dart'; /// Feedback event emitted by a notification adapter. diff --git a/packages/scheduler_notifications/lib/src/notification_adapter/feedback/notification_feedback_type.dart b/packages/scheduler_notifications/lib/src/notification_adapter/feedback/notification_feedback_type.dart index df0a92c..752c012 100644 --- a/packages/scheduler_notifications/lib/src/notification_adapter/feedback/notification_feedback_type.dart +++ b/packages/scheduler_notifications/lib/src/notification_adapter/feedback/notification_feedback_type.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../notification_adapter.dart'; /// User feedback category emitted by a notification adapter. diff --git a/packages/scheduler_notifications/lib/src/notification_adapter/requests/notification_request.dart b/packages/scheduler_notifications/lib/src/notification_adapter/requests/notification_request.dart index ce52fab..eb2ca29 100644 --- a/packages/scheduler_notifications/lib/src/notification_adapter/requests/notification_request.dart +++ b/packages/scheduler_notifications/lib/src/notification_adapter/requests/notification_request.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../notification_adapter.dart'; /// Request to schedule one notification through a platform adapter. @@ -19,6 +22,8 @@ sealed class NotificationRequest { ); } + /// Creates a `NotificationRequest._` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const NotificationRequest._({ required this.id, required this.title, diff --git a/packages/scheduler_notifications/lib/src/notification_adapter/requests/notification_request_impl.dart b/packages/scheduler_notifications/lib/src/notification_adapter/requests/notification_request_impl.dart index 0ae4131..0a7ea6a 100644 --- a/packages/scheduler_notifications/lib/src/notification_adapter/requests/notification_request_impl.dart +++ b/packages/scheduler_notifications/lib/src/notification_adapter/requests/notification_request_impl.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../notification_adapter.dart'; +/// Private implementation type for `_NotificationRequest` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. final class _NotificationRequest extends NotificationRequest { + /// Creates a `_NotificationRequest` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _NotificationRequest({ required super.id, required super.title, diff --git a/packages/scheduler_notifications/pubspec.yaml b/packages/scheduler_notifications/pubspec.yaml index e9d29dd..7cbf28c 100644 --- a/packages/scheduler_notifications/pubspec.yaml +++ b/packages/scheduler_notifications/pubspec.yaml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + name: scheduler_notifications description: Notification adapter contracts for the ADHD scheduler. version: 0.1.0 diff --git a/packages/scheduler_notifications/test/fake_adapter_test.dart b/packages/scheduler_notifications/test/fake_adapter_test.dart index 5a8743e..31b0a79 100644 --- a/packages/scheduler_notifications/test/fake_adapter_test.dart +++ b/packages/scheduler_notifications/test/fake_adapter_test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Fake Adapter behavior for the Scheduler Notifications package. library; @@ -6,6 +9,8 @@ import 'package:test/test.dart'; import 'notification_adapter_contract.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { runNotificationAdapterContractTests('fake', () { final adapter = FakeNotificationAdapter(); diff --git a/packages/scheduler_notifications/test/notification_adapter_contract.dart b/packages/scheduler_notifications/test/notification_adapter_contract.dart index 34ebca5..c8c8c9f 100644 --- a/packages/scheduler_notifications/test/notification_adapter_contract.dart +++ b/packages/scheduler_notifications/test/notification_adapter_contract.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Notification Adapter Contract behavior for the Scheduler Notifications package. library; @@ -63,6 +66,8 @@ void runNotificationAdapterContractTests( }); } +/// Top-level helper that performs the `_request` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. NotificationRequest _request(String id) { return NotificationRequest( id: id, diff --git a/packages/scheduler_notifications_desktop/LICENSE.md b/packages/scheduler_notifications_desktop/LICENSE.md new file mode 100644 index 0000000..16fafd9 --- /dev/null +++ b/packages/scheduler_notifications_desktop/LICENSE.md @@ -0,0 +1,6 @@ + + + +# License + +This package uses the repository-level license at [../../LICENSE.md](../../LICENSE.md). diff --git a/packages/scheduler_notifications_desktop/analysis_options.yaml b/packages/scheduler_notifications_desktop/analysis_options.yaml index 572dd23..7df02e8 100644 --- a/packages/scheduler_notifications_desktop/analysis_options.yaml +++ b/packages/scheduler_notifications_desktop/analysis_options.yaml @@ -1 +1,4 @@ -include: package:lints/recommended.yaml +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + +include: ../../analysis_options.yaml diff --git a/packages/scheduler_notifications_desktop/lib/desktop_notifications.dart b/packages/scheduler_notifications_desktop/lib/desktop_notifications.dart index 34b3ec4..4194ce3 100644 --- a/packages/scheduler_notifications_desktop/lib/desktop_notifications.dart +++ b/packages/scheduler_notifications_desktop/lib/desktop_notifications.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Desktop notification adapter for scheduler reminder delivery. library; diff --git a/packages/scheduler_notifications_desktop/lib/scheduler_notifications_desktop.dart b/packages/scheduler_notifications_desktop/lib/scheduler_notifications_desktop.dart index ab4603d..8c12457 100644 --- a/packages/scheduler_notifications_desktop/lib/scheduler_notifications_desktop.dart +++ b/packages/scheduler_notifications_desktop/lib/scheduler_notifications_desktop.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Package-name entry point for desktop notification adapters. library; diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter.dart index a072eae..39ec666 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Desktop Notification Adapter behavior for the Scheduler Notifications Desktop package. library; diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io.dart index acad696..7720b84 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Desktop Notification Adapter Io behavior for the Scheduler Notifications Desktop package. library; diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/adapter/desktop_notification_adapter.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/adapter/desktop_notification_adapter.dart index c88d98d..50b2c4f 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/adapter/desktop_notification_adapter.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/adapter/desktop_notification_adapter.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../desktop_notification_adapter_io.dart'; /// Notification adapter that delegates to a desktop backend. @@ -6,6 +9,8 @@ final class DesktopNotificationAdapter implements NotificationAdapter { DesktopNotificationAdapter({required DesktopNotificationBackend backend}) : _backend = backend; + /// Private state stored as `_backend` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final DesktopNotificationBackend _backend; /// Creates the best available desktop adapter for the current platform. @@ -23,14 +28,20 @@ final class DesktopNotificationAdapter implements NotificationAdapter { ); } + /// Returns the derived `feedback` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override Stream get feedback => const Stream.empty(); + /// Runs the `schedule` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future schedule(NotificationRequest request) { return _backend.deliver(request); } + /// Runs the `cancel` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future cancel(String id) { return _backend.cancel(id.trim()); diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/core/desktop_notification_backend.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/core/desktop_notification_backend.dart index de18569..5d63ef6 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/core/desktop_notification_backend.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/core/desktop_notification_backend.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../desktop_notification_adapter_io.dart'; /// Platform-neutral backend used by [DesktopNotificationAdapter]. diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/core/desktop_notification_backend_factory.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/core/desktop_notification_backend_factory.dart index 9a46dcc..a07ff17 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/core/desktop_notification_backend_factory.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/core/desktop_notification_backend_factory.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../desktop_notification_adapter_io.dart'; /// Create the best default desktop notification backend. diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/fallback/stdout_notification_backend.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/fallback/stdout_notification_backend.dart index cb09eed..b8e3d14 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/fallback/stdout_notification_backend.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/fallback/stdout_notification_backend.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../desktop_notification_adapter_io.dart'; /// Fallback backend that writes notification requests to stdout/logs. @@ -8,14 +11,20 @@ final class StdoutNotificationBackend implements DesktopNotificationBackend { required this.platform, }) : _logSink = logSink; + /// Private state stored as `_logSink` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final DesktopNotificationLogSink _logSink; /// Platform this fallback represents. final DesktopNotificationPlatform platform; + /// Returns the derived `isSupported` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override bool get isSupported => false; + /// Runs the `deliver` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future deliver(NotificationRequest request) async { _logSink( @@ -24,6 +33,8 @@ final class StdoutNotificationBackend implements DesktopNotificationBackend { ); } + /// Runs the `cancel` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future cancel(String id) async { _logSink('notification[$platform] cancel: ${id.trim()}'); diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/platform/apple_script_string_encoder.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/platform/apple_script_string_encoder.dart index b9880cb..6a677d0 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/platform/apple_script_string_encoder.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/platform/apple_script_string_encoder.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../desktop_notification_adapter_io.dart'; +/// Top-level helper that performs the `_appleScriptString` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _appleScriptString(String value) { return jsonEncode(value); } diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/platform/linux_notify_send_backend.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/platform/linux_notify_send_backend.dart index b3f6dd4..e336a69 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/platform/linux_notify_send_backend.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/platform/linux_notify_send_backend.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../desktop_notification_adapter_io.dart'; /// Linux backend using `notify-send`. @@ -9,12 +12,21 @@ final class LinuxNotifySendBackend implements DesktopNotificationBackend { }) : _processRunner = processRunner, _fallback = fallback; + /// Private state stored as `_processRunner` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final DesktopProcessRunner _processRunner; + + /// Private state stored as `_fallback` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final DesktopNotificationBackend _fallback; + /// Returns the derived `isSupported` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override bool get isSupported => true; + /// Runs the `deliver` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future deliver(NotificationRequest request) async { await _runOrFallback( @@ -27,11 +39,15 @@ final class LinuxNotifySendBackend implements DesktopNotificationBackend { ); } + /// Runs the `cancel` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future cancel(String id) async { await _fallback.cancel(id); } + /// Runs the `_runOrFallback` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _runOrFallback( NotificationRequest request, Future Function() run, diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/platform/mac_os_notification_backend.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/platform/mac_os_notification_backend.dart index 2222af9..70bbcf3 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/platform/mac_os_notification_backend.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/backends/platform/mac_os_notification_backend.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../desktop_notification_adapter_io.dart'; /// macOS backend using `osascript`. @@ -9,12 +12,21 @@ final class MacOsNotificationBackend implements DesktopNotificationBackend { }) : _processRunner = processRunner, _fallback = fallback; + /// Private state stored as `_processRunner` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final DesktopProcessRunner _processRunner; + + /// Private state stored as `_fallback` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final DesktopNotificationBackend _fallback; + /// Returns the derived `isSupported` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override bool get isSupported => true; + /// Runs the `deliver` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future deliver(NotificationRequest request) async { final script = 'display notification ${_appleScriptString(request.body)} ' @@ -29,6 +41,8 @@ final class MacOsNotificationBackend implements DesktopNotificationBackend { } } + /// Runs the `cancel` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future cancel(String id) async { await _fallback.cancel(id); diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/callbacks/desktop_notification_log_sink.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/callbacks/desktop_notification_log_sink.dart index 104b098..86df51c 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/callbacks/desktop_notification_log_sink.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/callbacks/desktop_notification_log_sink.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../desktop_notification_adapter_io.dart'; /// Logging callback used by fallback notification backends. diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/callbacks/desktop_process_runner.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/callbacks/desktop_process_runner.dart index 159ff19..0b379d6 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/callbacks/desktop_process_runner.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/callbacks/desktop_process_runner.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../desktop_notification_adapter_io.dart'; /// Process runner used by command-backed notification backends. diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/platform/desktop_notification_platform.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/platform/desktop_notification_platform.dart index d7b3cd4..be1cb92 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/platform/desktop_notification_platform.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/platform/desktop_notification_platform.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../desktop_notification_adapter_io.dart'; /// Supported desktop platform categories. diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/platform/desktop_notification_platform_detector.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/platform/desktop_notification_platform_detector.dart index ccedcae..ac2d5c0 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/platform/desktop_notification_platform_detector.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_io/platform/desktop_notification_platform_detector.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../desktop_notification_adapter_io.dart'; +/// Top-level helper that performs the `_currentPlatform` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. DesktopNotificationPlatform _currentPlatform() { if (Platform.isLinux) return DesktopNotificationPlatform.linux; if (Platform.isMacOS) return DesktopNotificationPlatform.macos; diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub.dart index e7c1e55..eabbd58 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Implements Desktop Notification Adapter Stub behavior for the Scheduler Notifications Desktop package. library; diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/adapter/desktop_notification_adapter.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/adapter/desktop_notification_adapter.dart index d3ad029..3b876dd 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/adapter/desktop_notification_adapter.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/adapter/desktop_notification_adapter.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../desktop_notification_adapter_stub.dart'; /// Notification adapter that delegates to a desktop backend. @@ -6,6 +9,8 @@ final class DesktopNotificationAdapter implements NotificationAdapter { DesktopNotificationAdapter({required DesktopNotificationBackend backend}) : _backend = backend; + /// Private state stored as `_backend` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final DesktopNotificationBackend _backend; /// Creates the best available desktop adapter for the current platform. @@ -23,14 +28,20 @@ final class DesktopNotificationAdapter implements NotificationAdapter { ); } + /// Returns the derived `feedback` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override Stream get feedback => const Stream.empty(); + /// Runs the `schedule` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future schedule(NotificationRequest request) { return _backend.deliver(request); } + /// Runs the `cancel` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future cancel(String id) { return _backend.cancel(id.trim()); diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/backends/desktop_notification_backend.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/backends/desktop_notification_backend.dart index 7fdd5a8..497f848 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/backends/desktop_notification_backend.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/backends/desktop_notification_backend.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../desktop_notification_adapter_stub.dart'; /// Platform-neutral backend used by [DesktopNotificationAdapter]. diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/backends/desktop_notification_backend_factory.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/backends/desktop_notification_backend_factory.dart index 603ffb4..39626a7 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/backends/desktop_notification_backend_factory.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/backends/desktop_notification_backend_factory.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../desktop_notification_adapter_stub.dart'; /// Create the best default desktop notification backend. diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/backends/stdout_notification_backend.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/backends/stdout_notification_backend.dart index 38c59e2..797cc2d 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/backends/stdout_notification_backend.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/backends/stdout_notification_backend.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../desktop_notification_adapter_stub.dart'; /// Fallback backend that writes notification requests to stdout/logs. @@ -8,14 +11,20 @@ final class StdoutNotificationBackend implements DesktopNotificationBackend { required this.platform, }) : _logSink = logSink; + /// Private state stored as `_logSink` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final DesktopNotificationLogSink _logSink; /// Platform this fallback represents. final DesktopNotificationPlatform platform; + /// Returns the derived `isSupported` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override bool get isSupported => false; + /// Runs the `deliver` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future deliver(NotificationRequest request) async { _logSink( @@ -24,6 +33,8 @@ final class StdoutNotificationBackend implements DesktopNotificationBackend { ); } + /// Runs the `cancel` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future cancel(String id) async { _logSink('notification[$platform] cancel: ${id.trim()}'); diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/callbacks/default_log_sink.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/callbacks/default_log_sink.dart index 8ce5c09..a00c134 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/callbacks/default_log_sink.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/callbacks/default_log_sink.dart @@ -1,5 +1,10 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../desktop_notification_adapter_stub.dart'; +/// Top-level helper that performs the `_defaultLogSink` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. void _defaultLogSink(String line) { // ignore: avoid_print print(line); diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/callbacks/desktop_notification_log_sink.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/callbacks/desktop_notification_log_sink.dart index c81c5ed..b4f4dd3 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/callbacks/desktop_notification_log_sink.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/callbacks/desktop_notification_log_sink.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../desktop_notification_adapter_stub.dart'; /// Logging callback used by fallback notification backends. diff --git a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/platform/desktop_notification_platform.dart b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/platform/desktop_notification_platform.dart index 438c864..a15b633 100644 --- a/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/platform/desktop_notification_platform.dart +++ b/packages/scheduler_notifications_desktop/lib/src/desktop_notification_adapter_stub/platform/desktop_notification_platform.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../desktop_notification_adapter_stub.dart'; /// Supported desktop platform categories. diff --git a/packages/scheduler_notifications_desktop/pubspec.yaml b/packages/scheduler_notifications_desktop/pubspec.yaml index 71c23f7..aebf6bc 100644 --- a/packages/scheduler_notifications_desktop/pubspec.yaml +++ b/packages/scheduler_notifications_desktop/pubspec.yaml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + name: scheduler_notifications_desktop description: Desktop notification adapter for the ADHD scheduler. version: 0.1.0 diff --git a/packages/scheduler_notifications_desktop/test/desktop_notification_adapter_test.dart b/packages/scheduler_notifications_desktop/test/desktop_notification_adapter_test.dart index 40cd4c4..207f02d 100644 --- a/packages/scheduler_notifications_desktop/test/desktop_notification_adapter_test.dart +++ b/packages/scheduler_notifications_desktop/test/desktop_notification_adapter_test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Desktop Notification Adapter behavior for the Scheduler Notifications Desktop package. library; @@ -11,6 +14,8 @@ import '../../scheduler_notifications/test/notification_adapter_contract.dart'; // ignore: avoid_relative_lib_imports import '../lib/desktop_notifications.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { runNotificationAdapterContractTests('desktop', () { final backend = _RecordingBackend(); @@ -39,7 +44,7 @@ void main() { final logs = []; final backend = createDefaultDesktopNotificationBackend( platform: DesktopNotificationPlatform.linux, - processRunner: (executable, arguments) async { + processRunner: (String executable, List arguments) async { calls.add(_ProcessCall(executable, arguments)); return ProcessResult(1, 0, '', ''); }, @@ -58,7 +63,7 @@ void main() { final calls = <_ProcessCall>[]; final backend = createDefaultDesktopNotificationBackend( platform: DesktopNotificationPlatform.macos, - processRunner: (executable, arguments) async { + processRunner: (String executable, List arguments) async { calls.add(_ProcessCall(executable, arguments)); return ProcessResult(1, 0, '', ''); }, @@ -112,6 +117,8 @@ void main() { }); } +/// Top-level helper that performs the `_scheduleAndCancelReminder` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _scheduleAndCancelReminder( NotificationAdapter adapter, NotificationRequest request, @@ -120,6 +127,8 @@ Future _scheduleAndCancelReminder( await adapter.cancel(request.id); } +/// Top-level helper that performs the `_request` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. NotificationRequest _request(String id) { return NotificationRequest( id: id, @@ -129,27 +138,49 @@ NotificationRequest _request(String id) { ); } +/// Private implementation type for `_RecordingBackend` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. final class _RecordingBackend implements DesktopNotificationBackend { + /// Stores the `delivered` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final List delivered = []; + + /// Stores the `cancelled` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final List cancelled = []; + /// Returns the derived `isSupported` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override bool get isSupported => true; + /// Runs the `deliver` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future deliver(NotificationRequest request) async { delivered.add(request); } + /// Runs the `cancel` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future cancel(String id) async { cancelled.add(id); } } +/// Private implementation type for `_ProcessCall` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. final class _ProcessCall { + /// Creates a `_ProcessCall` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _ProcessCall(this.executable, this.arguments); + /// Stores the `executable` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String executable; + + /// Stores the `arguments` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final List arguments; } diff --git a/packages/scheduler_persistence/LICENSE.md b/packages/scheduler_persistence/LICENSE.md new file mode 100644 index 0000000..16fafd9 --- /dev/null +++ b/packages/scheduler_persistence/LICENSE.md @@ -0,0 +1,6 @@ + + + +# License + +This package uses the repository-level license at [../../LICENSE.md](../../LICENSE.md). diff --git a/packages/scheduler_persistence/analysis_options.yaml b/packages/scheduler_persistence/analysis_options.yaml index 572dd23..7df02e8 100644 --- a/packages/scheduler_persistence/analysis_options.yaml +++ b/packages/scheduler_persistence/analysis_options.yaml @@ -1 +1,4 @@ -include: package:lints/recommended.yaml +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + +include: ../../analysis_options.yaml diff --git a/packages/scheduler_persistence/lib/persistence.dart b/packages/scheduler_persistence/lib/persistence.dart index b3592a7..93546d6 100644 --- a/packages/scheduler_persistence/lib/persistence.dart +++ b/packages/scheduler_persistence/lib/persistence.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Domain-only repository contracts for scheduler persistence adapters. /// /// This package defines the stable boundary that SQLite, memory, and future diff --git a/packages/scheduler_persistence/lib/persistence/failures/core/repository_failure.dart b/packages/scheduler_persistence/lib/persistence/failures/core/repository_failure.dart index d7570f8..374db6d 100644 --- a/packages/scheduler_persistence/lib/persistence/failures/core/repository_failure.dart +++ b/packages/scheduler_persistence/lib/persistence/failures/core/repository_failure.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence.dart'; /// Adapter-neutral repository failure. sealed class RepositoryFailure { + /// Creates a `RepositoryFailure` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const RepositoryFailure({ this.entityId, this.expectedRevision, diff --git a/packages/scheduler_persistence/lib/persistence/failures/identity/repository_duplicate_id.dart b/packages/scheduler_persistence/lib/persistence/failures/identity/repository_duplicate_id.dart index 0b09ab4..7fc5705 100644 --- a/packages/scheduler_persistence/lib/persistence/failures/identity/repository_duplicate_id.dart +++ b/packages/scheduler_persistence/lib/persistence/failures/identity/repository_duplicate_id.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence.dart'; /// A record with the requested id already exists. diff --git a/packages/scheduler_persistence/lib/persistence/failures/identity/repository_not_found.dart b/packages/scheduler_persistence/lib/persistence/failures/identity/repository_not_found.dart index 628abf5..7ccf6b2 100644 --- a/packages/scheduler_persistence/lib/persistence/failures/identity/repository_not_found.dart +++ b/packages/scheduler_persistence/lib/persistence/failures/identity/repository_not_found.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence.dart'; /// The requested entity was not found. diff --git a/packages/scheduler_persistence/lib/persistence/failures/identity/repository_owner_mismatch.dart b/packages/scheduler_persistence/lib/persistence/failures/identity/repository_owner_mismatch.dart index 177b3ff..af3fefb 100644 --- a/packages/scheduler_persistence/lib/persistence/failures/identity/repository_owner_mismatch.dart +++ b/packages/scheduler_persistence/lib/persistence/failures/identity/repository_owner_mismatch.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence.dart'; /// The requested record exists under a different owner scope. diff --git a/packages/scheduler_persistence/lib/persistence/failures/revision/repository_invalid_revision.dart b/packages/scheduler_persistence/lib/persistence/failures/revision/repository_invalid_revision.dart index d0e7a62..8a30884 100644 --- a/packages/scheduler_persistence/lib/persistence/failures/revision/repository_invalid_revision.dart +++ b/packages/scheduler_persistence/lib/persistence/failures/revision/repository_invalid_revision.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence.dart'; /// The caller supplied an invalid revision value. diff --git a/packages/scheduler_persistence/lib/persistence/failures/revision/repository_stale_revision.dart b/packages/scheduler_persistence/lib/persistence/failures/revision/repository_stale_revision.dart index c4a413d..1de5aab 100644 --- a/packages/scheduler_persistence/lib/persistence/failures/revision/repository_stale_revision.dart +++ b/packages/scheduler_persistence/lib/persistence/failures/revision/repository_stale_revision.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence.dart'; /// The caller attempted to write using a stale revision. diff --git a/packages/scheduler_persistence/lib/persistence/failures/storage/repository_storage_failure.dart b/packages/scheduler_persistence/lib/persistence/failures/storage/repository_storage_failure.dart index 527b35b..887535e 100644 --- a/packages/scheduler_persistence/lib/persistence/failures/storage/repository_storage_failure.dart +++ b/packages/scheduler_persistence/lib/persistence/failures/storage/repository_storage_failure.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../persistence.dart'; /// The adapter could not complete the operation due to storage failure. diff --git a/packages/scheduler_persistence/lib/persistence/repositories/locked_block_repository.dart b/packages/scheduler_persistence/lib/persistence/repositories/locked_block_repository.dart index 7af0911..ddb631c 100644 --- a/packages/scheduler_persistence/lib/persistence/repositories/locked_block_repository.dart +++ b/packages/scheduler_persistence/lib/persistence/repositories/locked_block_repository.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence.dart'; /// Repository contract for locked blocks and date-scoped overrides. diff --git a/packages/scheduler_persistence/lib/persistence/repositories/project_repository.dart b/packages/scheduler_persistence/lib/persistence/repositories/project_repository.dart index 17b2d0c..344408e 100644 --- a/packages/scheduler_persistence/lib/persistence/repositories/project_repository.dart +++ b/packages/scheduler_persistence/lib/persistence/repositories/project_repository.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence.dart'; /// Repository contract for project profile records. diff --git a/packages/scheduler_persistence/lib/persistence/repositories/schedule_snapshot_repository.dart b/packages/scheduler_persistence/lib/persistence/repositories/schedule_snapshot_repository.dart index a3671ee..30fc0ab 100644 --- a/packages/scheduler_persistence/lib/persistence/repositories/schedule_snapshot_repository.dart +++ b/packages/scheduler_persistence/lib/persistence/repositories/schedule_snapshot_repository.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence.dart'; /// Repository contract for diagnostic schedule snapshots. diff --git a/packages/scheduler_persistence/lib/persistence/repositories/settings_repository.dart b/packages/scheduler_persistence/lib/persistence/repositories/settings_repository.dart index e38cbc5..1d540ec 100644 --- a/packages/scheduler_persistence/lib/persistence/repositories/settings_repository.dart +++ b/packages/scheduler_persistence/lib/persistence/repositories/settings_repository.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence.dart'; /// Repository contract for owner settings. diff --git a/packages/scheduler_persistence/lib/persistence/repositories/task_repository.dart b/packages/scheduler_persistence/lib/persistence/repositories/task_repository.dart index b0899da..49d8022 100644 --- a/packages/scheduler_persistence/lib/persistence/repositories/task_repository.dart +++ b/packages/scheduler_persistence/lib/persistence/repositories/task_repository.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence.dart'; /// Repository contract for task records. diff --git a/packages/scheduler_persistence/lib/persistence/results/either.dart b/packages/scheduler_persistence/lib/persistence/results/either.dart index f0125b4..b8c1097 100644 --- a/packages/scheduler_persistence/lib/persistence/results/either.dart +++ b/packages/scheduler_persistence/lib/persistence/results/either.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence.dart'; /// Minimal Either type for expected repository success/failure paths. sealed class Either { + /// Creates a `Either` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const Either(); /// Whether this value is a left/failure value. diff --git a/packages/scheduler_persistence/lib/persistence/results/left.dart b/packages/scheduler_persistence/lib/persistence/results/left.dart index 62196b1..288866c 100644 --- a/packages/scheduler_persistence/lib/persistence/results/left.dart +++ b/packages/scheduler_persistence/lib/persistence/results/left.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence.dart'; /// Failure side of [Either]. diff --git a/packages/scheduler_persistence/lib/persistence/results/repo_result.dart b/packages/scheduler_persistence/lib/persistence/results/repo_result.dart index 7560b89..e91dde6 100644 --- a/packages/scheduler_persistence/lib/persistence/results/repo_result.dart +++ b/packages/scheduler_persistence/lib/persistence/results/repo_result.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence.dart'; /// Repository result wrapper for expected adapter outcomes. diff --git a/packages/scheduler_persistence/lib/persistence/results/right.dart b/packages/scheduler_persistence/lib/persistence/results/right.dart index caca5da..2932ea4 100644 --- a/packages/scheduler_persistence/lib/persistence/results/right.dart +++ b/packages/scheduler_persistence/lib/persistence/results/right.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence.dart'; /// Success side of [Either]. diff --git a/packages/scheduler_persistence/pubspec.yaml b/packages/scheduler_persistence/pubspec.yaml index 3d050ef..723b54b 100644 --- a/packages/scheduler_persistence/pubspec.yaml +++ b/packages/scheduler_persistence/pubspec.yaml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + name: scheduler_persistence description: Domain-only repository contracts for the ADHD scheduler. version: 0.1.0 diff --git a/packages/scheduler_persistence/test/repo_conformance.dart b/packages/scheduler_persistence/test/repo_conformance.dart index 024e765..a59da81 100644 --- a/packages/scheduler_persistence/test/repo_conformance.dart +++ b/packages/scheduler_persistence/test/repo_conformance.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Repo Conformance behavior for the Scheduler Persistence package. library; @@ -7,6 +10,8 @@ import 'package:test/test.dart'; /// Factory set used by adapter packages to run the shared repository contract. final class RepositoryComplianceFactories { + /// Creates a `RepositoryComplianceFactories` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const RepositoryComplianceFactories({ required this.taskRepository, required this.projectRepository, @@ -15,10 +20,24 @@ final class RepositoryComplianceFactories { required this.scheduleSnapshotRepository, }); + /// Stores the `taskRepository` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final TaskRepository Function() taskRepository; + + /// Stores the `projectRepository` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ProjectRepository Function() projectRepository; + + /// Stores the `lockedBlockRepository` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final LockedBlockRepository Function() lockedBlockRepository; + + /// Stores the `settingsRepository` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final SettingsRepository Function() settingsRepository; + + /// Stores the `scheduleSnapshotRepository` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final ScheduleSnapshotRepository Function() scheduleSnapshotRepository; } @@ -384,10 +403,14 @@ void runRepositoryComplianceTests(RepositoryComplianceFactories factories) { }); } +/// Top-level helper that performs the `_instant` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. DateTime _instant(int day, {int hour = 9}) { return DateTime.utc(2026, 1, 1 + day, hour); } +/// Top-level helper that performs the `_task` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.Task _task( String id, { String projectId = 'project-a', @@ -407,6 +430,8 @@ core.Task _task( ); } +/// Top-level helper that performs the `_project` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.ProjectProfile _project(String id) { return core.ProjectProfile( id: id, @@ -416,6 +441,8 @@ core.ProjectProfile _project(String id) { ); } +/// Top-level helper that performs the `_lockedBlock` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.LockedBlock _lockedBlock(String id) { return core.LockedBlock( id: id, @@ -428,6 +455,8 @@ core.LockedBlock _lockedBlock(String id) { ); } +/// Top-level helper that performs the `_override` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.LockedBlockOverride _override( String id, { String name = 'Added block', @@ -442,6 +471,8 @@ core.LockedBlockOverride _override( ); } +/// Top-level helper that performs the `_settings` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.OwnerSettings _settings(String ownerId) { return core.OwnerSettings( ownerId: ownerId, @@ -451,6 +482,8 @@ core.OwnerSettings _settings(String ownerId) { ); } +/// Top-level helper that performs the `_snapshot` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.SchedulingStateSnapshot _snapshot(String id) { return core.SchedulingStateSnapshot( id: id, diff --git a/packages/scheduler_persistence/test/repo_contract_smoke_test.dart b/packages/scheduler_persistence/test/repo_contract_smoke_test.dart index 6ac1102..28155b7 100644 --- a/packages/scheduler_persistence/test/repo_contract_smoke_test.dart +++ b/packages/scheduler_persistence/test/repo_contract_smoke_test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Repo Contract Smoke behavior for the Scheduler Persistence package. library; @@ -5,6 +8,8 @@ import 'package:scheduler_core/scheduler_core.dart' as core; import 'package:scheduler_persistence/persistence.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { group('repository contract smoke test', () { test('exports required repository interfaces', () { diff --git a/packages/scheduler_persistence_memory/LICENSE.md b/packages/scheduler_persistence_memory/LICENSE.md new file mode 100644 index 0000000..16fafd9 --- /dev/null +++ b/packages/scheduler_persistence_memory/LICENSE.md @@ -0,0 +1,6 @@ + + + +# License + +This package uses the repository-level license at [../../LICENSE.md](../../LICENSE.md). diff --git a/packages/scheduler_persistence_memory/analysis_options.yaml b/packages/scheduler_persistence_memory/analysis_options.yaml index 572dd23..7df02e8 100644 --- a/packages/scheduler_persistence_memory/analysis_options.yaml +++ b/packages/scheduler_persistence_memory/analysis_options.yaml @@ -1 +1,4 @@ -include: package:lints/recommended.yaml +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + +include: ../../analysis_options.yaml diff --git a/packages/scheduler_persistence_memory/lib/memory.dart b/packages/scheduler_persistence_memory/lib/memory.dart index 3b2621a..0ba6782 100644 --- a/packages/scheduler_persistence_memory/lib/memory.dart +++ b/packages/scheduler_persistence_memory/lib/memory.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Compatibility entry point for in-memory scheduler persistence adapters. library; diff --git a/packages/scheduler_persistence_memory/lib/persistence_memory.dart b/packages/scheduler_persistence_memory/lib/persistence_memory.dart index 59d9e92..c4236cc 100644 --- a/packages/scheduler_persistence_memory/lib/persistence_memory.dart +++ b/packages/scheduler_persistence_memory/lib/persistence_memory.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// In-memory implementations of the scheduler persistence repository contracts. /// /// These repositories are intended for core tests, local integration tests, and @@ -18,6 +21,10 @@ part 'persistence_memory/records/identified_record.dart'; part 'persistence_memory/records/record.dart'; part 'persistence_memory/records/snapshot_record.dart'; +/// Private file-level value for `_snapshotRetention`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _snapshotRetention = Duration(days: 30); +/// Private file-level value for `_epoch`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. final _epoch = DateTime.fromMillisecondsSinceEpoch(0, isUtc: true); diff --git a/packages/scheduler_persistence_memory/lib/persistence_memory/records/identified_record.dart b/packages/scheduler_persistence_memory/lib/persistence_memory/records/identified_record.dart index c665128..9dcc908 100644 --- a/packages/scheduler_persistence_memory/lib/persistence_memory/records/identified_record.dart +++ b/packages/scheduler_persistence_memory/lib/persistence_memory/records/identified_record.dart @@ -1,5 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_memory.dart'; +/// Private implementation type for `_IdentifiedRecord` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. abstract interface class _IdentifiedRecord { + /// Returns the derived `id` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. String get id; } diff --git a/packages/scheduler_persistence_memory/lib/persistence_memory/records/record.dart b/packages/scheduler_persistence_memory/lib/persistence_memory/records/record.dart index ee22723..f4ff449 100644 --- a/packages/scheduler_persistence_memory/lib/persistence_memory/records/record.dart +++ b/packages/scheduler_persistence_memory/lib/persistence_memory/records/record.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_memory.dart'; +/// Private implementation type for `_Record` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. final class _Record implements _IdentifiedRecord { + /// Creates a `_Record` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _Record({ required this.id, required this.ownerId, @@ -11,14 +18,33 @@ final class _Record implements _IdentifiedRecord { }) : createdAt = createdAt ?? _epoch, updatedAt = updatedAt ?? _epoch; + /// Stores the `id` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. @override final String id; + + /// Stores the `ownerId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final core.OwnerId ownerId; + + /// Stores the `value` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final T value; + + /// Stores the `revision` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final core.Revision revision; + + /// Stores the `createdAt` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DateTime createdAt; + + /// Stores the `updatedAt` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DateTime updatedAt; + /// Returns a copy of this value with selected fields replaced. + /// The scheduler uses copy-style updates to keep domain values immutable and make before-and-after behavior easier to test. _Record copyWith({ T? value, core.Revision? revision, diff --git a/packages/scheduler_persistence_memory/lib/persistence_memory/records/snapshot_record.dart b/packages/scheduler_persistence_memory/lib/persistence_memory/records/snapshot_record.dart index 3e3416e..ee07118 100644 --- a/packages/scheduler_persistence_memory/lib/persistence_memory/records/snapshot_record.dart +++ b/packages/scheduler_persistence_memory/lib/persistence_memory/records/snapshot_record.dart @@ -1,6 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_memory.dart'; +/// Private implementation type for `_SnapshotRecord` in this library. +/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. final class _SnapshotRecord implements _IdentifiedRecord { + /// Creates a `_SnapshotRecord` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. _SnapshotRecord({ required this.id, required this.ownerId, @@ -9,10 +16,24 @@ final class _SnapshotRecord implements _IdentifiedRecord { required this.retentionExpiresAt, }); + /// Stores the `id` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. @override final String id; + + /// Stores the `ownerId` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final core.OwnerId ownerId; + + /// Stores the `value` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final core.SchedulingStateSnapshot value; + + /// Stores the `revision` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final core.Revision revision; + + /// Stores the `retentionExpiresAt` value for this object. + /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final DateTime retentionExpiresAt; } diff --git a/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_locked_block_repository.dart b/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_locked_block_repository.dart index 7a686b7..497c4c0 100644 --- a/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_locked_block_repository.dart +++ b/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_locked_block_repository.dart @@ -1,12 +1,22 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_memory.dart'; /// In-memory locked-block repository with owner scoping and revision checks. final class InMemoryLockedBlockRepository implements LockedBlockRepository { + /// Private state stored as `_blocks` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map> _blocks = >{}; + + /// Private state stored as `_overrides` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map> _overrides = >{}; + /// Runs the `findBlockById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findBlockById({ required core.OwnerId ownerId, @@ -20,6 +30,8 @@ final class InMemoryLockedBlockRepository implements LockedBlockRepository { _cloneLockedBlock(record.value, record.ownerId, record.revision)); } + /// Runs the `findBlocksByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findBlocksByOwner({ required core.OwnerId ownerId, @@ -41,6 +53,8 @@ final class InMemoryLockedBlockRepository implements LockedBlockRepository { )); } + /// Runs the `findOverrideById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findOverrideById({ required core.OwnerId ownerId, @@ -55,6 +69,8 @@ final class InMemoryLockedBlockRepository implements LockedBlockRepository { ); } + /// Runs the `findOverridesForDate` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findOverridesForDate({ required core.OwnerId ownerId, @@ -74,6 +90,8 @@ final class InMemoryLockedBlockRepository implements LockedBlockRepository { )); } + /// Runs the `insertBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> insertBlock({ required core.OwnerId ownerId, @@ -91,6 +109,8 @@ final class InMemoryLockedBlockRepository implements LockedBlockRepository { return const Right(core.Revision.initial); } + /// Runs the `saveBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> saveBlock({ required core.OwnerId ownerId, @@ -116,6 +136,8 @@ final class InMemoryLockedBlockRepository implements LockedBlockRepository { return Right(nextRevision); } + /// Runs the `archiveBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> archiveBlock({ required core.OwnerId ownerId, @@ -143,6 +165,8 @@ final class InMemoryLockedBlockRepository implements LockedBlockRepository { return Right(nextRevision); } + /// Runs the `insertOverride` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> insertOverride({ required core.OwnerId ownerId, @@ -164,6 +188,8 @@ final class InMemoryLockedBlockRepository implements LockedBlockRepository { return const Right(core.Revision.initial); } + /// Runs the `saveOverride` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> saveOverride({ required core.OwnerId ownerId, diff --git a/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_project_repository.dart b/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_project_repository.dart index 58768ba..bf146db 100644 --- a/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_project_repository.dart +++ b/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_project_repository.dart @@ -1,10 +1,17 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_memory.dart'; /// In-memory project repository with owner scoping and revision checks. final class InMemoryProjectRepository implements ProjectRepository { + /// Private state stored as `_records` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map> _records = >{}; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findById({ required core.OwnerId ownerId, @@ -17,6 +24,8 @@ final class InMemoryProjectRepository implements ProjectRepository { return Right(_cloneProject(record)); } + /// Runs the `findByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findByOwner({ required core.OwnerId ownerId, @@ -34,6 +43,8 @@ final class InMemoryProjectRepository implements ProjectRepository { )); } + /// Runs the `insert` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> insert({ required core.OwnerId ownerId, @@ -59,6 +70,8 @@ final class InMemoryProjectRepository implements ProjectRepository { return const Right(core.Revision.initial); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> save({ required core.OwnerId ownerId, @@ -90,6 +103,8 @@ final class InMemoryProjectRepository implements ProjectRepository { return Right(nextRevision); } + /// Runs the `archive` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> archive({ required core.OwnerId ownerId, diff --git a/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_schedule_snapshot_repository.dart b/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_schedule_snapshot_repository.dart index 9661c11..ca2c902 100644 --- a/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_schedule_snapshot_repository.dart +++ b/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_schedule_snapshot_repository.dart @@ -1,10 +1,17 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_memory.dart'; /// In-memory diagnostic schedule snapshot repository. final class InMemoryScheduleSnapshotRepository implements ScheduleSnapshotRepository { + /// Private state stored as `_records` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map _records = {}; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findById({ required core.OwnerId ownerId, @@ -17,6 +24,8 @@ final class InMemoryScheduleSnapshotRepository return Right(_cloneSnapshot(record.value, record.ownerId, record.revision)); } + /// Runs the `findInWindow` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findInWindow({ required core.OwnerId ownerId, @@ -34,6 +43,8 @@ final class InMemoryScheduleSnapshotRepository )); } + /// Runs the `insert` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> insert({ required core.OwnerId ownerId, @@ -52,6 +63,8 @@ final class InMemoryScheduleSnapshotRepository return const Right(core.Revision.initial); } + /// Runs the `deleteExpired` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> deleteExpired({ required core.OwnerId ownerId, @@ -72,6 +85,8 @@ final class InMemoryScheduleSnapshotRepository } } +/// Top-level helper that performs the `_checkWrite` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Either> _checkWrite({ required Map> records, required String id, @@ -105,6 +120,8 @@ Either> _checkWrite({ return Right(record); } +/// Runs the `R>` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. core.Page _pageRecords( Iterable records, core.PageRequest page, @@ -119,6 +136,8 @@ core.Page _pageRecords( return core.Page(items: items, nextCursor: nextCursor); } +/// Top-level helper that performs the `_cursorOffset` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _cursorOffset(String? cursor) { if (cursor == null) { return 0; @@ -130,10 +149,14 @@ int _cursorOffset(String? cursor) { return parsed; } +/// Top-level helper that performs the `_windowsOverlap` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _windowsOverlap(core.SchedulingWindow left, core.SchedulingWindow right) { return left.start.isBefore(right.end) && right.start.isBefore(left.end); } +/// Top-level helper that performs the `_cloneTask` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.Task _cloneTask( core.Task task, core.OwnerId ownerId, @@ -148,6 +171,8 @@ core.Task _cloneTask( )); } +/// Top-level helper that performs the `_cloneProject` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.ProjectProfile _cloneProject(_Record record) { return _cloneProjectValue( record.value, @@ -158,6 +183,8 @@ core.ProjectProfile _cloneProject(_Record record) { ); } +/// Top-level helper that performs the `_cloneProjectValue` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.ProjectProfile _cloneProjectValue( core.ProjectProfile project, { required core.OwnerId ownerId, @@ -176,6 +203,8 @@ core.ProjectProfile _cloneProjectValue( )); } +/// Top-level helper that performs the `_cloneLockedBlock` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.LockedBlock _cloneLockedBlock( core.LockedBlock block, core.OwnerId ownerId, @@ -190,6 +219,8 @@ core.LockedBlock _cloneLockedBlock( )); } +/// Top-level helper that performs the `_cloneLockedBlockOverride` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.LockedBlockOverride _cloneLockedBlockOverride( core.LockedBlockOverride override, core.OwnerId ownerId, @@ -204,6 +235,8 @@ core.LockedBlockOverride _cloneLockedBlockOverride( )); } +/// Top-level helper that performs the `_cloneSettings` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.OwnerSettings _cloneSettings(_Record record) { return _cloneSettingsValue( record.value, @@ -213,6 +246,8 @@ core.OwnerSettings _cloneSettings(_Record record) { ); } +/// Top-level helper that performs the `_cloneSettingsValue` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.OwnerSettings _cloneSettingsValue( core.OwnerSettings settings, { required core.Revision revision, @@ -229,6 +264,8 @@ core.OwnerSettings _cloneSettingsValue( )); } +/// Top-level helper that performs the `_cloneSnapshot` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.SchedulingStateSnapshot _cloneSnapshot( core.SchedulingStateSnapshot snapshot, core.OwnerId ownerId, @@ -244,6 +281,8 @@ core.SchedulingStateSnapshot _cloneSnapshot( )); } +/// Top-level helper that performs the `_roundTrip` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _roundTrip(Map document) { return Map.from( jsonDecode(jsonEncode(document)) as Map, diff --git a/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_settings_repository.dart b/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_settings_repository.dart index dc86418..fadfca1 100644 --- a/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_settings_repository.dart +++ b/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_settings_repository.dart @@ -1,10 +1,17 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_memory.dart'; /// In-memory owner settings repository with owner scoping and revision checks. final class InMemorySettingsRepository implements SettingsRepository { + /// Private state stored as `_records` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map> _records = >{}; + /// Runs the `findByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByOwner({ required core.OwnerId ownerId, @@ -16,6 +23,8 @@ final class InMemorySettingsRepository implements SettingsRepository { return Right(_cloneSettings(record)); } + /// Runs the `insert` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> insert({ required core.OwnerId ownerId, @@ -43,6 +52,8 @@ final class InMemorySettingsRepository implements SettingsRepository { return const Right(core.Revision.initial); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> save({ required core.OwnerId ownerId, diff --git a/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_task_repository.dart b/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_task_repository.dart index 1fd8976..6f5bd66 100644 --- a/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_task_repository.dart +++ b/packages/scheduler_persistence_memory/lib/persistence_memory/repositories/in_memory_task_repository.dart @@ -1,10 +1,17 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../persistence_memory.dart'; /// In-memory task repository with owner scoping and revision checks. final class InMemoryTaskRepository implements TaskRepository { + /// Private state stored as `_records` for this implementation. + /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior. final Map> _records = >{}; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findById({ required core.OwnerId ownerId, @@ -17,6 +24,8 @@ final class InMemoryTaskRepository implements TaskRepository { return Right(_cloneTask(record.value, record.ownerId, record.revision)); } + /// Runs the `findByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findByOwner({ required core.OwnerId ownerId, @@ -29,6 +38,8 @@ final class InMemoryTaskRepository implements TaskRepository { )); } + /// Runs the `findByParentTaskId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findByParentTaskId({ required core.OwnerId ownerId, @@ -46,6 +57,8 @@ final class InMemoryTaskRepository implements TaskRepository { )); } + /// Runs the `findByProjectId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findByProjectId({ required core.OwnerId ownerId, @@ -62,6 +75,8 @@ final class InMemoryTaskRepository implements TaskRepository { )); } + /// Runs the `findByStatus` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findByStatus({ required core.OwnerId ownerId, @@ -77,6 +92,8 @@ final class InMemoryTaskRepository implements TaskRepository { )); } + /// Runs the `insert` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> insert({ required core.OwnerId ownerId, @@ -94,6 +111,8 @@ final class InMemoryTaskRepository implements TaskRepository { return const Right(core.Revision.initial); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> save({ required core.OwnerId ownerId, @@ -119,6 +138,8 @@ final class InMemoryTaskRepository implements TaskRepository { return Right(nextRevision); } + /// Runs the `delete` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> delete({ required core.OwnerId ownerId, diff --git a/packages/scheduler_persistence_memory/pubspec.yaml b/packages/scheduler_persistence_memory/pubspec.yaml index add5b9a..6db2fe6 100644 --- a/packages/scheduler_persistence_memory/pubspec.yaml +++ b/packages/scheduler_persistence_memory/pubspec.yaml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + name: scheduler_persistence_memory publish_to: none diff --git a/packages/scheduler_persistence_memory/test/memory_repository_conformance_test.dart b/packages/scheduler_persistence_memory/test/memory_repository_conformance_test.dart index 2d5f076..0c2b05e 100644 --- a/packages/scheduler_persistence_memory/test/memory_repository_conformance_test.dart +++ b/packages/scheduler_persistence_memory/test/memory_repository_conformance_test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Memory Repository Conformance behavior for the Scheduler Persistence Memory package. library; @@ -5,6 +8,8 @@ import 'package:scheduler_persistence_memory/persistence_memory.dart'; import '../../scheduler_persistence/test/repo_conformance.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { runRepositoryComplianceTests( RepositoryComplianceFactories( diff --git a/packages/scheduler_persistence_sqlite/LICENSE.md b/packages/scheduler_persistence_sqlite/LICENSE.md new file mode 100644 index 0000000..16fafd9 --- /dev/null +++ b/packages/scheduler_persistence_sqlite/LICENSE.md @@ -0,0 +1,6 @@ + + + +# License + +This package uses the repository-level license at [../../LICENSE.md](../../LICENSE.md). diff --git a/packages/scheduler_persistence_sqlite/analysis_options.yaml b/packages/scheduler_persistence_sqlite/analysis_options.yaml index 572dd23..7df02e8 100644 --- a/packages/scheduler_persistence_sqlite/analysis_options.yaml +++ b/packages/scheduler_persistence_sqlite/analysis_options.yaml @@ -1 +1,4 @@ -include: package:lints/recommended.yaml +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + +include: ../../analysis_options.yaml diff --git a/packages/scheduler_persistence_sqlite/lib/sqlite.dart b/packages/scheduler_persistence_sqlite/lib/sqlite.dart index be88c1d..57cecc4 100644 --- a/packages/scheduler_persistence_sqlite/lib/sqlite.dart +++ b/packages/scheduler_persistence_sqlite/lib/sqlite.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Drift-backed SQLite persistence surface for the scheduler. library; diff --git a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db.dart b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db.dart index 10cf902..66b8cd7 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Drift schema for the scheduler's local SQLite database. /// /// This package owns SQLite and Drift details. The scheduler core continues to diff --git a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/locked_block_dao.dart b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/locked_block_dao.dart index bf231af..54d9f48 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/locked_block_dao.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/locked_block_dao.dart @@ -1,8 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../scheduler_db.dart'; /// Generated locked-time accessors for blocks and date overrides. @DriftAccessor(tables: [LockedBlocks, LockedOverrides]) class LockedBlockDao extends DatabaseAccessor with _$LockedBlockDaoMixin { + /// Creates a `LockedBlockDao` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. LockedBlockDao(super.db); } diff --git a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/project_dao.dart b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/project_dao.dart index 2cef75d..1b1e08a 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/project_dao.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/project_dao.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../scheduler_db.dart'; /// Generated project-row accessor. @DriftAccessor(tables: [Projects]) class ProjectDao extends DatabaseAccessor with _$ProjectDaoMixin { + /// Creates a `ProjectDao` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. ProjectDao(super.db); } diff --git a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/settings_dao.dart b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/settings_dao.dart index 9e384f7..55f6841 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/settings_dao.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/settings_dao.dart @@ -1,8 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../scheduler_db.dart'; /// Generated owner-settings accessor. @DriftAccessor(tables: [SettingsTable]) class SettingsDao extends DatabaseAccessor with _$SettingsDaoMixin { + /// Creates a `SettingsDao` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. SettingsDao(super.db); } diff --git a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/snapshot_dao.dart b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/snapshot_dao.dart index 174f9c0..8bb67cb 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/snapshot_dao.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/snapshot_dao.dart @@ -1,8 +1,13 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../scheduler_db.dart'; /// Generated diagnostic snapshot accessor. @DriftAccessor(tables: [Snapshots]) class SnapshotDao extends DatabaseAccessor with _$SnapshotDaoMixin { + /// Creates a `SnapshotDao` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. SnapshotDao(super.db); } diff --git a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/task_dao.dart b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/task_dao.dart index fe6f0e6..98f4939 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/task_dao.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/task_dao.dart @@ -1,7 +1,12 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../scheduler_db.dart'; /// Generated task-row accessor. @DriftAccessor(tables: [Tasks]) class TaskDao extends DatabaseAccessor with _$TaskDaoMixin { + /// Creates a `TaskDao` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. TaskDao(super.db); } diff --git a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/database/scheduler_db.dart b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/database/scheduler_db.dart index b09c9c8..d2115be 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/database/scheduler_db.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/database/scheduler_db.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../scheduler_db.dart'; /// Drift database for scheduler persistence. @@ -19,11 +22,17 @@ part of '../../scheduler_db.dart'; ], ) class SchedulerDb extends _$SchedulerDb { + /// Creates a `SchedulerDb` instance with the values required by its invariants. + /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. SchedulerDb(super.executor); + /// Returns the derived `schemaVersion` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override int get schemaVersion => 1; + /// Runs the `migration` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override MigrationStrategy get migration => MigrationStrategy( onCreate: (Migrator migrator) async { diff --git a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/locked_time/locked_blocks.dart b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/locked_time/locked_blocks.dart index df0350d..403da32 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/locked_time/locked_blocks.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/locked_time/locked_blocks.dart @@ -1,23 +1,66 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduler_db.dart'; /// Recurring and one-off locked-time rows. @DataClassName('LockedBlockRow') class LockedBlocks extends Table { + /// Returns the derived `id` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get id => text()(); + + /// Returns the derived `ownerId` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get ownerId => text().named('owner_id')(); + + /// Returns the derived `name` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get name => text()(); + + /// Returns the derived `date` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get date => text().nullable()(); + + /// Returns the derived `startTime` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get startTime => text().named('start_time')(); + + /// Returns the derived `endTime` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get endTime => text().named('end_time')(); + + /// Converts scheduler data for `recurrenceJson` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. TextColumn get recurrenceJson => text().named('recurrence_json').nullable()(); + + /// Returns the derived `hiddenByDefault` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. BoolColumn get hiddenByDefault => boolean().named('hidden_by_default')(); + + /// Returns the derived `projectId` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get projectId => text().named('project_id').nullable()(); + + /// Returns the derived `archivedAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get archivedAtUtc => dateTime().named('archived_at_utc').nullable()(); + + /// Returns the derived `revision` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. IntColumn get revision => integer()(); + + /// Returns the derived `createdAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get createdAtUtc => dateTime().named('created_at_utc')(); + + /// Returns the derived `updatedAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get updatedAtUtc => dateTime().named('updated_at_utc')(); + /// Returns the derived `primaryKey` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override Set> get primaryKey => {id}; } diff --git a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/locked_time/locked_overrides.dart b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/locked_time/locked_overrides.dart index d5381c5..5d955ba 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/locked_time/locked_overrides.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/locked_time/locked_overrides.dart @@ -1,22 +1,65 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduler_db.dart'; /// Date-scoped overrides for recurring locked blocks. @DataClassName('LockedOverrideRow') class LockedOverrides extends Table { + /// Returns the derived `id` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get id => text()(); + + /// Returns the derived `ownerId` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get ownerId => text().named('owner_id')(); + + /// Returns the derived `lockedBlockId` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get lockedBlockId => text().named('locked_block_id').nullable()(); + + /// Returns the derived `date` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get date => text()(); + + /// Returns the derived `type` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get type => text()(); + + /// Returns the derived `name` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get name => text().nullable()(); + + /// Returns the derived `startTime` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get startTime => text().named('start_time').nullable()(); + + /// Returns the derived `endTime` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get endTime => text().named('end_time').nullable()(); + + /// Returns the derived `hiddenByDefault` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. BoolColumn get hiddenByDefault => boolean().named('hidden_by_default')(); + + /// Returns the derived `projectId` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get projectId => text().named('project_id').nullable()(); + + /// Returns the derived `revision` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. IntColumn get revision => integer()(); + + /// Returns the derived `createdAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get createdAtUtc => dateTime().named('created_at_utc')(); + + /// Returns the derived `updatedAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get updatedAtUtc => dateTime().named('updated_at_utc')(); + /// Returns the derived `primaryKey` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override Set> get primaryKey => {id}; } diff --git a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/projects/projects.dart b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/projects/projects.dart index 742da1d..59a675f 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/projects/projects.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/projects/projects.dart @@ -1,25 +1,68 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduler_db.dart'; /// Project configuration rows. @DataClassName('ProjectRow') class Projects extends Table { + /// Returns the derived `id` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get id => text()(); + + /// Returns the derived `ownerId` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get ownerId => text().named('owner_id')(); + + /// Returns the derived `name` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get name => text()(); + + /// Returns the derived `colorKey` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get colorKey => text().named('color_key')(); + + /// Returns the derived `defaultPriority` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get defaultPriority => text().named('default_priority')(); + + /// Returns the derived `defaultReward` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get defaultReward => text().named('default_reward')(); + + /// Returns the derived `defaultDifficulty` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get defaultDifficulty => text().named('default_difficulty')(); + + /// Returns the derived `defaultReminderProfile` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get defaultReminderProfile => text().named('default_reminder_profile')(); + + /// Returns the derived `defaultDurationMinutes` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. IntColumn get defaultDurationMinutes => integer().named('default_duration_minutes').nullable()(); + + /// Returns the derived `archivedAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get archivedAtUtc => dateTime().named('archived_at_utc').nullable()(); + + /// Returns the derived `revision` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. IntColumn get revision => integer()(); + + /// Returns the derived `createdAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get createdAtUtc => dateTime().named('created_at_utc')(); + + /// Returns the derived `updatedAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get updatedAtUtc => dateTime().named('updated_at_utc')(); + /// Returns the derived `primaryKey` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override Set> get primaryKey => {id}; } diff --git a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/settings/settings_table.dart b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/settings/settings_table.dart index 1e7a0c5..b436228 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/settings/settings_table.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/settings/settings_table.dart @@ -1,22 +1,55 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduler_db.dart'; /// Owner-level settings rows. @DataClassName('SettingsRow') class SettingsTable extends Table { + /// Returns the derived `tableName` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override String get tableName => 'settings'; + /// Returns the derived `ownerId` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get ownerId => text().named('owner_id')(); + + /// Returns the derived `timeZoneId` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get timeZoneId => text().named('timezone_id')(); + + /// Returns the derived `dayStartMinutes` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. IntColumn get dayStartMinutes => integer().named('day_start_minutes')(); + + /// Returns the derived `dayEndMinutes` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. IntColumn get dayEndMinutes => integer().named('day_end_minutes')(); + + /// Returns the derived `compactMode` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. BoolColumn get compactMode => boolean().named('compact_mode')(); + + /// Converts scheduler data for `backlogStalenessJson` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. TextColumn get backlogStalenessJson => text().named('backlog_staleness_json')(); + + /// Returns the derived `revision` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. IntColumn get revision => integer()(); + + /// Returns the derived `createdAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get createdAtUtc => dateTime().named('created_at_utc')(); + + /// Returns the derived `updatedAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get updatedAtUtc => dateTime().named('updated_at_utc')(); + /// Returns the derived `primaryKey` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override Set> get primaryKey => {ownerId}; } diff --git a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/snapshots/snapshots.dart b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/snapshots/snapshots.dart index 892d56c..c86386f 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/snapshots/snapshots.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/snapshots/snapshots.dart @@ -1,29 +1,87 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduler_db.dart'; /// Bounded diagnostic schedule snapshots. @DataClassName('SnapshotRow') class Snapshots extends Table { + /// Returns the derived `id` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get id => text()(); + + /// Returns the derived `ownerId` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get ownerId => text().named('owner_id')(); + + /// Returns the derived `capturedAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get capturedAtUtc => dateTime().named('captured_at_utc')(); + + /// Returns the derived `operationName` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get operationName => text().named('operation_name').nullable()(); + + /// Returns the derived `sourceDate` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get sourceDate => text().named('source_date').nullable()(); + + /// Returns the derived `targetDate` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get targetDate => text().named('target_date').nullable()(); + + /// Converts scheduler data for `windowJson` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. TextColumn get windowJson => text().named('window_json')(); + + /// Converts scheduler data for `tasksJson` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. TextColumn get tasksJson => text().named('tasks_json')(); + + /// Converts scheduler data for `lockedIntervalsJson` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. TextColumn get lockedIntervalsJson => text().named('locked_intervals_json')(); + + /// Converts scheduler data for `requiredVisibleIntervalsJson` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. TextColumn get requiredVisibleIntervalsJson => text().named('required_visible_intervals_json')(); + + /// Converts scheduler data for `noticesJson` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. TextColumn get noticesJson => text().named('notices_json')(); + + /// Converts scheduler data for `changesJson` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. TextColumn get changesJson => text().named('changes_json')(); + + /// Converts scheduler data for `overlapsJson` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. TextColumn get overlapsJson => text().named('overlaps_json')(); + + /// Returns the derived `retentionExpiresUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get retentionExpiresUtc => dateTime().named('retention_expires_utc')(); + + /// Returns the derived `truncated` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. BoolColumn get truncated => boolean()(); + + /// Returns the derived `revision` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. IntColumn get revision => integer()(); + + /// Returns the derived `createdAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get createdAtUtc => dateTime().named('created_at_utc')(); + + /// Returns the derived `updatedAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get updatedAtUtc => dateTime().named('updated_at_utc')(); + /// Returns the derived `primaryKey` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override Set> get primaryKey => {id}; } diff --git a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/tasks/tasks.dart b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/tasks/tasks.dart index ea73624..0fbf2c3 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/tasks/tasks.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/tasks/tasks.dart @@ -1,42 +1,118 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../../../scheduler_db.dart'; /// Authoritative task rows. @DataClassName('TaskRow') class Tasks extends Table { + /// Returns the derived `id` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get id => text()(); + + /// Returns the derived `ownerId` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get ownerId => text().named('owner_id')(); + + /// Returns the derived `title` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get title => text()(); + + /// Returns the derived `projectId` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get projectId => text().named('project_id')(); + + /// Returns the derived `parentId` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get parentId => text().named('parent_id').nullable()(); + + /// Returns the derived `type` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get type => text()(); + + /// Returns the derived `status` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get status => text()(); + + /// Returns the derived `priority` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get priority => text().nullable()(); + + /// Returns the derived `reward` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get reward => text()(); + + /// Returns the derived `difficulty` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get difficulty => text()(); + + /// Returns the derived `durationMinutes` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. IntColumn get durationMinutes => integer().named('duration_minutes').nullable()(); + + /// Returns the derived `scheduledStartUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get scheduledStartUtc => dateTime().named('scheduled_start_utc').nullable()(); + + /// Returns the derived `scheduledEndUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get scheduledEndUtc => dateTime().named('scheduled_end_utc').nullable()(); + + /// Returns the derived `actualStartUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get actualStartUtc => dateTime().named('actual_start_utc').nullable()(); + + /// Returns the derived `actualEndUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get actualEndUtc => dateTime().named('actual_end_utc').nullable()(); + + /// Returns the derived `completedAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get completedAtUtc => dateTime().named('completed_at_utc').nullable()(); + + /// Converts scheduler data for `backlogTagsJson` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. TextColumn get backlogTagsJson => text().named('backlog_tags_json')(); + + /// Returns the derived `reminderOverride` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get reminderOverride => text().named('reminder_override').nullable()(); + + /// Converts scheduler data for `statsJson` without changing the source object. + /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details. TextColumn get statsJson => text().named('stats_json')(); + + /// Returns the derived `backlogEnteredAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get backlogEnteredAtUtc => dateTime().named('backlog_entered_at_utc').nullable()(); + + /// Returns the derived `backlogEnteredProvenance` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. TextColumn get backlogEnteredProvenance => text().named('backlog_entered_provenance').nullable()(); + + /// Returns the derived `revision` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. IntColumn get revision => integer()(); + + /// Returns the derived `createdAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get createdAtUtc => dateTime().named('created_at_utc')(); + + /// Returns the derived `updatedAtUtc` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. DateTimeColumn get updatedAtUtc => dateTime().named('updated_at_utc')(); + /// Returns the derived `primaryKey` value for this object. + /// Keeping this as an accessor gives callers a stable read surface while the owning type controls how the value is calculated. @override Set> get primaryKey => {id}; } diff --git a/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories.dart b/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories.dart index 4b5f71e..e734091 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// SQLite repository implementations backed by [SchedulerDb]. library; @@ -14,14 +17,24 @@ part 'sqlite_repositories/sqlite_locked_block_repository.dart'; part 'sqlite_repositories/sqlite_settings_repository.dart'; part 'sqlite_repositories/sqlite_schedule_snapshot_repository.dart'; +/// Private file-level value for `_snapshotRetention`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. const _snapshotRetention = Duration(days: 30); +/// Private file-level value for `_epoch`. +/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals. final _epoch = DateTime.fromMillisecondsSinceEpoch(0, isUtc: true); +/// Adds focused helper behavior through `on`. +/// The extension keeps conversion or convenience logic near the type it supports while avoiding changes to the original model surface. extension on int { + /// Performs the `next` behavior for this scheduler component. + /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. core.Revision next() => core.Revision(this).next(); } +/// Top-level helper that performs the `_windowsOverlap` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _windowsOverlap(core.SchedulingWindow left, core.SchedulingWindow right) { return left.start.isBefore(right.end) && right.start.isBefore(left.end); } diff --git a/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_locked_block_repository.dart b/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_locked_block_repository.dart index 2161405..dc127f5 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_locked_block_repository.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_locked_block_repository.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../sqlite_repositories.dart'; /// Drift-backed locked-block and override repository. @@ -8,6 +11,8 @@ final class SqliteLockedBlockRepository implements LockedBlockRepository { /// Shared SQLite database handle. final SchedulerDb db; + /// Runs the `findBlockById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findBlockById({ required core.OwnerId ownerId, @@ -20,6 +25,8 @@ final class SqliteLockedBlockRepository implements LockedBlockRepository { return Right(_lockedBlockFromRow(row)); } + /// Runs the `findBlocksByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findBlocksByOwner({ required core.OwnerId ownerId, @@ -44,6 +51,8 @@ final class SqliteLockedBlockRepository implements LockedBlockRepository { )); } + /// Runs the `findOverrideById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findOverrideById({ required core.OwnerId ownerId, @@ -56,6 +65,8 @@ final class SqliteLockedBlockRepository implements LockedBlockRepository { return Right(_lockedOverrideFromRow(row)); } + /// Runs the `findOverridesForDate` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findOverridesForDate({ required core.OwnerId ownerId, @@ -79,6 +90,8 @@ final class SqliteLockedBlockRepository implements LockedBlockRepository { )); } + /// Runs the `insertBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> insertBlock({ required core.OwnerId ownerId, @@ -95,6 +108,8 @@ final class SqliteLockedBlockRepository implements LockedBlockRepository { return const Right(core.Revision.initial); } + /// Runs the `saveBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> saveBlock({ required core.OwnerId ownerId, @@ -128,6 +143,8 @@ final class SqliteLockedBlockRepository implements LockedBlockRepository { return Right(nextRevision); } + /// Runs the `archiveBlock` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> archiveBlock({ required core.OwnerId ownerId, @@ -161,6 +178,8 @@ final class SqliteLockedBlockRepository implements LockedBlockRepository { return Right(nextRevision); } + /// Runs the `insertOverride` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> insertOverride({ required core.OwnerId ownerId, @@ -177,6 +196,8 @@ final class SqliteLockedBlockRepository implements LockedBlockRepository { return const Right(core.Revision.initial); } + /// Runs the `saveOverride` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> saveOverride({ required core.OwnerId ownerId, @@ -213,17 +234,23 @@ final class SqliteLockedBlockRepository implements LockedBlockRepository { return Right(nextRevision); } + /// Runs the `_blockById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _blockById(String id) { return (db.select(db.lockedBlocks)..where((table) => table.id.equals(id))) .getSingleOrNull(); } + /// Runs the `_overrideById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _overrideById(String id) { return (db.select(db.lockedOverrides) ..where((table) => table.id.equals(id))) .getSingleOrNull(); } + /// Runs the `_checkBlockWrite` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> _checkBlockWrite( String id, core.OwnerId ownerId, @@ -250,6 +277,8 @@ final class SqliteLockedBlockRepository implements LockedBlockRepository { return Right(row); } + /// Runs the `_checkOverrideWrite` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> _checkOverrideWrite( String id, core.OwnerId ownerId, @@ -276,6 +305,8 @@ final class SqliteLockedBlockRepository implements LockedBlockRepository { return Right(row); } + /// Runs the `_staleBlockFailure` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _staleBlockFailure( String id, core.Revision expectedRevision, @@ -289,6 +320,8 @@ final class SqliteLockedBlockRepository implements LockedBlockRepository { ); } + /// Runs the `_staleOverrideFailure` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _staleOverrideFailure( String id, core.Revision expectedRevision, diff --git a/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_project_repository.dart b/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_project_repository.dart index c2011f7..7fea479 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_project_repository.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_project_repository.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../sqlite_repositories.dart'; /// Drift-backed project repository. @@ -8,6 +11,8 @@ final class SqliteProjectRepository implements ProjectRepository { /// Shared SQLite database handle. final SchedulerDb db; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findById({ required core.OwnerId ownerId, @@ -20,6 +25,8 @@ final class SqliteProjectRepository implements ProjectRepository { return Right(_projectFromRow(row)); } + /// Runs the `findByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findByOwner({ required core.OwnerId ownerId, @@ -44,6 +51,8 @@ final class SqliteProjectRepository implements ProjectRepository { )); } + /// Runs the `insert` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> insert({ required core.OwnerId ownerId, @@ -62,6 +71,8 @@ final class SqliteProjectRepository implements ProjectRepository { return const Right(core.Revision.initial); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> save({ required core.OwnerId ownerId, @@ -98,6 +109,8 @@ final class SqliteProjectRepository implements ProjectRepository { return Right(nextRevision); } + /// Runs the `archive` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> archive({ required core.OwnerId ownerId, @@ -136,11 +149,15 @@ final class SqliteProjectRepository implements ProjectRepository { return Right(nextRevision); } + /// Runs the `_projectById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _projectById(String id) { return (db.select(db.projects)..where((table) => table.id.equals(id))) .getSingleOrNull(); } + /// Runs the `_checkProjectWrite` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> _checkProjectWrite( String id, core.OwnerId ownerId, @@ -169,6 +186,8 @@ final class SqliteProjectRepository implements ProjectRepository { return Right(row); } + /// Runs the `_staleProjectFailure` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _staleProjectFailure( String id, core.Revision expectedRevision, diff --git a/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_schedule_snapshot_repository.dart b/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_schedule_snapshot_repository.dart index edd07f1..16c1c26 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_schedule_snapshot_repository.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_schedule_snapshot_repository.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../sqlite_repositories.dart'; /// Drift-backed schedule snapshot repository. @@ -9,6 +12,8 @@ final class SqliteScheduleSnapshotRepository /// Shared SQLite database handle. final SchedulerDb db; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findById({ required core.OwnerId ownerId, @@ -21,6 +26,8 @@ final class SqliteScheduleSnapshotRepository return Right(_snapshotFromRow(row)); } + /// Runs the `findInWindow` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findInWindow({ required core.OwnerId ownerId, @@ -44,6 +51,8 @@ final class SqliteScheduleSnapshotRepository )); } + /// Runs the `insert` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> insert({ required core.OwnerId ownerId, @@ -60,6 +69,8 @@ final class SqliteScheduleSnapshotRepository return const Right(core.Revision.initial); } + /// Runs the `deleteExpired` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> deleteExpired({ required core.OwnerId ownerId, @@ -75,12 +86,16 @@ final class SqliteScheduleSnapshotRepository return Right(deleted); } + /// Runs the `_snapshotById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _snapshotById(String id) { return (db.select(db.snapshots)..where((table) => table.id.equals(id))) .getSingleOrNull(); } } +/// Top-level helper that performs the `_taskCompanion` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. TasksCompanion _taskCompanion( core.Task task, { required core.OwnerId ownerId, @@ -152,6 +167,8 @@ TasksCompanion _taskCompanion( ); } +/// Top-level helper that performs the `_taskFromRow` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.Task _taskFromRow(TaskRow row) { return core.TaskDocumentMapping.fromDocument({ ..._commonDocumentFields( @@ -184,6 +201,8 @@ core.Task _taskFromRow(TaskRow row) { }); } +/// Top-level helper that performs the `_projectCompanion` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. ProjectsCompanion _projectCompanion( core.ProjectProfile project, { required core.OwnerId ownerId, @@ -223,6 +242,8 @@ ProjectsCompanion _projectCompanion( ); } +/// Top-level helper that performs the `_projectFromRow` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.ProjectProfile _projectFromRow(ProjectRow row) { return core.ProjectDocumentMapping.fromDocument({ ..._commonDocumentFields( @@ -242,6 +263,8 @@ core.ProjectProfile _projectFromRow(ProjectRow row) { }); } +/// Top-level helper that performs the `_lockedBlockCompanion` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. LockedBlocksCompanion _lockedBlockCompanion( core.LockedBlock block, { required core.OwnerId ownerId, @@ -278,6 +301,8 @@ LockedBlocksCompanion _lockedBlockCompanion( ); } +/// Top-level helper that performs the `_lockedBlockFromRow` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.LockedBlock _lockedBlockFromRow(LockedBlockRow row) { return core.LockedBlockDocumentMapping.fromDocument({ ..._commonDocumentFields( @@ -295,6 +320,8 @@ core.LockedBlock _lockedBlockFromRow(LockedBlockRow row) { }); } +/// Top-level helper that performs the `_lockedOverrideCompanion` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. LockedOverridesCompanion _lockedOverrideCompanion( core.LockedBlockOverride override, { required core.OwnerId ownerId, @@ -337,6 +364,8 @@ LockedOverridesCompanion _lockedOverrideCompanion( ); } +/// Top-level helper that performs the `_lockedOverrideFromRow` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.LockedBlockOverride _lockedOverrideFromRow(LockedOverrideRow row) { return core.LockedBlockOverrideDocumentMapping.fromDocument({ ..._commonDocumentFields( @@ -352,6 +381,8 @@ core.LockedBlockOverride _lockedOverrideFromRow(LockedOverrideRow row) { }); } +/// Top-level helper that performs the `_settingsCompanion` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. SettingsTableCompanion _settingsCompanion( core.OwnerSettings settings, { required core.Revision revision, @@ -379,6 +410,8 @@ SettingsTableCompanion _settingsCompanion( ); } +/// Top-level helper that performs the `_settingsFromRow` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.OwnerSettings _settingsFromRow(SettingsRow row) { return core.OwnerSettingsDocumentMapping.fromDocument({ ..._commonDocumentFields(row.ownerId, row.ownerId, row.revision, @@ -394,6 +427,8 @@ core.OwnerSettings _settingsFromRow(SettingsRow row) { }); } +/// Top-level helper that performs the `_snapshotCompanion` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. SnapshotsCompanion _snapshotCompanion( core.SchedulingStateSnapshot snapshot, { required core.OwnerId ownerId, @@ -441,6 +476,8 @@ SnapshotsCompanion _snapshotCompanion( ); } +/// Top-level helper that performs the `_snapshotFromRow` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.SchedulingStateSnapshot _snapshotFromRow(SnapshotRow row) { return core.SchedulingSnapshotDocumentMapping.fromDocument({ ..._commonDocumentFields( @@ -467,6 +504,8 @@ core.SchedulingStateSnapshot _snapshotFromRow(SnapshotRow row) { }); } +/// Top-level helper that performs the `_commonDocumentFields` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _commonDocumentFields( String id, String ownerId, @@ -486,22 +525,32 @@ Map _commonDocumentFields( }; } +/// Top-level helper that performs the `_string` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _string(Map doc, String fieldName) { return doc[fieldName] as String; } +/// Top-level helper that performs the `_nullableString` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _nullableString(Map doc, String fieldName) { return doc[fieldName] as String?; } +/// Top-level helper that performs the `_nullableInt` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int? _nullableInt(Map doc, String fieldName) { return doc[fieldName] as int?; } +/// Top-level helper that performs the `_bool` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _bool(Map doc, String fieldName) { return doc[fieldName] as bool; } +/// Top-level helper that performs the `_nullableDateTime` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. DateTime? _nullableDateTime(Map doc, String fieldName) { final value = doc[fieldName] as String?; return value == null @@ -509,30 +558,42 @@ DateTime? _nullableDateTime(Map doc, String fieldName) { : core.PersistenceDateTimeConvention.fromStoredString(value); } +/// Top-level helper that performs the `_storedDateTimeOrNull` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _storedDateTimeOrNull(DateTime? value) { return value == null ? null : core.PersistenceDateTimeConvention.toStoredString(value); } +/// Top-level helper that performs the `_jsonEncodeNullable` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _jsonEncodeNullable(Object? value) { return value == null ? null : jsonEncode(value); } +/// Top-level helper that performs the `_jsonMap` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Map _jsonMap(String value) { return Map.from( jsonDecode(value) as Map, ); } +/// Top-level helper that performs the `_jsonList` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. List _jsonList(String value) { return List.from(jsonDecode(value) as List); } +/// Top-level helper that performs the `_wallTimeFromMinutes` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. core.WallTime _wallTimeFromMinutes(int minutes) { return core.WallTime(hour: minutes ~/ 60, minute: minutes % 60); } +/// Top-level helper that performs the `_cursorOffset` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. int _cursorOffset(String? cursor) { if (cursor == null) return 0; final parsed = int.tryParse(cursor); diff --git a/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_settings_repository.dart b/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_settings_repository.dart index be78987..1de3ae3 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_settings_repository.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_settings_repository.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../sqlite_repositories.dart'; /// Drift-backed owner settings repository. @@ -8,6 +11,8 @@ final class SqliteSettingsRepository implements SettingsRepository { /// Shared SQLite database handle. final SchedulerDb db; + /// Runs the `findByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findByOwner({ required core.OwnerId ownerId, @@ -17,6 +22,8 @@ final class SqliteSettingsRepository implements SettingsRepository { return Right(_settingsFromRow(row)); } + /// Runs the `insert` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> insert({ required core.OwnerId ownerId, @@ -37,6 +44,8 @@ final class SqliteSettingsRepository implements SettingsRepository { return const Right(core.Revision.initial); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> save({ required core.OwnerId ownerId, @@ -70,12 +79,16 @@ final class SqliteSettingsRepository implements SettingsRepository { return Right(nextRevision); } + /// Runs the `_settingsByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _settingsByOwner(String ownerId) { return (db.select(db.settingsTable) ..where((table) => table.ownerId.equals(ownerId))) .getSingleOrNull(); } + /// Runs the `_checkSettingsWrite` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> _checkSettingsWrite( core.OwnerId ownerId, core.Revision expectedRevision, @@ -98,6 +111,8 @@ final class SqliteSettingsRepository implements SettingsRepository { return Right(row); } + /// Runs the `_staleSettingsFailure` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _staleSettingsFailure( core.OwnerId ownerId, core.Revision expectedRevision, diff --git a/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_task_repository.dart b/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_task_repository.dart index 40759f7..d23fcb9 100644 --- a/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_task_repository.dart +++ b/packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_task_repository.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + part of '../sqlite_repositories.dart'; /// Drift-backed task repository. @@ -8,6 +11,8 @@ final class SqliteTaskRepository implements TaskRepository { /// Shared SQLite database handle. final SchedulerDb db; + /// Runs the `findById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> findById({ required core.OwnerId ownerId, @@ -20,6 +25,8 @@ final class SqliteTaskRepository implements TaskRepository { return Right(_taskFromRow(row)); } + /// Runs the `findByOwner` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findByOwner({ required core.OwnerId ownerId, @@ -31,6 +38,8 @@ final class SqliteTaskRepository implements TaskRepository { )); } + /// Runs the `findByParentTaskId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findByParentTaskId({ required core.OwnerId ownerId, @@ -45,6 +54,8 @@ final class SqliteTaskRepository implements TaskRepository { )); } + /// Runs the `findByProjectId` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findByProjectId({ required core.OwnerId ownerId, @@ -59,6 +70,8 @@ final class SqliteTaskRepository implements TaskRepository { )); } + /// Runs the `findByStatus` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future>> findByStatus({ required core.OwnerId ownerId, @@ -75,6 +88,8 @@ final class SqliteTaskRepository implements TaskRepository { )); } + /// Runs the `insert` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> insert({ required core.OwnerId ownerId, @@ -91,6 +106,8 @@ final class SqliteTaskRepository implements TaskRepository { return const Right(core.Revision.initial); } + /// Runs the `save` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> save({ required core.OwnerId ownerId, @@ -125,6 +142,8 @@ final class SqliteTaskRepository implements TaskRepository { return Right(nextRevision); } + /// Runs the `delete` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. @override Future> delete({ required core.OwnerId ownerId, @@ -150,6 +169,8 @@ final class SqliteTaskRepository implements TaskRepository { return Right(nextRevision); } + /// Runs the `_pageTaskRows` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> _pageTaskRows({ required core.PageRequest page, required drift.Expression Function($TasksTable table) where, @@ -167,11 +188,15 @@ final class SqliteTaskRepository implements TaskRepository { ); } + /// Runs the `_taskById` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _taskById(String id) { return (db.select(db.tasks)..where((table) => table.id.equals(id))) .getSingleOrNull(); } + /// Runs the `_checkTaskWrite` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future> _checkTaskWrite( String id, core.OwnerId ownerId, @@ -200,6 +225,8 @@ final class SqliteTaskRepository implements TaskRepository { return Right(row); } + /// Runs the `_staleTaskFailure` operation and completes after its asynchronous work finishes. + /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order. Future _staleTaskFailure( String id, core.Revision expectedRevision, diff --git a/packages/scheduler_persistence_sqlite/pubspec.yaml b/packages/scheduler_persistence_sqlite/pubspec.yaml index 54d5d7a..195202e 100644 --- a/packages/scheduler_persistence_sqlite/pubspec.yaml +++ b/packages/scheduler_persistence_sqlite/pubspec.yaml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + name: scheduler_persistence_sqlite description: Drift-backed SQLite persistence adapter for the ADHD scheduler. version: 0.1.0 diff --git a/packages/scheduler_persistence_sqlite/test/scheduler_db_test.dart b/packages/scheduler_persistence_sqlite/test/scheduler_db_test.dart index 7e568bd..d1c02f6 100644 --- a/packages/scheduler_persistence_sqlite/test/scheduler_db_test.dart +++ b/packages/scheduler_persistence_sqlite/test/scheduler_db_test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Scheduler Db behavior for the Scheduler Persistence Sqlite package. library; @@ -5,6 +8,8 @@ import 'package:drift/native.dart'; import 'package:scheduler_persistence_sqlite/sqlite.dart'; import 'package:test/test.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { test('opens schema version 1 with expected tables', () async { final db = SchedulerDb(NativeDatabase.memory()); diff --git a/packages/scheduler_persistence_sqlite/test/sqlite_repository_conformance_test.dart b/packages/scheduler_persistence_sqlite/test/sqlite_repository_conformance_test.dart index fc1ee73..ebf7dc3 100644 --- a/packages/scheduler_persistence_sqlite/test/sqlite_repository_conformance_test.dart +++ b/packages/scheduler_persistence_sqlite/test/sqlite_repository_conformance_test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Tests Sqlite Repository Conformance behavior for the Scheduler Persistence Sqlite package. library; @@ -8,6 +11,8 @@ import 'package:test/test.dart'; import '../../scheduler_persistence/test/repo_conformance.dart'; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { runRepositoryComplianceTests( RepositoryComplianceFactories( @@ -53,6 +58,8 @@ void main() { }); } +/// Top-level helper that performs the `_repo` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. T _repo(T Function(SchedulerDb db) create) { final db = SchedulerDb(NativeDatabase.memory()); addTearDown(db.close); diff --git a/pubspec.yaml b/pubspec.yaml index 6bdf50a..fd21421 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + name: adhd_scheduling_workspace publish_to: none @@ -29,6 +32,8 @@ dependencies: scheduler_persistence_sqlite: any dev_dependencies: + analyzer: ^13.3.0 build_runner: ^2.4.13 coverage: ^1.11.0 + lints: ^5.0.0 test: ^1.25.0 diff --git a/scripts/bootstrap_dev.sh b/scripts/bootstrap_dev.sh index 7bd460d..d89d001 100755 --- a/scripts/bootstrap_dev.sh +++ b/scripts/bootstrap_dev.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + # Prepare local dependencies and the default scheduler SQLite location. set -euo pipefail @@ -8,9 +11,14 @@ scheduler_dir="${SCHEDULER_HOME:-"$HOME/ADHD_Scheduler"}" cd "$root_dir" dart pub get +if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then + git config core.hooksPath .githooks +fi + mkdir -p "$scheduler_dir/backups" if [[ ! -e "$scheduler_dir/scheduler.sqlite" ]]; then : > "$scheduler_dir/scheduler.sqlite" fi printf 'Scheduler SQLite path: %s\n' "$scheduler_dir/scheduler.sqlite" +printf 'Git hooks path: .githooks\n' diff --git a/scripts/build.dart b/scripts/build.dart index fe42c70..c55fa56 100644 --- a/scripts/build.dart +++ b/scripts/build.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Runs the Build workspace script. library; @@ -30,6 +33,8 @@ Future main(List arguments) async { } } +/// Top-level helper that performs the `_buildMacOs` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _buildMacOs(Directory outputDirectory) async { await _run('flutter', ['build', 'macos', '--release']); final releaseDir = Directory('build/macos/Build/Products/Release'); @@ -47,6 +52,8 @@ Future _buildMacOs(Directory outputDirectory) async { } } +/// Top-level helper that performs the `_buildWindows` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _buildWindows(Directory outputDirectory) async { await _run('flutter', ['build', 'windows', '--release']); final bundle = Directory('build/windows/x64/runner/Release'); @@ -69,6 +76,8 @@ Future _buildWindows(Directory outputDirectory) async { } } +/// Top-level helper that performs the `_buildLinux` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _buildLinux(Directory outputDirectory) async { await _run('flutter', ['build', 'linux', '--release']); await _run('appimage-builder', [ @@ -89,6 +98,8 @@ Future _buildLinux(Directory outputDirectory) async { } } +/// Top-level helper that performs the `_run` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _run(String executable, List arguments) async { stdout.writeln('> $executable ${arguments.join(' ')}'); final result = await Process.run( @@ -108,6 +119,8 @@ Future _run(String executable, List arguments) async { } } +/// Top-level helper that performs the `_copyDirectory` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _copyDirectory(Directory source, Directory destination) async { await destination.create(recursive: true); await for (final entity in source.list(recursive: false)) { @@ -120,6 +133,8 @@ Future _copyDirectory(Directory source, Directory destination) async { } } +/// Top-level helper that performs the `_currentPlatform` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _currentPlatform() { if (Platform.isMacOS) return 'macos'; if (Platform.isWindows) return 'windows'; @@ -127,11 +142,15 @@ String _currentPlatform() { throw UnsupportedError('No Flutter desktop build target for this platform.'); } +/// Top-level helper that performs the `_basename` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _basename(String path) { final normalized = path.replaceAll('\\', '/'); return normalized.substring(normalized.lastIndexOf('/') + 1); } +/// Top-level helper that performs the `_join` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _join(String first, String second) { final separator = Platform.pathSeparator; final left = first.endsWith(separator) @@ -141,6 +160,8 @@ String _join(String first, String second) { return '$left$separator$right'; } +/// Top-level helper that performs the `_option` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _option(List arguments, String name) { final index = arguments.indexOf(name); if (index == -1 || index + 1 >= arguments.length) { diff --git a/scripts/dev.dart b/scripts/dev.dart index b421233..9f84ca8 100644 --- a/scripts/dev.dart +++ b/scripts/dev.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Runs the Dev workspace script. library; @@ -46,6 +49,8 @@ Future main(List arguments) async { } } +/// Top-level helper that performs the `_watchForExit` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. void _watchForExit(ProcessSignal signal, int code, Process buildRunner) { signal.watch().listen((_) { buildRunner.kill(); @@ -53,6 +58,8 @@ void _watchForExit(ProcessSignal signal, int code, Process buildRunner) { }); } +/// Top-level helper that performs the `_start` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _start(String executable, List arguments) async { stdout.writeln('> $executable ${arguments.join(' ')}'); try { @@ -69,12 +76,16 @@ Future _start(String executable, List arguments) async { } } +/// Top-level helper that performs the `_defaultDesktopDevice` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String _defaultDesktopDevice() { if (Platform.isMacOS) return 'macos'; if (Platform.isWindows) return 'windows'; return 'linux'; } +/// Top-level helper that performs the `_option` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. String? _option(List arguments, String name) { final index = arguments.indexOf(name); if (index == -1 || index + 1 >= arguments.length) { diff --git a/scripts/dev.sh b/scripts/dev.sh index 8dd6556..7c504e3 100755 --- a/scripts/dev.sh +++ b/scripts/dev.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + # Compatibility wrapper for the Dart desktop development runner. set -euo pipefail diff --git a/scripts/package_release.sh b/scripts/package_release.sh index 5d70313..5ffc1fa 100755 --- a/scripts/package_release.sh +++ b/scripts/package_release.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + # Compatibility wrapper for the Dart release packaging runner. set -euo pipefail diff --git a/scripts/test.dart b/scripts/test.dart index bc20af4..5488a73 100644 --- a/scripts/test.dart +++ b/scripts/test.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Runs the Test workspace script. library; @@ -25,9 +28,12 @@ Future main(List arguments) async { 'coverage/lcov.info', '80', ]); + await _run('dart', ['run', 'tool/check_reuse.dart']); await _run('dart', ['run', 'tool/check_docs.dart']); } +/// Top-level helper that performs the `_deleteCoverageDirectory` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _deleteCoverageDirectory() async { final coverage = Directory('coverage'); if (await coverage.exists()) { @@ -35,6 +41,8 @@ Future _deleteCoverageDirectory() async { } } +/// Top-level helper that performs the `_run` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. Future _run(String executable, List arguments) async { final command = '$executable ${arguments.join(' ')}'; stdout.writeln('> $command'); diff --git a/scripts/test.sh b/scripts/test.sh index ab1acb8..821bef6 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash +# SPDX-FileCopyrightText: 2026 FocusFlow contributors +# SPDX-License-Identifier: AGPL-3.0-only + set -euo pipefail dart analyze diff --git a/test/scheduler_core_test.dart b/test/scheduler_core_test.dart index 0c57b88..bba78f8 100644 --- a/test/scheduler_core_test.dart +++ b/test/scheduler_core_test.dart @@ -70,6 +70,8 @@ import '../packages/scheduler_persistence_memory/test/memory_repository_conforma import '../packages/scheduler_persistence_sqlite/test/sqlite_repository_conformance_test.dart' as sqlite_repository_conformance_test; +/// Entry point for this executable Dart file. +/// It wires the local command, test, or application behavior needed by this repository without exposing additional public API. void main() { encrypted_backup_test.main(); application_commands_test.main(); diff --git a/tool/check_coverage.dart b/tool/check_coverage.dart index fca1692..aa28aa7 100644 --- a/tool/check_coverage.dart +++ b/tool/check_coverage.dart @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Runs the Check Coverage workspace validation tool. library; @@ -45,6 +48,8 @@ void main(List arguments) { } } +/// Runs the `this operation` top-level operation. +/// This function is part of the file-level API and gives callers a direct way to use the associated scheduler behavior. ({int coveredLines, int totalLines, double percent}) _readCoverage(File file) { var includeFile = false; var coveredLines = 0; @@ -77,6 +82,8 @@ void main(List arguments) { ); } +/// Top-level helper that performs the `_includeSourceFile` operation for this file. +/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail. bool _includeSourceFile(String path) { final normalized = path.replaceAll('\\', '/'); return normalized.contains('/packages/') && diff --git a/tool/check_docs.dart b/tool/check_docs.dart index 2ec8a75..222b63a 100644 --- a/tool/check_docs.dart +++ b/tool/check_docs.dart @@ -1,10 +1,25 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + /// Runs the Check Docs workspace validation tool. library; import 'dart:io'; -/// Generates Dart docs for each package with public libraries and fails on warnings. +import 'package:analyzer/dart/analysis/utilities.dart'; +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:analyzer/dart/ast/visitor.dart'; +import 'package:analyzer/source/line_info.dart'; + +/// Generates Dart docs for each package and fails on documentation gaps. +/// +/// This tool is intentionally stricter than `dart doc` alone. It checks that +/// tracked Dart files have file-level library docs where appropriate and that +/// every declaration-like API surface has a Dartdoc comment, including private +/// helpers and part files. That keeps internal scheduler behavior readable for +/// future contributors instead of relying on project history or tribal context. Future main(List arguments) async { + final skipDartdoc = arguments.contains('--skip-dartdoc'); final missingFileDocs = await _trackedDartFilesMissingFileDocs(); if (missingFileDocs.isNotEmpty) { stderr.writeln('Dart files missing file-level Dartdoc library headers:'); @@ -13,6 +28,25 @@ Future main(List arguments) async { } } + final missingDeclarationDocs = + await _trackedDartFilesMissingDeclarationDocs(); + if (missingDeclarationDocs.isNotEmpty) { + stderr.writeln('Dart declarations missing Dartdoc comments:'); + for (final missing in missingDeclarationDocs) { + stderr.writeln('- $missing'); + } + } + + if (skipDartdoc) { + if (missingFileDocs.isNotEmpty || missingDeclarationDocs.isNotEmpty) { + stderr.writeln('Dart documentation quick gate failed.'); + exitCode = 1; + } else { + stdout.writeln('Dart documentation quick gate passed.'); + } + return; + } + final outputRoot = Directory(_join(_join('doc', 'api'), 'packages')); if (await outputRoot.exists()) { await outputRoot.delete(recursive: true); @@ -28,7 +62,7 @@ Future main(List arguments) async { }).toList(growable: false) ..sort((left, right) => left.path.compareTo(right.path)); - var failed = missingFileDocs.isNotEmpty; + var failed = missingFileDocs.isNotEmpty || missingDeclarationDocs.isNotEmpty; for (final package in packages) { final outputPath = _join(outputRoot.absolute.path, _basename(package.path)); stdout.writeln('> dart doc --output $outputPath (${package.path})'); @@ -51,7 +85,40 @@ Future main(List arguments) async { } } -Future> _trackedDartFilesMissingFileDocs() async { +/// Finds tracked Dart declarations that do not have Dartdoc comments. +/// +/// The audit includes classes, mixins, enums, enum values, extensions, +/// extension types, constructors, methods, top-level functions, fields, and +/// top-level variables. Generated files are skipped because their source of +/// truth is the generator configuration, not hand-maintained comments. +Future> _trackedDartFilesMissingDeclarationDocs() async { + final paths = await _trackedDartFiles(); + final missing = []; + + for (final path in paths) { + final file = File(path); + final contents = await file.readAsString(); + if (_isGenerated(path, contents)) { + continue; + } + final result = parseString( + content: contents, + path: file.absolute.path, + throwIfDiagnostics: false, + ); + final visitor = _DeclarationDocVisitor(path, result.unit.lineInfo); + result.unit.accept(visitor); + missing.addAll(visitor.missing); + } + + return missing; +} + +/// Returns tracked Dart files in stable path order. +/// +/// Git is the source of truth so local build outputs, generated docs, and +/// editor scratch files do not affect the documentation gate. +Future> _trackedDartFiles() async { final result = await Process.run( 'git', ['ls-files', '*.dart'], @@ -66,12 +133,20 @@ Future> _trackedDartFilesMissingFileDocs() async { ); } - final paths = (result.stdout as String) + return (result.stdout as String) .split('\n') .where((path) => path.trim().isNotEmpty) .toList(growable: false) ..sort(); +} +/// Finds tracked Dart files that are missing file-level library docs. +/// +/// Part files and generated files are excluded from this specific check because +/// they cannot declare their own `library;` header. Their declarations are still +/// covered by the declaration-level audit above. +Future> _trackedDartFilesMissingFileDocs() async { + final paths = await _trackedDartFiles(); final missing = []; for (final path in paths) { final file = File(path); @@ -86,25 +161,185 @@ Future> _trackedDartFilesMissingFileDocs() async { return missing; } +/// Reports whether a file is generated or a library part. +/// +/// SPDX headers may appear before `part of`, so the check removes the standard +/// leading SPDX block before identifying part files. bool _isGeneratedPart(String path, String contents) { - return path.endsWith('.g.dart') || contents.startsWith("part of '"); + final source = _stripLeadingSpdxHeader(contents).trimLeft(); + return _isGenerated(path, contents) || source.startsWith('part of '); } +/// Reports whether a file should be treated as generated source. +/// +/// Generated sources are not edited by hand, so enforcing hand-written docs on +/// them would create churn every time the generator runs. +bool _isGenerated(String path, String contents) { + return path.endsWith('.g.dart') || + contents.contains('// GENERATED CODE - DO NOT MODIFY BY HAND'); +} + +/// Reports whether a Dart file starts with a Dartdoc library header. +/// +/// SPDX headers are allowed to precede the docs so files can satisfy both REUSE +/// metadata conventions and Dartdoc's library-level documentation expectations. bool _hasFileLevelLibraryDocs(String contents) { - return RegExp(r'^\s*///[\s\S]*?\nlibrary;', multiLine: false) - .hasMatch(contents); + final source = _stripLeadingSpdxHeader(contents); + return RegExp( + r'^\s*///[\s\S]*?\nlibrary;', + multiLine: false, + ).hasMatch(source); } +/// Removes the standard leading SPDX comment block from a Dart source string. +/// +/// The function deliberately handles only SPDX and copyright line comments at +/// the top of the file; ordinary explanatory comments remain visible to the +/// file-level documentation check. +String _stripLeadingSpdxHeader(String contents) { + return contents.replaceFirst( + RegExp( + r'^(?:(?://\s*SPDX-[^\n]*|//\s*Copyright[^\n]*|//\s*$)\n)*', + multiLine: false, + ), + '', + ); +} + +/// Visits Dart declarations and records any declaration without Dartdoc. +/// +/// The visitor intentionally ignores local variables and local functions inside +/// method bodies. Those are implementation details where inline comments should +/// remain rare and reserved for unusually complex logic. +class _DeclarationDocVisitor extends RecursiveAstVisitor { + /// Creates a visitor for one parsed Dart file. + /// + /// The [lineInfo] object is reused for every finding so error messages can + /// point directly at the declaration line that needs documentation. + _DeclarationDocVisitor(this.path, this.lineInfo); + + /// Repository-relative path for the file currently being audited. + final String path; + + /// Line lookup table produced by the analyzer parser. + final LineInfo lineInfo; + + /// Human-readable documentation findings for this file. + final List missing = []; + + /// Checks class declarations for Dartdoc. + @override + void visitClassDeclaration(ClassDeclaration node) { + _check(node, 'class'); + super.visitClassDeclaration(node); + } + + /// Checks mixin declarations for Dartdoc. + @override + void visitMixinDeclaration(MixinDeclaration node) { + _check(node, 'mixin'); + super.visitMixinDeclaration(node); + } + + /// Checks enum declarations for Dartdoc. + @override + void visitEnumDeclaration(EnumDeclaration node) { + _check(node, 'enum'); + super.visitEnumDeclaration(node); + } + + /// Checks enum constants for Dartdoc. + @override + void visitEnumConstantDeclaration(EnumConstantDeclaration node) { + _check(node, 'enum value'); + super.visitEnumConstantDeclaration(node); + } + + /// Checks extension declarations for Dartdoc. + @override + void visitExtensionDeclaration(ExtensionDeclaration node) { + _check(node, 'extension'); + super.visitExtensionDeclaration(node); + } + + /// Checks extension type declarations for Dartdoc. + @override + void visitExtensionTypeDeclaration(ExtensionTypeDeclaration node) { + _check(node, 'extension type'); + super.visitExtensionTypeDeclaration(node); + } + + /// Checks constructor declarations for Dartdoc. + @override + void visitConstructorDeclaration(ConstructorDeclaration node) { + _check(node, 'constructor'); + super.visitConstructorDeclaration(node); + } + + /// Checks class, mixin, extension, and enum methods for Dartdoc. + @override + void visitMethodDeclaration(MethodDeclaration node) { + _check(node, 'method'); + super.visitMethodDeclaration(node); + } + + /// Checks only top-level functions for Dartdoc. + @override + void visitFunctionDeclaration(FunctionDeclaration node) { + if (node.parent is CompilationUnit) { + _check(node, 'top-level function'); + } + super.visitFunctionDeclaration(node); + } + + /// Checks instance and static fields for Dartdoc. + @override + void visitFieldDeclaration(FieldDeclaration node) { + _check(node, 'field'); + super.visitFieldDeclaration(node); + } + + /// Checks top-level variables for Dartdoc. + @override + void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { + _check(node, 'top-level variable'); + super.visitTopLevelVariableDeclaration(node); + } + + /// Adds a missing-doc finding for [node] when it has no documentation comment. + void _check(Declaration node, String kind) { + if (node.documentationComment != null) { + return; + } + final location = lineInfo.getLocation(node.offset); + final summary = node.toSource().split('\n').first.trim(); + missing.add('$path:${location.lineNumber}: $kind `$summary`'); + } +} + +/// Reports whether `dart doc` produced warning text. +/// +/// Dartdoc may return success while still reporting warnings, and this project +/// treats warnings as documentation failures so broken references are caught +/// before they reach CI or generated docs. bool _hasWarnings(String output) { return output.contains(' warning:') || RegExp(r'Found [1-9][0-9]* warnings').hasMatch(output); } +/// Joins two path segments using the platform separator. +/// +/// The helper avoids pulling in another dependency for the small amount of path +/// handling needed by this repository-local script. String _join(String first, String second) { final separator = Platform.pathSeparator; return '$first$separator$second'; } +/// Returns the final path segment for a platform-neutral path string. +/// +/// Dartdoc output directory names use package basenames, so this helper keeps +/// the script independent of whether Git produced slash or backslash paths. String _basename(String path) { final normalized = path.replaceAll('\\', '/'); return normalized.substring(normalized.lastIndexOf('/') + 1); diff --git a/tool/check_reuse.dart b/tool/check_reuse.dart new file mode 100644 index 0000000..20f86ab --- /dev/null +++ b/tool/check_reuse.dart @@ -0,0 +1,193 @@ +// SPDX-FileCopyrightText: 2026 FocusFlow contributors +// SPDX-License-Identifier: AGPL-3.0-only + +/// Runs the local SPDX and REUSE metadata validation tool. +library; + +import 'dart:io'; + +/// SPDX expression used by package and app source metadata. +/// +/// The top-level `LICENSE.md` contains the GNU Affero General Public License +/// version 3 text, so the repository uses the corresponding SPDX identifier. +const _licenseIdentifier = 'AGPL-3.0-only'; + +/// Repository-local copyright text used in SPDX headers. +/// +/// The project uses a contributor-oriented copyright holder because individual +/// source files do not currently carry more specific ownership notices. +const _copyrightText = '2026 FocusFlow contributors'; + +/// Package directories that must include a pointer to the root license file. +/// +/// Each Dart package is publishable as its own unit even though publishing is +/// disabled, so every package folder carries a small `LICENSE.md` reference. +const _packageDirectories = [ + 'packages/scheduler_backup', + 'packages/scheduler_core', + 'packages/scheduler_export', + 'packages/scheduler_export_json', + 'packages/scheduler_integration_tests', + 'packages/scheduler_notifications', + 'packages/scheduler_notifications_desktop', + 'packages/scheduler_persistence', + 'packages/scheduler_persistence_memory', + 'packages/scheduler_persistence_sqlite', +]; + +/// App directories that must include a pointer to the root license file. +/// +/// The Flutter app is outside the root Dart workspace, but it still ships with +/// repository code and therefore follows the same licensing metadata rules. +const _appDirectories = ['apps/focus_flow_flutter']; + +/// Validates SPDX headers, REUSE metadata, and package/app license pointers. +void main(List arguments) { + final failures = [ + ..._reuseTomlFailures(), + ..._licensePointerFailures(), + ..._spdxHeaderFailures(), + ]; + + if (failures.isEmpty) { + stdout.writeln('SPDX and REUSE metadata checks passed.'); + return; + } + + stderr.writeln('SPDX and REUSE metadata checks failed:'); + for (final failure in failures) { + stderr.writeln('- $failure'); + } + exitCode = 1; +} + +/// Checks that `REUSE.toml` exists and covers package/app trees. +/// +/// This does not replace the upstream REUSE tool, but it keeps the repository's +/// expected local metadata shape from drifting when contributors add files. +List _reuseTomlFailures() { + final file = File('REUSE.toml'); + if (!file.existsSync()) { + return ['REUSE.toml is missing.']; + } + + final contents = file.readAsStringSync(); + final failures = []; + for (final required in [ + 'packages/**', + 'apps/focus_flow_flutter/**', + 'SPDX-License-Identifier = "$_licenseIdentifier"', + 'SPDX-FileCopyrightText = "$_copyrightText"', + ]) { + if (!contents.contains(required)) { + failures.add('REUSE.toml does not contain `$required`.'); + } + } + return failures; +} + +/// Checks package and app `LICENSE.md` pointer files. +/// +/// Pointer files keep each package understandable when opened in isolation while +/// still making the root `LICENSE.md` the single license text source. +List _licensePointerFailures() { + final failures = []; + for (final directory in [ + ..._packageDirectories, + ..._appDirectories + ]) { + final file = File('$directory/LICENSE.md'); + if (!file.existsSync()) { + failures.add('$directory/LICENSE.md is missing.'); + continue; + } + final contents = file.readAsStringSync(); + if (!contents.contains('../../LICENSE.md')) { + failures + .add('$directory/LICENSE.md does not reference ../../LICENSE.md.'); + } + if (!contents.contains('SPDX-License-Identifier: $_licenseIdentifier')) { + failures.add('$directory/LICENSE.md is missing its SPDX license header.'); + } + } + return failures; +} + +/// Checks safe text files for inline SPDX headers. +/// +/// Binary files, JSON resources, generated platform project files, and XML/plist +/// files are covered by `REUSE.toml` annotations because adding comments to +/// those formats can either be invalid or be overwritten by platform tooling. +List _spdxHeaderFailures() { + final failures = []; + for (final path in _trackedFiles()) { + if (!_requiresInlineSpdxHeader(path)) { + continue; + } + final contents = File(path).readAsStringSync(); + if (!contents.contains('SPDX-License-Identifier: $_licenseIdentifier')) { + failures.add('$path is missing SPDX-License-Identifier.'); + } + if (!contents.contains('SPDX-FileCopyrightText: $_copyrightText')) { + failures.add('$path is missing SPDX-FileCopyrightText.'); + } + } + return failures; +} + +/// Returns tracked repository files in stable path order. +/// +/// Git is used so ignored build output and local editor files do not affect the +/// metadata check. +List _trackedFiles() { + final result = Process.runSync( + 'git', + ['ls-files'], + runInShell: Platform.isWindows, + ); + if (result.exitCode != 0) { + throw ProcessException( + 'git', + ['ls-files'], + 'Unable to list tracked files.', + result.exitCode, + ); + } + return (result.stdout as String) + .split('\n') + .where((path) => path.trim().isNotEmpty) + .toList(growable: false) + ..sort(); +} + +/// Reports whether [path] should carry an inline SPDX header. +/// +/// The allow-list is intentionally conservative and includes only formats where +/// adding a leading comment is safe and unlikely to break generated tooling. +bool _requiresInlineSpdxHeader(String path) { + if (!_isComplianceScope(path)) { + return false; + } + if (path.endsWith('.g.dart') || path.endsWith('LICENSE.md')) { + return false; + } + return path.endsWith('.dart') || + path.endsWith('.yaml') || + path.endsWith('.yml') || + path.endsWith('.sh') || + path.endsWith('.md'); +} + +/// Reports whether [path] belongs to the checked compliance surface. +/// +/// The package and app folders are the main requested scope; root scripts and +/// tool files are included because they enforce the same standards. +bool _isComplianceScope(String path) { + return path.startsWith('packages/') || + path.startsWith('apps/focus_flow_flutter/') || + path.startsWith('scripts/') || + path.startsWith('tool/') || + path == 'pubspec.yaml' || + path == 'analysis_options.yaml' || + path == '.github/workflows/ci.yml'; +}