goyban 39842c72d7 Add plan dates, postponing, backlog and projects
- Tasks get an optional plan date separate from the deadline. Unfinished
  plans roll over in Today; only missed deadlines count as overdue.
- Postpone sheet on every task (tomorrow, weekend, next week, ...) that
  can move either the plan date or the deadline, with undo.
- Backlog view for undated tasks, with suggestions in Today.
- Projects with deadline, notes, progress, next step and "falling
  behind" warnings, shown in Today and in their own view.
- Times and the calendar now follow the plan date (else the deadline).
- Schema v3 migration (backup taken first); export format v3 includes
  projects and still imports older files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 14:26:32 +02:00
2026-10-07 11:43:56 +02:00
2026-10-07 11:43:56 +02:00
2026-10-07 11:43:56 +02:00
2026-10-07 11:43:56 +02:00
2026-10-07 11:43:56 +02:00
2026-10-07 11:43:56 +02:00
2026-10-07 11:43:56 +02:00
2026-10-07 11:43:56 +02:00
2026-10-07 11:43:56 +02:00

WhatToDo

A small, self-hosted to-do app for one person. It works in a desktop browser and on a phone, and you can install it to your home screen.

  • Tasks have an optional plan date (when you'll do it), an optional deadline (when it must be done), and an optional time range (e.g. 10:00–12:00). Each task also has a priority, category, tags, notes, and a checklist of steps.
  • Postpone any task from the ⏭ button: today, tomorrow, the weekend, next week, in 2 weeks, next month, or a date you pick. You can move either the plan date or the deadline.
  • Unfinished planned tasks roll over: they stay in Today until you do them or postpone them, and they never turn red. Only missed deadlines count as overdue.
  • Backlog lists tasks with no date at all. Today suggests a couple of them so they don't get forgotten.
  • Projects group the tasks of a bigger goal and have their own deadline, notes and progress bar. Today shows each active project's next step, how much time is left, and a warning if it's falling behind or nothing was done on it in over a week.
  • Recurring tasks (every N days/weeks/months/years): completing one creates the next occurrence.
  • When you pick a date and time, the task form lists what else is planned that day and warns about overlaps.
  • Views: Today, Upcoming, Calendar (day timeline with week strip; tap an hour to add a task there), Backlog, All open, Done, plus one view per project and per category.
  • You can rename, recolor, reorder, add, or delete categories in Settings. It starts with Work, Life, Personal, YouTube.
  • Export / import of all data as JSON, from Settings.
  • Login with a single password.

Stack: Python (FastAPI) + SQLite with a plain HTML/CSS/JS frontend and no build step. Everything runs in Docker.

Run locally

Requirements: Docker with the Compose plugin. Nothing else is installed on the host.

cp .env.example .env          # then edit .env: set APP_PASSWORD and SECRET_KEY
docker compose up -d --build

Open http://localhost:8080 and log in with APP_PASSWORD.

The database lives in ./data/whattodo.db, which is git-ignored.

Useful commands:

docker compose logs -f              # follow logs
docker compose down                 # stop
docker compose up -d --build        # rebuild after pulling changes
docker compose run --rm test        # run the test suite (in Docker)

Testing on your phone (same Wi-Fi)

Set BIND_ADDR=0.0.0.0 in .env, run docker compose up -d, then open http://<this-computer's-LAN-IP>:8080 on the phone. Browsers only allow "Install app" / "Add to Home Screen" with offline support over HTTPS (or on localhost). Over plain LAN HTTP the app still works, but it won't install as a full app.

Deploy to production

  1. On the server, clone the repo and create .env from .env.example. Use a new strong APP_PASSWORD and SECRET_KEY, and set COOKIE_SECURE=true.

  2. docker compose up -d --build. The app listens on 127.0.0.1:${PORT}.

  3. Put it behind a reverse proxy with HTTPS. For example, with Caddy:

    todo.example.com {
        reverse_proxy 127.0.0.1:8080
    }
    

    If the proxy runs in another container instead of on the host, set BIND_ADDR/networking to match and set FORWARDED_ALLOW_IPS to the proxy's IP. The app then sees the real client IP, which login rate limiting uses.

Moving your data from this PC to production

  1. Local app → Settings → Export data. The export includes tasks, projects and categories. This downloads whattodo-export-YYYYMMDD-HHMM.json.
  2. Production app → Settings → Import, pick the file:
    • Replace deletes everything on that install and loads the file. Use this for the first move to prod.
    • Merge adds the file's tasks to what is already there. Categories with the same name are reused.

The export file contains your tasks. Keep it out of the repo (whattodo-export-*.json is git-ignored).

Backups

Export regularly from Settings, or copy ./data/whattodo.db while the app is stopped.

Security notes

  • .env and data/ are git-ignored. Never commit them; the repository is public.
  • Changing APP_PASSWORD or SECRET_KEY logs out all sessions.
  • Failed logins are rate limited: 10 failures per 15 minutes per IP.
  • Write requests require an X-WhatToDo header (CSRF protection). The app also sends a strict Content-Security-Policy.

Project layout

app/main.py          API: auth, tasks, categories, export/import
app/db.py            SQLite schema and setup
app/static/          frontend (index.html, app.js, style.css, PWA files, icons)
tests/               API tests (run with: docker compose run --rm test)
tools/make_icons.py  regenerates the PNG icons
S
Description
No description provided
Readme 208 KiB
Languages
JavaScript 43.2%
Python 32.3%
CSS 15.1%
HTML 7.7%
Shell 1.1%
Other 0.6%