tech_notes

A collection of notes on setups and implementations.
Log | Files | Refs | README

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.