cfait 1.0.9

Powerful, fast and elegant task / TODO manager. (GUI & TUI, CalDAV & local)
Documentation
# Cfait Specifications & Developer Guidelines

> **⚠️ INSTRUCTIONS FOR DEVELOPERS AND CONTRIBUTORS:**
> This document is the ultimate source of truth for Cfait's behavior, data model, and architecture.
> 1. **Core-First & DRY:** Business logic, filtering, parsing, and data manipulation MUST live in the Rust core (`src/model`, `src/store.rs`, `src/controller.rs`). UIs (TUI, GUI, Mobile, CLI) must remain as thin as possible and act only as rendering/routing layers.
> 2. **Performance is Critical:** The UI must never lag, even with 100,000+ tasks. Avoid unnecessary cloning (use `&Task` references in filter pipelines). Rely on `TaskStore` indices for O(1) lookups.
> 3. **Keep this updated:** Update this document whenever introducing a new feature, syntax token, setting, or architectural shift. Keep it concise, behavioral, and accurate.

---

## 1. Core Architecture & Persistence

Cfait is an offline-first task manager that seamlessly synchronizes with CalDAV servers and local file storage.

### 1.1. Data Flow & Synchronization
*   **TaskStore (In-Memory):** The single source of truth for the active session. Contains tasks grouped by calendar HREF. Maintains O(1) HashMaps for UID lookups, blocking relationships, and parent-child hierarchies.
*   **Journal (Offline Queue):** All mutations (`Create`, `Update`, `Delete`, `Move`) append to `journal.json` immediately. UIs update optimistically.
*   **TaskController:** Orchestrates all updates. Receives `AppIntent`s from the UIs, applies them to the `TaskStore`, writes to the `Journal`, and signals the background worker.
*   **Background Sync:** 
    *   *Desktop (GUI/CLI daemon):* A background worker reads the Journal and pushes changes via `RustyClient`.
    *   *Android:* Handled via `WorkManager`. `PeriodicSyncWorker` runs based on `auto_refresh_interval_mins` (min 15 mins). Foreground manual syncs trigger immediate updates.
*   **Settings Sync:** User configuration and aliases sync across devices via a hidden `VTODO` task with UID `cfait-global-settings-v1` (status `CANCELLED`, category `cfait-internal`).
*   **Conflict & Error Handling:** 
    *   `412 Precondition Failed` (ETag mismatch): Performs a local 3-way merge. If unmergeable, a "Conflict Copy" is generated.
    *   **Fatal Server Errors (e.g., 400, 403, 415):** The problematic task is rescued into a local `local://recovery` calendar to prevent data loss or sync loop lockups, with the error appended to its description.

### 1.2. The Task Entity (`VTODO` Mapping)
Tasks map strictly to iCalendar `VTODO` components (RFC 5545). Non-standard metadata is stored via `X-CFAIT-` properties.
*   **Status:** `NeedsAction` (Pending), `InProcess` (Timer running), `Completed`, `Cancelled`.
*   **Dates (`DateType`):** Start (`DTSTART`) and Due (`DUE`). Supported variants:
    *   *Specific:* Exact DateTime (UTC).
    *   *All-Day:* NaiveDate.
    *   *Fuzzy:* Month/Year precision (stored as All-Day with `X-CFAIT-FUZZY-DUE`/`START` properties).
*   **Hierarchy:** `RELATED-TO` establishes the `parent_uid`.
*   **Dependencies:** `RELATED-TO;RELTYPE=DEPENDS-ON` establishes blocking relationships. `RELTYPE=SIBLING` establishes related tasks.
*   **Time Tracking:** Logged via `X-TIME-SPENT` (total seconds), `X-LAST-START` (unix timestamp), and `X-CFAIT-SESSION` (WorkSessions holding Unix start/end timestamps).
*   **System Entities:** Local trash uses `local://trash`. Items here are soft-deleted and pruned based on `trash_retention_days`.

