# Tasks Module
Full-screen view for managing tasks (issue keys with metadata). Opened with `t` from Normal mode.
## Purpose
Time entries reference issue keys as plain strings. The tasks table gives those keys a persistent home with optional `name` and `project` fields. Tasks are auto-created when saving a time entry with a new issue key, so users never have to manually create them unless they want to fill in details.
## Files
| `mod.rs` | Exports `handle_tasks_input` and `draw_tasks` |
| `db.rs` | `impl Database` block with task CRUD (`get_all_tasks`, `create_task`, `update_task`, `delete_task`, `ensure_task_exists`) |
| `state.rs` | `impl App` block with task state methods (`open_tasks`, `refresh_tasks`, `tasks_start_creating`, `tasks_start_editing`, `tasks_save`, `tasks_delete`, cancel/confirm helpers) |
| `input.rs` | Keyboard handler. Dispatches to browse, edit, or confirm-delete sub-handlers based on current state |
| `ui.rs` | Renders the full-screen task list view: title bar, table, edit form, and context-sensitive footer |
## Types defined elsewhere
- `Task` struct — `models.rs` (id, issue_key, name, project)
- `TaskEditState` struct — `app.rs` (editing form state: task_id, issue_key, name, project, current_field)
- `InputMode::Tasks` variant — `app.rs` (holds Vec<Task>, selected_index, editing, confirm_delete)
## DB table
```sql
CREATE TABLE tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
issue_key TEXT NOT NULL UNIQUE,
name TEXT NOT NULL DEFAULT '',
project TEXT NOT NULL DEFAULT ''
);
```
Table is created in `db.rs:init_schema()`. The UNIQUE constraint on `issue_key` makes `ensure_task_exists()` use `INSERT OR IGNORE` for zero-friction auto-creation.
## Input modes
The Tasks view has three sub-states, all nested inside `InputMode::Tasks`:
1. **Browse** — `editing: None, confirm_delete: false`. Up/Down navigate, `n` create, `e` edit, `d` delete, `Esc`/`q` close.
2. **Edit** — `editing: Some(TaskEditState)`. Tab cycles fields, Enter saves, Esc cancels, char/backspace edit. When editing an existing task, `issue_key` is read-only (field 0 is skipped).
3. **Confirm delete** — `confirm_delete: true`. `y` confirms, any other key cancels.
## Auto-creation flow
In `app.rs:save_entry()`, after creating or updating a time entry with a non-empty issue_key, `db.ensure_task_exists(&issue_key)` is called. This inserts a row with empty name/project if no task with that key exists yet.
## Integration points
- `dashboard/input.rs` — routes `InputMode::Tasks` to `tasks::handle_tasks_input`, binds `t` key
- `dashboard/ui.rs` — renders `tasks::draw_tasks` when in Tasks mode (full-screen, replaces dashboard)
- `dashboard/bottom_bar/ui.rs` — returns empty vec for Tasks (view has its own footer)