No description
Find a file
2026-05-31 10:49:26 +01:00
.forgejo/workflows ci: replace Forgejo deploy workflow with container build pipeline 2026-05-31 10:49:26 +01:00
backend backend: tidy modules, consolidate schema migrations, expand API tests 2026-05-31 10:49:26 +01:00
frontend frontend(modals): consolidate settings modals and drop page-settings 2026-05-31 10:49:26 +01:00
.dockerignore snapshot 2026-05-28 21:24:47 +01:00
.gitignore snapshot 2026-05-28 21:24:47 +01:00
CLAUDE.md docs: add CLAUDE.md agent guide, drop legacy design/API specs, refresh READMEs 2026-05-31 10:49:26 +01:00
docker-compose.dev.yml snapshot 2026-05-28 21:24:47 +01:00
docker-compose.yml snapshot 2026-05-28 21:24:47 +01:00
Dockerfile ci: replace Forgejo deploy workflow with container build pipeline 2026-05-31 10:49:26 +01:00
README.md docs: add CLAUDE.md agent guide, drop legacy design/API specs, refresh READMEs 2026-05-31 10:49:26 +01:00

Life Towers

A personal productivity tool for organising tasks into visual "towers" of blocks, grouped on pages. Each user is identified by a client-generated token — no accounts, no passwords.

Architecture

The application runs as a single Docker container. A FastAPI process serves both the Angular SPA (as static files) and the JSON API on port 8000. Data is stored in a SQLite database file persisted via a volume mount at /data. There is no separate database server required.

The container is designed to run behind a reverse proxy (nginx, Caddy, Traefik). It honors X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Host so rate limiting and logging see the real client IP, and links built with request.url produce the correct scheme.

Quick start

# Local build (uses docker-compose.dev.yml which builds from source and
# wipes data on `down -v`):
docker compose -f docker-compose.dev.yml up --build -d

Then visit http://localhost:8000.

For a production-style run, set LIFE_TOWERS_IMAGE to point at your registry tag and use the default docker-compose.yml:

export LIFE_TOWERS_IMAGE=registry.example.com/life-towers:latest
docker compose pull
docker compose up -d

Environment variables

Variable Default Description
LIFE_TOWERS_IMAGE life-towers:local The image docker-compose.yml will run. Point at your registry tag for production deploys.
LIFE_TOWERS_PORT 8000 Host port mapped to the container.
LIFE_TOWERS_PULL_POLICY missing pull_policy passed to compose. Set always to force-pull on up.
LIFE_TOWERS_ALLOWED_ORIGIN (empty) If set, restricts CORS to this origin. Leave empty for same-origin mode (the typical setup behind nginx).
LIFE_TOWERS_PUBLIC_URL (derived from request) Absolute public URL used for canonical and Open Graph image tags. Set this when serving behind a path prefix or proxy that rewrites the visible URL.
LIFE_TOWERS_FORWARDED_ALLOW_IPS * (Optional, advanced.) Override uvicorn's --forwarded-allow-ips if you want to narrow the set of trusted proxies.

Data persistence

SQLite data is stored at /data/life-towers.db inside the container, persisted via the life-towers-data Docker named volume. Back up with:

docker compose exec life-towers sqlite3 /data/life-towers.db .dump > backup.sql

To switch to a host bind mount for easier file-level backups, see the commented line in docker-compose.yml.

Behind nginx

Sample reverse-proxy snippet:

server {
    listen 443 ssl http2;
    server_name towers.example.com;

    # SSL config omitted

    client_max_body_size 4m;     # backend enforces 2 MiB; give a small margin

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host  $host;
    }
}

Development without Docker

  • Backend: cd backend && uv run uvicorn life_towers.main:app --reload
  • Frontend: cd frontend && npm start — runs ng serve on :4200 with /api/* proxied to the backend on :8000 (see frontend/proxy.conf.json).

End-to-end tests

A docker-compose.dev.yml builds a single-container stack with an ephemeral volume — ideal for Playwright runs:

docker compose -f docker-compose.dev.yml up --build -d
cd frontend && npm run test:e2e          # http://localhost:8000
docker compose -f docker-compose.dev.yml down -v

PLAYWRIGHT_BASE_URL overrides the target (e.g. http://life-towers:8000 when Playwright itself runs in a container on the same docker network).

Deployment

Forgejo CI (.forgejo/workflows/ci.yml) tests the backend, frontend, production build, and Playwright e2e flow on every push to master.

The Docker workflow (.forgejo/workflows/docker.yml) builds and pushes images tagged latest and sha-<commit> on pushes to master or manual dispatch. It publishes to vars.REGISTRY (default ghcr.io) under the repository name, using secrets.GITHUB_TOKEN for registry auth.