### 1.3. System Integrations
*   **Keyring:** Passwords are never stored in plaintext `config.toml`. They are vaulted via OS keyrings: Windows Credential Manager, macOS Keychain, Linux Secret Portal (oo7) or Keyutils, Android Keystore.
*   **Logging:** Outputs to `cache/cfait.log` (rotating `cfait.old.log`). Terminal stderr logging is enabled for CLI/GUI, but disabled for TUI to prevent screen tearing. Android uses dual logging (File + Logcat).
*   **Crash Reporting (Android):** An `UncaughtExceptionHandler` writes panics to `cache/android_crash.txt`.

---

## 2. Smart Syntax & Parsing
Evaluated instantly during text input. Supported across all clients.

### 2.1. Tokens
| Token | Meaning | Example |
| :--- | :--- | :--- |
| `!1` .. `!9` | Priority (1 is highest/most urgent). | `!1` |
| `@` or `due:` | Due date. | `@now`, `@tomorrow`, `@2025-12-31`, `@fri 2pm` |
| `^` or `start:` | Start date. | `^next week` |
| `^@` | Sets *both* Start and Due dates. | `^@tomorrow 9am` |
| `~` or `est:` | Estimated duration (supports ranges). | `~30m`, `~1h-2h` |
| `#` | Tag/Category (Supports brace expansion). | `#work`, `#project{sub1,sub2}` |
| `@@` or `loc:`| Location. | `@@office` |
| `url:` / `[[ ]]`| Attach URL. | `url:https://example.com` |
| `geo:` | Geo-coordinates. | `geo:50.1,4.2`, `geo:here` (Mobile: Fetches GPS) |
| `desc:` | Append text to the description. | `desc:"Buy milk"` or `desc:{...}` |
| `rem:` | Reminder / Alarm. | `rem:10m`, `rem:in 1h`, `rem:8pm`, `rem:next friday` |
| `done:` | Mark completed / Set percentage. | `done:now`, `done:yesterday`, `done:50%` |
| `spent:` | Log time spent manually. | `spent:1h` |
| `rec:` or `@` | Recurrence (`RRULE`). | `@daily`, `rec:every 2 weeks` |
| `@after` | Relative recurrence (shifts from completion). | `@after 1w`, `@after 2mo` |
| `until` | End date for recurrence. | `@daily until 2025-12-31` |
| `except` | Exclusion dates (`EXDATE`). | `@daily except sat,sun` |
| `+cal` / `-cal` | Force/prevent companion Calendar Event. | `+cal` |
| `+pin` / `-pin` | Pin task to the top of the list. | `+pin` |
| `goal:` | Goal tracking target. | `goal:5/w`, `goal:2h/daily`, `goal:weekly` |

*Rules:* 
* Double prefixes (`##tag`, `@@@loc`) apply metadata but *keep* the word in the display title.
* Use `\` to escape special characters (e.g., `\#not-a-tag`).

### 2.2. Aliases (Macros)
Users can define reusable shortcuts that expand into multiple tags, locations, or priorities.
*   *Syntax:* `#gardening := #home:outside, @@garden, !4`
*   Aliases are resolved retroactively across the database upon creation/edit. Cycle detection is strictly enforced (max depth 10).

### 2.3. Markdown Subtask Extraction
If a task's description contains a Markdown list, Cfait extracts those lines into distinct child tasks via the "Extract Subtasks" action or `Ctrl+E`.
*   **Hierarchy:** Child tasks nest based on indentation level.
*   **Parallel Tasks:** Unnumbered lists (`- [ ]`) create independent sibling tasks.
*   **Sequential Dependencies:** Numbered lists (`1. [ ]`, `2. [ ]`) create `DEPENDS-ON` blocking relationships (Task 2 is blocked by Task 1).

---

## 3. Searching, Filtering, and Sorting

### 3.1. Search Operators & Primitives
The search bar supports a boolean recursive-descent parser.
*   **Logic:** Implicit `AND` (space), `OR` (`|`), `NOT` (`-`), and Grouping `()`.
*   **Primitives:**
    *   *State:* `is:done`, `is:active`, `is:started` / `is:ongoing`, `is:blocked`.
    *   *Actionable:* `is:ready` (Excludes completed tasks, explicitly/implicitly blocked tasks, and tasks starting in the future. `InProcess` bypasses this).
    *   *Comparison:* `~<30m` (duration < 30m), `!<4` (priority < 4).
    *   *Dates:* `@<today` (Overdue), `^>1w` (Starts in > 1 week).

