509b1a1320
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>
85 lines
3.9 KiB
Markdown
85 lines
3.9 KiB
Markdown
# 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.
|
||
|
||
```sh
|
||
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:
|
||
|
||
```sh
|
||
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
|
||
```
|