247 lines
17 KiB
Markdown
247 lines
17 KiB
Markdown
# Development Progress
|
|
|
|
This is the living implementation log for Steady. Update it after every meaningful development step with what changed, why it changed, how it was verified, and what remains.
|
|
|
|
## Current Status
|
|
|
|
- Current phase: Phase 4 — Import, Export & Backup
|
|
- Status: Complete
|
|
- Last updated: 2026-08-08
|
|
- Next phase: Phase 5 — Settings & Personalization
|
|
|
|
## Phase 1 — Core Infrastructure
|
|
|
|
### 1. Application foundation
|
|
|
|
Added an application factory, environment-specific configuration, secure defaults, feature flags, and independently initialized Flask extensions.
|
|
|
|
Why: isolated application instances support testing and future deployments, while `init_app()` keeps extensions reusable. Feature packages can be added without creating a single tightly coupled application module.
|
|
|
|
Key files: `app/__init__.py`, `app/extensions.py`, `config.py`, and `wsgi.py`.
|
|
|
|
### 2. Modular routing
|
|
|
|
Added `core` and `auth` Blueprints, a `/health` endpoint, and reserved packages for tasks, settings, admin, and the versioned API.
|
|
|
|
Why: each feature owns its routes and implementation. The health endpoint provides a lightweight operational check that does not depend on authentication or database access.
|
|
|
|
### 3. Secure authentication
|
|
|
|
Implemented user registration, login, POST-only logout, password hashing, CSRF protection, safe redirects, generic login failures, and unique username/email handling. Authentication is separated into models, forms, services, and routes under `app/auth/`.
|
|
|
|
Why: separating HTTP handling from business logic allows future web and API interfaces to reuse the same account services. Security checks are part of the initial design rather than later additions.
|
|
|
|
### 4. Shared interface
|
|
|
|
Added a reusable Jinja base template, authentication pages, navigation, feedback messages, and a responsive pastel stylesheet.
|
|
|
|
Why: all future features inherit consistent navigation and accessible interaction. The interface includes keyboard focus indicators, system light/dark themes, restrained animation, and reduced-motion support.
|
|
|
|
### 5. Database migrations
|
|
|
|
Configured Flask-Migrate and generated the initial Alembic migration for the `user` table.
|
|
|
|
Why: committed migrations provide a reproducible database history as additional features introduce new tables and schema changes.
|
|
|
|
### 6. Tests and documentation
|
|
|
|
Added factory, configuration, CSRF, route, registration, password, duplicate-account, login/logout, and redirect-security tests. Added local setup, migration, and testing instructions to `README.md`.
|
|
|
|
Why: tests protect observable behavior and security boundaries. The documentation gives contributors a repeatable development workflow.
|
|
|
|
## Verification
|
|
|
|
```text
|
|
10 tests passed in 0.52s
|
|
Flask discovered all expected routes.
|
|
Alembic reported no pending model changes.
|
|
Python compilation completed successfully.
|
|
git diff --check completed successfully.
|
|
```
|
|
|
|
## Phase 2 — Task Management
|
|
|
|
### Phase 2.1 — Task data model and migration
|
|
|
|
Added an independently registered task Blueprint plus typed `Task` and `Subtask` models. Tasks include status, priority, due date, ownership, completion time, and reserved Phase 3 timing fields. Database constraints restrict status and priority values; owned subtasks cascade safely when their task is deleted. Progress is derived from subtask completion instead of stored redundantly.
|
|
|
|
Why: database constraints protect invariants even outside web forms, while ownership keys prepare every query for user isolation. Keeping progress derived prevents stale percentages when subtasks change.
|
|
|
|
Generated, reviewed, and applied the `Add tasks and subtasks` Alembic migration. The existing 10-test suite remained green after the schema change.
|
|
|
|
### Phase 2.2 — Task service layer
|
|
|
|
Added service operations for owned task lookup, filtered lists, the seven-item Today view, creation, editing, deletion, subtask creation, and subtask toggling. Today excludes completed and future-dated tasks while accepting undated inbox items. Sorting consistently favors active, higher-priority, nearer-due work.
|
|
|
|
Why: ownership filtering in the service boundary prevents routes and future APIs from accidentally exposing another user's records. Centralized ordering and completion timestamps keep behavior consistent across every interface.
|
|
|
|
Next: add validated forms and authenticated routes that use these services.
|
|
|
|
### Phase 2.3 — Forms and authenticated routes
|
|
|
|
Added validated task and subtask forms plus authenticated routes for task lists, Today, create, detail, edit, delete, subtask creation, and subtask toggling. Invalid filters return `400`; missing or foreign-owned records return `404`; all mutations require POST and CSRF validation.
|
|
|
|
Why: forms constrain input at the HTTP boundary, while the service layer remains the ownership authority. Separating read routes from POST mutations prevents links or crawlers from changing data and gives CSRF protection complete coverage.
|
|
|
|
Next: build the templates and visual components for filtering, priorities, subtasks, and progress.
|
|
|
|
### Phase 2.4 — Task-management interface
|
|
|
|
Added the full task list, Today view, create/edit form, and task detail templates. The interface includes status filters, calm priority badges, accessible native progress bars, subtask toggles, responsive layouts, empty states, and a deliberately disclosed delete action. Authenticated navigation now links to Today and Tasks.
|
|
|
|
Why: Today reduces visible choices to seven without hiding the full workspace. Native progress elements retain semantic meaning for assistive technology. Delete is available but visually separated to reduce accidental destructive actions, while empty states give a low-pressure next action.
|
|
|
|
Next: cover Phase 2 behavior and ownership boundaries with automated tests.
|
|
|
|
### Phase 2.5 — Automated coverage
|
|
|
|
Added eight Phase 2 tests covering authentication gates, complete task CRUD, status filtering, invalid filters, the seven-item Today limit, future/completed hiding, cross-user isolation, subtask-derived progress, and whitespace-only title rejection. The shared database fixture now always establishes an application context.
|
|
|
|
Why: these tests protect the feature's behavioral and security boundaries. In particular, the ownership test proves that another user receives `404` and cannot delete the record, while the Today test validates the query result and not merely page text.
|
|
|
|
Verification at this step: `18 passed in 1.51s`.
|
|
|
|
Next: run compilation, migration consistency, route discovery, whitespace, and full regression checks.
|
|
|
|
### Phase 2.6 — Final verification
|
|
|
|
Completed the full regression suite, Alembic model comparison, route discovery, Python compilation, dependency consistency check, trailing-whitespace scan, and patch-format validation.
|
|
|
|
Why: a feature is complete only when its behavior, schema, dependencies, and integration with earlier work agree. Running the Phase 1 suite alongside the new tests proves that task management did not regress authentication or the application factory.
|
|
|
|
Final results:
|
|
|
|
```text
|
|
18 tests passed in 1.50s
|
|
Alembic detected no pending model operations.
|
|
Flask discovered all expected authentication, core, and task routes.
|
|
Python compilation completed successfully.
|
|
No broken Python requirements were found.
|
|
Whitespace and git diff checks completed successfully.
|
|
```
|
|
|
|
## Phase 3 — ADHD-Specific Features
|
|
|
|
### Phase 3.1 — Focus domain
|
|
|
|
Added validated focus settings for an optional countdown, helpful context, and up to 12 comma-separated time blocks. Service operations configure focus without resetting unchanged completed blocks, toggle individual blocks, complete tasks, and calculate a forgiving streak with one internal missed-day freeze.
|
|
|
|
Why: focus behavior belongs in reusable services so the web interface does not become the only possible client. The streak is derived from completion history rather than stored counters, avoiding drift and making the freeze rule explainable. The current day is never counted as missed while it is still underway.
|
|
|
|
Next: expose these operations through authenticated, ownership-safe Focus Mode routes.
|
|
|
|
### Phase 3.2 — Focus Mode routes
|
|
|
|
Added Focus Mode routes for the highest-ranked Today task or an explicitly selected owned task. Added protected mutations for focus settings, chunk toggles, and completion. Focus rendering includes the derived streak and moves to the next eligible task after completion.
|
|
|
|
Why: the default route surfaces exactly one decision, while explicit task focus preserves user control. All mutations remain POST-only with CSRF and ownership checks. Completing a task redirects to the next focus item instead of returning users to a visually dense list.
|
|
|
|
Next: build the focused screen, countdown controls, chunk plan, context cue, and positive completion feedback.
|
|
|
|
### Phase 3.3 — Focus interface and feedback
|
|
|
|
Added a single-task Focus Mode screen with an optional persistent visual countdown, time-block checklist, visible context cue, forgiving streak card, and focused completion action. Added navigation from task cards and details. Completion moves to the next task and renders a calm celebration with an optional synthesized chime.
|
|
|
|
The timer uses local browser storage to survive reloads, supports start/pause/reset, announces completion to assistive technology, and continues in-page if storage is unavailable. Chime failures are ignored so browser audio policy can never block task completion.
|
|
|
|
Why: only one task is rendered as the primary action. Timer state is local interaction state rather than high-frequency database traffic. Context is explicitly a visible placeholder with no hidden location tracking. Feedback remains optional and respects the user's existing chime preference.
|
|
|
|
Next: add accessible styling and automated tests for focus selection, settings, chunks, streak rules, completion, and ownership.
|
|
|
|
### Phase 3.4 — Automated coverage
|
|
|
|
Added eight tests for single-task focus selection, focus configuration, invalid chunk plans, exact block toggling, completion and advancement, ownership isolation, an internal rest-day freeze, and an unfinished current day. The full suite now contains 26 passing tests.
|
|
|
|
Why: deterministic dates make the emotional contract of the forgiving streak testable. Ownership tests cover every new mutation, while the advancement assertion distinguishes the completed-task confirmation from the next primary focus heading.
|
|
|
|
Verification at this step: `26 passed in 2.53s`.
|
|
|
|
Next: run JavaScript syntax, Python compilation, migration, dependency, routing, formatting, and full regression checks.
|
|
|
|
### Phase 3.5 — Final verification
|
|
|
|
Completed the full regression suite, JavaScript syntax validation, Alembic model comparison, Flask route discovery, Python compilation, dependency consistency, line-length and trailing-whitespace scans, and patch-format validation. Added the same positive completion action to task details so feedback is not restricted to users who enter Focus Mode first.
|
|
|
|
Why: Phase 3 combines client-side state with server-side ownership rules, so both language runtimes and their integration points require validation. Reusing the protected completion route keeps completion semantics, streak history, and feedback consistent from every entry point.
|
|
|
|
Final results:
|
|
|
|
```text
|
|
26 tests passed in 2.54s
|
|
JavaScript syntax validation completed successfully.
|
|
Alembic detected no pending model operations.
|
|
Flask discovered all expected routes.
|
|
Python compilation completed successfully.
|
|
No broken Python requirements were found.
|
|
Line-length, whitespace, and git diff checks completed successfully.
|
|
```
|
|
|
|
## Phase 4 — Import, Export & Backup
|
|
|
|
### Phase 4.1 — Reversible completed-task clearing
|
|
|
|
Added soft-clear timestamps and user-scoped batch identifiers to tasks. Normal task queries now exclude cleared records, while streak history intentionally retains their completions. Added services to clear all currently completed tasks in one batch and restore only that user's matching batch. Upload requests are globally limited to 2 MiB.
|
|
|
|
Why: “clear” should not mean immediate permanent deletion. Batch identifiers create a precise undo target without exposing sequential database IDs, and ownership is enforced again during recovery. Retaining completion timestamps preserves the user's forgiving streak after tidying the task list.
|
|
|
|
Next: migrate the schema, then implement bounded and atomic import/export services.
|
|
|
|
The `Add reversible task clearing` migration was generated, reviewed, applied, and followed by a green 26-test regression run.
|
|
|
|
### Phase 4.2 — Validated transfer services
|
|
|
|
Added UTF-8 Markdown/plain-text parsing for headings, bullets, numbered items, and checklists, with a 200-task and 200-character-title limit. Bulk creation commits once after the entire document validates.
|
|
|
|
Added a versioned JSON backup format containing active tasks, subtasks, focus setup, completion history, and user preferences—but no password hash, email address, database IDs, or ownership fields. Restore validates the complete document, bounds nested collections and values, assigns every task to the current user, and supports merge or replace behavior in one transaction.
|
|
|
|
Why: uploads are untrusted input. Full validation before mutation prevents partial imports, explicit schema versions allow safe evolution, and omitting identity/security fields prevents a backup from changing account ownership or credentials. Atomic restore ensures failure leaves existing data intact.
|
|
|
|
Next: add CSRF-protected forms and authenticated routes for import, export, clear, and undo.
|
|
|
|
### Phase 4.3 — Protected transfer routes
|
|
|
|
Added an authenticated data-transfer hub plus separate routes for Markdown import, JSON download, JSON restore, clearing completed tasks, and undoing a specific clear batch. All uploads and state changes require validated Flask-WTF forms and CSRF; downloads contain only the current user's active data. Undo route identifiers use Flask's UUID converter and are rechecked against the current user in the service.
|
|
|
|
Why: separating each mutation keeps permissions and error handling explicit. Downloads remain GET because they do not change server state; import, replace, clear, and undo remain POST-only. File names and ownership values from uploads are never used to select database records.
|
|
|
|
Next: build the instructional transfer interface and visible undo recovery control.
|
|
|
|
### Phase 4.4 — Transfer and recovery interface
|
|
|
|
Added a responsive Data & Backups hub with the supported Markdown format, explicit limits, JSON privacy scope, merge/replace distinction, confirmation controls, and a disclosed completed-task clear action. After clearing, a prominent recovery banner explains that tasks are hidden and provides a CSRF-protected undo button. Authenticated navigation now links to the hub.
|
|
|
|
Why: import and replacement have different risk profiles, so their consequences are explained next to the action. File inputs advertise accepted formats without treating browser hints as security validation. Clear remains visually available but not effortless to trigger accidentally, and recovery is surfaced immediately.
|
|
|
|
Next: test parser limits, atomic restore, privacy, ownership, replacement, clear/undo, and upload routes.
|
|
|
|
### Phase 4.5 — Automated coverage
|
|
|
|
Added tests for Markdown syntax, encoding and size limits, confirmed upload behavior, versioned/private JSON output, nested backup round trips, JSON upload ownership, invalid-replace atomicity, user-isolated replacement, streak-preserving soft clear, foreign-user undo rejection, and browser-route recovery.
|
|
|
|
During the quality pass, Markdown database failures gained explicit rollback handling, and backup validation now rejects inconsistent task states such as completed tasks without completion timestamps.
|
|
|
|
Why: rollback behavior keeps the SQLAlchemy session usable after failure, while state/date consistency preserves streak and status meaning after restore. Testing the upload route proves ownership is assigned from the active session rather than merely working in direct service calls.
|
|
|
|
Next: run the complete regression, migration, route, dependency, compilation, JavaScript, line-length, whitespace, and patch checks.
|
|
|
|
### Phase 4.6 — Final verification
|
|
|
|
The first full verification exposed a misplaced date-validation block in the JSON serializer. Four transfer tests failed while 33 passed. The validation was moved into `_validate_task`, the focused 11-test transfer suite passed, and then the complete verification was repeated successfully.
|
|
|
|
Why: structurally similar dictionary-return blocks made a broad patch match the wrong function. Running focused tests after the correction provided fast evidence for the affected subsystem before the final regression. Recording this makes the progress log reflect corrective work as well as completed features.
|
|
|
|
Final results:
|
|
|
|
```text
|
|
37 tests passed in 3.79s
|
|
All 11 focused transfer tests passed.
|
|
Alembic detected no pending model operations.
|
|
Flask discovered all expected routes.
|
|
Python and JavaScript syntax validation completed successfully.
|
|
No broken Python requirements were found.
|
|
Line-length, whitespace, and git diff checks completed successfully.
|
|
```
|
|
|
|
## Next Work
|
|
|
|
Phase 5 will expose the existing theme, dyslexia-font, completion-chime, and notification preferences through an authenticated settings feature. It will also add the browser-reminder placeholder without requesting notification permission prematurely.
|