### 3.2. Multi-Stage Sorting Algorithm
Tasks sort deterministically by rank (0 to 9), then by Overdue -> Priority -> Due Date -> Start Date -> Summary.
*   **Rank 0:** Pinned (`+pin`).
*   **Ranks 1-3 (Urgent/Started/Due Soon):** Order dictated by `sort_preset` (e.g., Urgent > Started > Due Soon).
*   **Rank 4 (Actionable):** Due date `<=` `sort_cutoff_days`.
*   **Rank 5 (Deferred):** No due date, or `>` `sort_cutoff_days`.
*   **Rank 6 (Blocked):** Has unresolved dependencies or parent is blocked.
*   **Rank 7 (Future):** Start date is > `start_grace_period_days`.
*   **Rank 8 (Completed):** Done or Cancelled.
*   **Rank 9 (Trash):** In `local://trash`.

*Rule:* If `sort_standard_by_priority` is enabled, Ranks 4 and 5 merge and sort by numeric Priority first, then Date.

---

## 4. Core Business Workflows

### 4.1. The "Yank" Relationship System
Instead of drag-and-drop, Cfait uses a robust "Yank" (Clipboard) system for hierarchy management.
1.  **Yank (`y` / Action Menu):** Copies the selected task's UID to an internal "Yanked" state. UI displays a persistent banner.
2.  **Relate:** Select a *target* task and execute:
    *   `c` (Child): Target becomes a subtask (child) of Yanked.
    *   `b` (Block): Target becomes blocked by Yanked.
    *   `l` (Link): Target becomes related (sibling) to Yanked.
3.  **Clear (`Esc`):** Clears yank state. (`Y` locks the yanked state for multiple relations).

### 4.2. Recurrence Recycling & DST Safety
When completing a recurring task:
1.  Running timers commit to `time_spent_seconds`.
2.  A **History Snapshot** is generated (`X-CFAIT-HISTORY-OF: parent_uid`) with the completion date. This snapshot is non-recurring and retains no alarms.
3.  Master task dates advance to the next occurrence based on the `RRULE`.
4.  *DST Rule:* Absolute alarms advance using Local Naive time math. (A 9:00 AM alarm stays 9:00 AM across DST shifts).
5.  *Relative Recurrence:* If `@after 1w` (or Shift+Complete), the master task's base date temporarily shifts to `now` before advancing.
6.  *Completed* subtasks/descendants of the recurring task reset to `NeedsAction`.

### 4.3. Virtualization & Truncation (Completed Groups)
*   If completed subtasks exceed `max_done_subtasks` (or roots exceed `max_done_roots`), the Model injects a **Virtual Expand/Collapse Row** into the flattened task list.
*   Selecting this virtual row toggles visibility of the hidden completed items. State is saved in `expanded_done_groups`.
*   **Tree Navigation & Expansion (Tags, Locations, Tasks)**
    *   Tags and Locations automatically expand transiently to reveal their active selection, returning to their configured collapsed state when unselected.
    *   During searches, all matching tasks are automatically expanded so their context is visible. Users can still manually collapse tasks to temporarily hide them; this preference is saved to the database but will be overridden (auto-expanded) again on subsequent new searches.

### 4.4. Companion Events (Calendar Integration)
If `create_events_for_tasks` is enabled or `+cal` is used:
*   Generates `.ics` `VEVENT` files and `PUT`s them alongside the `VTODO`.
*   Start/Due ranges > 1 day apart split into `-start` and `-due` events.
*   WorkSessions emit as distinct events (`-session-0`).
*   `EXDATE`s sync to the event so skipped instances disappear from the user's agenda.
*   *Android Note:* Handled reliably via `CalendarSyncWorker` (WorkManager).

