familytree.md (3457B)
1 # Family Tree app 2 3 We document the installation of the self-hosted family tree app running at [familytree.piribauer.ch](https://familytree.piribauer.ch). 4 The source is available at [git.piribauer.ch/familytree](https://git.piribauer.ch/familytree/log.html). 5 6 The app is built with FastAPI and stores its data in a SQLite database. 7 Authentication is handled entirely by an Authentik outpost via nginx forward-auth; the app reads the `X-Authentik-Username` and `X-Authentik-Email` headers injected by nginx and never touches the Authentik API directly. 8 9 We assume that nginx and an Authentik outpost are already running, and that the repo has been cloned to `/home/julian/familytree`. 10 11 ## Python environment 12 13 The system Python on Arch Linux is PEP 668-managed and rejects direct `pip install` calls. 14 We therefore use a virtual environment: 15 16 ```console 17 $ python -m venv /home/julian/familytree/venv 18 $ /home/julian/familytree/venv/bin/pip install -r /home/julian/familytree/requirements.txt 19 ``` 20 21 ## Database directory 22 23 The app stores its data in a SQLite database under `/var/lib/familytree/`. 24 We create the directory and assign ownership to the service user: 25 26 ```console 27 # mkdir -p /var/lib/familytree 28 # chown julian:julian /var/lib/familytree 29 ``` 30 31 ## Environment file 32 33 The app reads its configuration from `/home/julian/familytree/.env`. 34 We create it with the database URL: 35 36 ```bash 37 DATABASE_URL=sqlite:////var/lib/familytree/familytree.db 38 ``` 39 40 ## Systemd service 41 42 We install the unit file included in the repo: 43 44 ```console 45 # cp /home/julian/familytree/familytree.service /etc/systemd/system/familytree.service 46 # systemctl daemon-reload 47 # systemctl enable --now familytree 48 ``` 49 50 The service runs as user `julian`, listening on `127.0.0.1:8766`. 51 We can verify it started cleanly with 52 53 ```console 54 $ systemctl status familytree 55 ``` 56 57 ## Nginx 58 59 We copy the nginx config from the repo and enable it: 60 61 ```console 62 # cp /home/julian/familytree/nginx/family /etc/nginx/sites-available/family 63 # ln -s /etc/nginx/sites-available/family /etc/nginx/sites-enabled/family 64 # nginx -t && systemctl reload nginx 65 ``` 66 67 The config forwards all requests through the Authentik outpost running on `127.0.0.1:9000`. 68 On success, nginx extracts the username and email from the outpost response and passes them to the app: 69 70 ```nginx 71 auth_request_set $authentik_username $upstream_http_x_authentik_username; 72 auth_request_set $authentik_email $upstream_http_x_authentik_email; 73 74 proxy_set_header X-Authentik-Username $authentik_username; 75 proxy_set_header X-Authentik-Email $authentik_email; 76 ``` 77 78 Unauthenticated requests are redirected to the Authentik login page. 79 80 ## Schema migrations 81 82 SQLAlchemy creates missing tables on startup with `create_all`, but does not modify tables that already exist. 83 If a column is added to the models, it must be applied to the existing database manually. 84 For example, adding a `notes` column to the `persons` table: 85 86 ```console 87 $ sqlite3 /var/lib/familytree/familytree.db "ALTER TABLE persons ADD COLUMN notes TEXT;" 88 ``` 89 90 ## Invitation flow 91 92 Users are invited by email address from within the app. 93 The invitation is stored as a pending record linked to the tree. 94 When the invited user logs in for the first time, their Authentik email is matched against all pending invitations and the corresponding tree memberships are created automatically. 95 Trees have three roles: `owner`, `editor`, and `viewer`. 96 Only owners can invite others or change roles.