goyban 509b1a1320 Add optional time ranges and a calendar day view
Tasks can now have a start/end time on their deadline date. The new
Calendar view shows a day as a timeline (with a week strip and projected
repeats of recurring tasks), and the task form lists what is already
planned that day and flags overlaps. Existing databases are migrated to
schema v2 automatically, with a backup copy taken first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 12:08:09 +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 deadline with an optional time range (e.g. 10:00–12:00), priority (none / low / medium / high), category, tags, notes, and a checklist of steps.
  • 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 (overdue, due today, high priority), Upcoming, Calendar (day timeline with week strip; tap an hour to add a task there), All open, Done, plus one view 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. 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%