### 4.5. Goals & Habit Tracking
Goals act as quotas or habits and can be applied globally or locally.
*   **Global Goals:** Mapped to tags/locations using aliases (e.g., `#reading := goal:2h/w`). They appear in the Goals sidebar tab.
*   **Task-Specific Goals:** Defined directly on a task (e.g., `Read book goal:2h/w`). They replace the task's duration badge with a progress tracker. If `show_task_goals_in_sidebar` is true, they also appear under the Goals tab.
*   **Progress & Heatmaps:** Progress is calculated dynamically by summing `WorkSession` overlaps and completion dates within the calendar interval. The last 7 intervals are evaluated and rendered as a Heatmap sparkline (e.g., `■■□■■■□`) across all UI clients.
*   **Effective Goals:** Recurring tasks (`RRULE`) inherently generate a `1/period` count goal automatically to feed the Heatmap renderer, even if no explicit `goal:` token is set.
*   **Implicit Credit:** If a task with an `estimated_duration` is completed *without* explicitly running a timer, the remaining estimated time is granted instantly as goal progress. Logging a session fulfills "Count" goals if `sessions_count_as_completions` is true.

### 4.6. Permanent / Continuous Tasks
Tasks tagged with `#permanent` act as endless trackers. When checked off (Completed), they do not change status. Instead:
1. If a timer is running, it is committed as a work session.
2. If no timer is running, a session is logged using the task's `estimated_duration` (or the default goal duration).
3. The task remains in `NeedsAction` state.

### 4.7. Alarms & Reminders
*   **AlarmIndex:** Optimized cache `alarm_index.json` stores upcoming triggers.
*   **Implicit:** Auto-generated alarms for Due / Start dates (if `auto_reminders` is true).
*   **Snoozing:** Snoozing acknowledges the original alarm and creates a new absolute alarm linked via `RELATED-TO;RELTYPE=SNOOZE`.
*   **Just-In-Time (JIT) Sync:** To prevent phantom alarms across devices, clients must attempt a synchronous network fetch immediately prior to firing an alarm (or within a 15-second pre-fire window). If the task was completed, canceled, or the alarm's trigger time was advanced (via recurrence) on another device, the local alarm is pruned before notifying the user.
*   *Android Implementation:* Uses `AlarmManager.setExactAndAllowWhileIdle`. When an alarm fires, an `AlarmWorker` executes a foreground `api.sync()` before posting a Notification. Notification Actions (Snooze, Done, Pause) are handled via `NotificationActionReceiver` which delegates back to a unique `WorkManager` request to prevent background ANRs.

---

## 5. UI Layout & Platform Specifics

### 5.1. Desktop Graphical User Interface (GUI)
*Powered by `iced`. Optimized for mouse & keyboard.*
*   **Layout:** 3-pane layout (Sidebar, Main List, Markdown Details Pane).
*   **Window:** Client-Side Decorations (Custom frameless window, resize grips) unless `--force-ssd` is passed.
*   **Zooming:** Global scale via `Ctrl++`, `Ctrl+-`, and `Ctrl+ScrollWheel`. Middle-click resets.
*   **Mouse Interactions:**
    *   *Single Click:* Select row.
    *   *Double Click:* Triggers `EditTaskStart` (focus title input).
    *   *Right Click:* Opens **Full Context Menu** at cursor coordinates.
    *   *Ellipsis (`...`) Click:* Opens **Partial Context Menu** anchored to the button (shows unpinned actions).
*   **Modals:** Hovering overlays with dimmed backdrops (Move Task, ICS Import, Alarm Notification).

### 5.2. Terminal Interface (TUI)
*Powered by `ratatui`. Keyboard-only paradigm.*
*   **Layout:** 2-Pane (Sidebar 20%, Main List 80%). Details view shares vertical space with Main List. Press `Shift+Up/Down` to scroll the active details pane without losing focus on the list.
*   **Modals/Popups:** Instead of context menus, pressing `Enter` on a task opens a centered **Action Menu** popup with fuzzy filtering. 
*   **Details Viewer (`L`):** Unified popup containing the full markdown description, History/Heatmaps, WorkSessions, and relationships (Parents, Children, Blockers, Successors, Siblings) for quick jump navigation.
*   **Session Manager (`T`):** Popup to view/delete `WorkSession` records.
*   **External Editor:** Pressing `E` launches `$VISUAL`/`$EDITOR` (suspending the TUI), falling back to the built-in modal if empty.

