@@ -22,7 +22,7 @@ Self-hosted website analytics service. Tracks page views, clicks, scrolls, sessi| App | Purpose ||---|---|| `analytics` | Project config (settings, URLs, templates, ASGI/WSGI, context processors, Playwright PDF utils). Vite outputs land in `analytics/static/`. || `analytics` | Project config (settings, URLs, templates, ASGI/WSGI, context processors, headless chromium PDF utils via `analytics/chromium.py`). Vite outputs land in `analytics/static/`. || `accounts` | Custom `User` model (UUID PK, extends `AbstractUser`). Login/logout/signup views. || `properties` | Core domain. `Property` model (a tracked site, UUID PK, belongs to User) and `Event` model (stores all analytics events as JSON in `data` field). Dashboard views, query helpers (`queries.py`), and custom card management. || `collector` | Single `POST /collect/` endpoint (CSRF-exempt, CORS-open). Receives events from client JS, enriches with GeoIP + user-agent parsing, filters bots, saves to DB. |
@@ -34,13 +34,13 @@ Self-hosted website analytics service. Tracks page views, clicks, scrolls, sessi**Collection flow:** Client sites include `collector.js` (bundled via Vite's `collector` entry point). The script sets a `collectoruserid` cookie, fires session_start (on first visit), page_view, click, scroll, and page_leave events to `POST /collect/`. The server-side view enriches session_start events with GeoIP data (optional, requires `db.mmdb` MaxMind database) and parses user-agent strings into platform/browser/device fields. Bot traffic is silently dropped.**Dashboard:** `properties/views.py:property()` is the main dashboard view. It filters events by date range, computes current vs. previous period comparisons, and builds all chart/list data server-side. Standard metric cards are computed in `properties/queries.py`. Properties can have custom event cards (stored as JSON on the Property model). The dashboard supports a `?report` query param to generate PDF reports via Playwright/Chromium.**Dashboard:** `properties/views.py:property()` is the main dashboard view. It filters events by date range, computes current vs. previous period comparisons, and builds all chart/list data server-side. Standard metric cards are computed in `properties/queries.py`. Properties can have custom event cards (stored as JSON on the Property model). The dashboard supports a `?report` query param to generate PDF reports via a headless Chromium subprocess (`analytics/chromium.py`).**Frontend:** Vite bundles 4 entry points (`base`, `pages`, `properties`, `collector`) from each app's `static_src/` directory. Uses Bootstrap 5 (SCSS), Chart.js for graphs, D3 + datamaps for the US state map. Output goes to `analytics/static/`. WhiteNoise serves static files.**Settings:** Split into `analytics/settings/__init__.py` (shared), `development.py`, and `production.py`. Dev uses SQLite at project root; production uses SQLite at `/data/db/db.sqlite3`. `DJANGO_SETTINGS_MODULE` defaults to development; production sets it via `.env`.**Production:** Single Docker container running Gunicorn with Uvicorn workers (ASGI). Caddy as reverse proxy. Data persisted to `/srv/data/analytics/`. Deployed via `git push server master` triggering a post-receive hook.**Production:** Single Docker container (Alpine 3.21 base) running Gunicorn with Uvicorn workers (ASGI). Caddy as reverse proxy. Data persisted to `/srv/data/analytics/`. Deployed via `git push server master` triggering a post-receive hook.## Key Conventions
@@ -48,4 +48,4 @@ Self-hosted website analytics service. Tracks page views, clicks, scrolls, sessi- Event data is schemaless — the `data` JSONField is the extensibility point. New event attributes are added by sending them from the client; no migration needed.- The `collector` context processor injects `collector_server` and `collector_id` into all templates so the app can track its own usage (property named "Proprium").- GeoIP is optional — if `db.mmdb` is missing, location enrichment is silently skipped.- Playwright + Chromium are bundled in the Docker image for server-side PDF generation.- Chromium is bundled in the Docker image (Alpine `chromium` package) for server-side PDF generation. `analytics/chromium.py` wraps a headless Chromium subprocess — no Playwright dependency.
@@ -32,9 +32,8 @@ dependencies:- python- uv- node- yarn- playwright (and remember to run `playwright install` for the Chromium browser)- bun- chromium (used for server-side PDF report generation via a subprocess wrapper)You can also check the `Dockerfile` for an exact list of dependencies and adjustpackage names for your desired platform.
@@ -55,15 +54,14 @@ everything.## Checking outdated dependenciesThis can be done in both yarn and uv with the following two commands:This can be done in both bun and uv with the following two commands: uv lock --upgrade --dry-run yarn outdated bun outdatedYou can then upgrade the outdated dependencies with the following two commands:You can then upgrade all dependencies at once with: uv lock --upgrade && uv sync yarn upgrade make updateI recommend testing everything after this to make sure it's all working.
modified
pages/templates/pages/changelog.html
@@ -35,6 +35,16 @@ <div class="row mt-4"> <div class="col-lg-8 offset-lg-2"> <div class="changelog-entry"> <div class="changelog-date">2026-04-18</div> <ul> <li>Replace the Playwright PDF pipeline with a headless Chromium subprocess wrapper and move the Docker base image to Alpine — smaller image, faster cold starts</li> <li>Centralize SQLite settings and expand PRAGMA tuning (WAL, synchronous, cache, mmap, temp_store)</li> <li>Speed up the property dashboard, split the property view, and surface bot traffic separately</li> <li>Swap the Exim relay for a Python direct-to-MX email backend</li> </ul> </div> <div class="changelog-entry"> <div class="changelog-date">2026-04-17</div> <ul>