Task trees with real progress.
Do It List is a small web app for breaking work into nested tasks and watching parent and root progress roll up automatically from the leaves. Importance is expressed by decomposition: break the work that matters more into more detail, and it counts for more — there are no weights to configure.
Do It List grows milestone by milestone. The execution dashboard lives in
docs/PLAN.md; the canonical product spec lives in
docs/ProductSpec.md. The first shipped milestone
is M01-BaseApp (docs/milestones/m01-baseapp/m01-baseapp.md).
- Phoenix LiveView 1.1 (Elixir 1.18)
- PostgreSQL 16
- Tailwind + DaisyUI for styling
- Bcrypt for password hashing
The whole development environment is containerised. The only host-level requirements are Docker and Docker Compose.
docker compose up --buildThen open http://localhost:4000. Register an account, create an Initiative, and start adding lists and nested tasks.
The first boot is slow — Elixir, Hex, and the JS asset toolchain are all
pulled into the image. Subsequent runs use the cached _build, deps, and
node_modules named volumes.
compose.yaml ships with sensible defaults that need no configuration. To
override them, copy .env.example to .env and edit:
| Variable | Default | Purpose |
|---|---|---|
WEB_PORT |
4000 |
Port mapped from the host to the web app. |
DB_USERNAME |
postgres |
PostgreSQL user. |
DB_PASSWORD |
postgres |
PostgreSQL password. |
DB_DATABASE |
doit_dev |
PostgreSQL database name. |
Database data lives in the named Docker volume doit_pgdata, so it survives
docker compose down. docker compose down -v wipes everything.
The test suite (notably the progress roll-up unit tests) runs inside the container too. With the stack already up, reuse the running container — no spin-up cost:
docker compose exec -e MIX_ENV=test web mix testWithout a running stack, an ephemeral container works as before:
docker compose run --rm \
-e MIX_ENV=test \
-e DB_DATABASE=doit \
web mix testThis creates a doit_test database alongside doit_dev. The pure-Elixir
progress tests in test/doit/tasks/progress_test.exs do not touch the database
at all and are the fastest signal that the roll-up math is correct.
Browser-level behavior is verified by hand — each milestone arc carries
[Human] action items in its testing section instead of automated browser
tests.
Canonical definitions live in docs/ProductSpec.md. Quick reference:
- Initiative — the top-level container, has members and many Lists.
- Task — any node in the tree.
- List — informal name for a root task (a task whose
parent_idisnull). An Initiative usually has multiple Lists, each with its own tree. - Roll-up progress —
computed_progresson a task: the average progress of all its descendant leaves (the leaf average). - Initiative member — a
(user, initiative, role)triple. Roles areowner,editor,viewer.
The principle and formula live in docs/ProductSpec.md;
detailed edge cases live in docs/milestones/m01-baseapp/m01-baseapp.md.
Pure implementation lives in DoIt.Tasks.Progress and is exercised by
test/doit/tasks/progress_test.exs.
leaf task → manual_progress (clamped 0..100)
status == "done" → 100
branch task → sum(leaf_progress) / leaf_count (all descendant leaves)
Every leaf counts one unit wherever it sits, so a subtree's pull on its
ancestors is its leaf count — decomposing a branch further is how it comes to
matter more. Marking a task done snaps its progress to 100; reopening lets
the user move it back down. Whenever a task changes, DoIt.Tasks recomputes
its ancestors recursively.
lib/doit/accounts/— user registration / login / password hashing.lib/doit/initiatives/— initiatives and initiative membership.lib/doit/tasks/— tasks, comments, activity events, and the pure-ElixirProgressmodule.lib/doit_web/live/—InitiativeIndexLiveandInitiativeShowLive. The latter subscribes toinitiative:<id>PubSub topics so other browsers see updates promptly. Last writer wins; no conflict resolution.lib/doit_web/user_auth.ex— session-based auth plug + LiveView mount hooks.
Activity events are recorded on task creation, deletion, comment, and field changes (title, status, progress, assignee, parent, priority) and are shown in the task editor sidebar.
- No drag-and-drop reordering.
sort_orderis set on creation and editable only via the JSON form field. - No conflict resolution: simultaneous edits to the same field follow last-writer-wins.
- No notifications, attachments, kanban, calendar, or AI features.
- No password reset / email confirmation flow yet — registration logs you straight in.
mix release/ production Dockerfile are out of scope for M01-BaseApp; the shipped image runsmix phx.serverindevmode.