### 5.3. Mobile Interface (Android)
*Powered by Jetpack Compose. Touch-optimized.*
*   **Layout:** 
    *   *Top Bar:* Search toggle, Quick Filter, Random Jump, Settings.
    *   *Tabs:* Desktop "Sidebar" is translated into horizontal `HorizontalPager` tabs. Pull-to-refresh triggers manual sync.
    *   *Navigation Drawer:* Swipe from the left edge to switch between Calendars, Tags, Locations, Goals view modes. (Swipe logic uses custom pointer interception to avoid conflicting with tab paging).
*   **Task List Rendering:** `LazyColumn`. Real-time relative duration formatting via coroutines (`liveDurationMins`). Real-time syntax highlighting in input via `VisualTransformation`.
*   **Task Details:** Tapping a task navigates to a dedicated `TaskDetailScreen`.
*   **Context Menu:** Long-pressing a row opens the full Dropdown Menu.
*   **Location Integration (`geo:here`):** If a user types `geo:here`, the UI requests permissions and invokes `LocationManager.getCurrentLocation`. If it fails within 5s, falls back to the last known location.
*   **Notifications:** 
    *   *Ongoing Tasks:* Generate a persistent, swipable notification with a live Chronometer and "Pause"/"Done" actions.
    *   *Alarms:* High-priority. Includes inline "Snooze Custom" via `RemoteInput` text reply.
*   **Intents:** Intercepts `ACTION_VIEW` for `.ics` files to launch the Import Screen.
*   **Debug Export:** UI includes an advanced option to generate a zip of `cache/`, `data/`, `config/`, and `android_crash.txt`, sharing it via `ACTION_SEND`.

---

## 6. Keyboard Shortcuts (GUI & TUI)

*   **Navigation:** `j`/`k` or `Up`/`Down` (Select), `Tab` (Cycle focus between Sidebar, List, Input). `1..4` (Switch Sidebar tabs).
*   **Main Actions:** 
    *   `Space`: Toggle Done/NeedsAction.
    *   `Shift+Space`: Complete & Shift recurrence (Relative advance).
    *   `s`: Start/Pause timer.
    *   `S`: Stop/Reset timer.
    *   `x`: Cancel task.
    *   `+` / `-`: Increase/Decrease priority.
    *   `e`: Edit title. `E`: Edit description (Markdown). `Ctrl+E`: Create new task with description.
    *   `Delete`: Move to trash. `Ctrl+Delete`: Delete entire tree.
    *   `t`: Log time session manually.
*   **Tree/Relationships:** 
    *   `z`: Fold/Unfold tree.
    *   `>` / `.` : Demote (Indent / Make child of previous).
    *   `<` / `,` : Promote (Outdent / Remove parent).
    *   `L` : Open relationship browser.
*   **App Actions:** 
    *   `/`: Focus search.
    *   `a`: Focus add task.
    *   `w`: Toggle Quick Filter.
    *   `m`: Toggle Match AND/OR logic for sidebar tags.
    *   `H`: Toggle Hide Completed.
    *   `*`: Clear all filters.
    *   `Shift+R`: Jump to random actionable task (weighted by priority).
    *   `Ctrl+,`: Settings.

---

## 7. Command Line Interface (CLI)
Used for headless automation, scripting, and piping. Operates directly on the `TaskStore`.

