Files
whattodo/README.md
T
2026-10-12 10:48:56 +02:00

112 lines
5.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
Requirements: Docker with the Compose plugin. You don't need the source code: only `docker-compose.yaml` and a `.env`.
```sh
mkdir whattodo && cd whattodo
# copy docker-compose.yaml and .env.example from this repo into this folder
cp .env.example .env # then edit .env: set APP_PASSWORD and SECRET_KEY
docker compose up -d
```
Open <http://localhost:8080> and log in with `APP_PASSWORD`.
The database lives in `./data/whattodo.db`.
Useful commands:
```sh
docker compose logs -f # follow logs
docker compose down # stop
docker compose pull && docker compose up -d # update to the newest published version
```
To pin a version, set `WHATTODO_TAG=<version>` in `.env`, e.g. `v1.0` or a commit (default: `latest`).
## Develop (build from source)
`docker-compose.build.yaml` builds the image from this checkout. Add this line to your `.env` so plain `docker compose` uses it:
```sh
COMPOSE_FILE=docker-compose.build.yaml
```
```sh
docker compose up -d --build # build and start
docker compose run --rm test # run the test suite (in Docker)
```
### Publishing the image
`./publish.sh` builds the last commit (uncommitted changes are left out) and pushes it to
`git.goyban.com/goyban/whattodo` as `:latest` and `:<commit>`. `./publish.sh <tag|branch|commit>` publishes another version.
To release a numbered version, tag the commit first: `git tag v1.1 && ./publish.sh v1.1` also pushes the image as `:v1.1`.
Log in once first with `docker login git.goyban.com`, using a Gitea token with package write access as the password.
### 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, put `docker-compose.yaml` in a folder 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`. 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 -f docker-compose.build.yaml run --rm test)
tools/make_icons.py regenerates the PNG icons
```