*   `cfait add <task...>`: Smart input task creation. Flags: `-c <href>`, `--desc <text>`, `-p <uid>` (set parent), `-n` (queue to journal, don't wait for network sync).
*   `cfait edit <uid> <task...>`: Edits metadata using smart syntax. Flags: `--clear-due`, `--clear-start`, `--clear-tags`, `--clear-loc`, `-p <uid>` (set parent), `--clear-parent`.
*   `cfait list [--all] [--json] [-c <id>]`: Outputs task tree.
*   `cfait search <query> [--all] [--json] [-c <id>]`: Searches and outputs tasks.
*   `cfait view <uid> [--json]`: Outputs detailed task info.
*   `cfait start|pause|toggle|done|complete|delete <uid>`: State mutation commands.
*   `cfait export [--collection <id>]`: Dumps collection as standard ICS to stdout.
*   `cfait import <file.ics> [--collection <id>]`: Parses and imports ICS to store.
*   `cfait sync`: Foreground network sync.
*   `cfait daemon`: Runs a continuous background sync loop based on `auto_refresh_interval_mins`. Acquires a cross-process lock to prevent overlapping syncs with UIs.
*   `cfait collection list|create|edit`: Manages CalDAV collections.

---

## 8. Configuration (`config.toml`)
All persistent state and settings live here. Unrecognized TOML keys must not be dropped during serialization.

**Connection & Sync:**
*   `url`, `username`: CalDAV credentials. *(Password vaulted in OS Keyring).*
*   `allow_insecure_certs`: Boolean.
*   `sync_settings`: Boolean. Enables the `cfait-global-settings-v1` hidden VTODO sync.
*   `auto_refresh_interval_mins`: Integer. Daemon sync loop interval.
*   `trash_retention_days`: Integer. Days before `local://trash` items are permanently purged. (0 = disable trash).

**UI & Behavior:**
*   `default_calendar`: String HREF.
*   `enable_local_mode`: Boolean. Allow offline `local://` collections.
*   `hide_completed`, `hide_fully_completed_tags`, `hide_aliases_in_sidebar`: Booleans.
*   `strikethrough_completed`: Boolean. Line-through styling for done tasks.
*   `ui_scale`: Float (0.5-3.0). Global zoom.
*   `theme`: Enum (RustyDark, Light, Dracula, Nord, Catppuccin variants, etc.).
*   `language`: String (`en`, `fr`). None = system locale.
*   `description_editor`: String. CLI command for TUI description editing. `builtin` forces internal UI editor.
*   `show_ongoing_notifications`, `show_priority_numbers`, `sidebar_is_hidden`, `show_goals_tab`, `show_task_goals_in_sidebar`: Booleans.
*   `pinned_actions`: Array of `TaskAction` enums. Dictates buttons pinned directly to GUI task rows.

**Sorting & Limits:**
*   `sort_preset`: Enum (`UrgentStartedDue`, `UrgentDueStarted`, `StartedUrgentDue`).
*   `sort_cutoff_days`: Integer/None. Rank 4 vs 5 divider.
*   `sort_standard_by_priority`: Boolean. Merge ranks 4/5.
*   `urgent_days_horizon`: Integer. Tasks due within X days are "Urgent" (Rank 1-3).
*   `urgent_priority_threshold`: Integer (1-9). Priorities <= X are "Urgent".
*   `default_priority`: Integer (1-9). Maps `!0` to this.
*   `start_grace_period_days`: Integer. Show future tasks X days before they start (Rank 7).
*   `max_done_roots`, `max_done_subtasks`: Integers. Triggers Virtual Expand/Collapse rows.

**Data & Events:**
*   `create_events_for_tasks`, `delete_events_on_completion`: Booleans for VEVENT generation.
*   `default_duration_goal_mins`: Integer. Implicit duration credit for checked-off tasks without an estimate.
*   `sessions_count_as_completions`: Boolean. Logging time counts towards `Count` goals.

**Reminders:**
*   `auto_reminders`: Boolean. Implicit alarms for Due/Start.
*   `default_reminder_time`: String (HH:MM). Default time for all-day date alarms.
*   `snooze_short_mins`, `snooze_long_mins`: Integers for quick snooze preset buttons.

**Quick Filters & State:**
*   `quick_filter_term`, `quick_filter_icon`, `show_quick_filter`: Quick filter button settings.
*   `hidden_calendars`, `disabled_calendars`: Arrays of HREFs.
*   `expanded_tags`, `expanded_locations`, `expanded_done_groups`: Arrays mapping visual tree expansion states.
*   `tag_aliases`: HashMap of Alias Key -> Array of Tags/Locations.
*   `goals`: HashMap of Goal Key -> Goal Object.