ParallelPathdocumentation

Developer guide

How ParallelPath is built, how to run it locally, and how to contribute. The complete source running on this server is browsable at /source.

Design goals

  1. Trustworthy records - immutable messages, versioned everything, hash-chained audit, verifiable reports.
  2. Private by default - envelope encryption of all family content, no third-party requests, admins can't read content.
  3. Light - one Python process, PostgreSQL, nginx. Runs on a 1 GB VPS. No JavaScript build step, no frameworks in the browser.
  4. Easy to self-host - one interactive installer; plays nicely next to existing sites.
  5. Accessible - WCAG 2.2 AA target.

Stack

Layer Technology
Web framework FastAPI on Uvicorn, server-rendered Jinja2 templates
Database PostgreSQL 16+ via SQLAlchemy 2 + psycopg 3 (SQLite for development/tests)
Crypto cryptography (AES-256-GCM, HKDF), argon2-cffi, pyotp
Realtime WebSockets (in-process hub) for chat, notifications and WebRTC signalling
Calls Browser WebRTC + coturn TURN relay
Reports ReportLab (PDF), csv, json
Front end Hand-written CSS (static/css/app.css) and vanilla JS (static/js/*.js), no dependencies
Ops systemd (sandbox, encrypted credentials, timers), nginx, AppArmor, fail2ban, ufw, LUKS2

Repository layout

install.sh                 interactive installer (install / upgrade / tls / uninstall)
deploy/                    systemd units, nginx/coturn templates, AppArmor, fail2ban, ppctl, root helper
  pp-sysd.py               root helper: metrics, fail2ban bridge, encrypted backups/restore
app/
  requirements.txt
  parallelpath/
    main.py                app + security middleware + error handling
    config.py              settings from env / systemd credentials
    db.py, models.py       SQLAlchemy models (columns ending _enc are ciphertext)
    schema.py              table creation + PostgreSQL triggers and least-privilege grants
    crypto.py              envelope encryption, chunked file encryption, key rotation
    audit.py               hash-chained audit trail + entity revisions
    security.py            passwords, TOTP, sessions, rate limiting
    web.py                 request context (Ctx), permissions, templates, helpers
    tone.py                Tone Check: local heuristics + Ollama/OpenAI-compatible/Claude providers
    realtime.py            WebSocket hub
    storage.py             encrypted blob store
    sitecfg.py             admin-editable settings
    mailer.py              optional SMTP
    cli.py                 ppctl commands
    routes/                one module per area (auth, family, messages, calendar, files, expenses,
                           records, calls, reports, home, admin)
    templates/             Jinja2 templates (admin/ is the separate admin portal)
    static/                css, js, icons, wiki screenshots, service worker
    wiki/                  these pages (Markdown)
  tests/                   pytest end-to-end, security and unit tests
tools/screenshots.py       seeds a demo instance and captures the wiki screenshots

Running locally

Requires Python 3.12+.

python -m venv .venv
. .venv/bin/activate            # Windows: .venv\Scripts\activate
pip install -r app/requirements.txt pytest pytest-xdist
cd app
PP_DEV=1 uvicorn parallelpath.main:app --reload --port 8000

PP_DEV=1 uses SQLite in ./devdata, auto-generates a development master key, and allows plain-HTTP cookies. Create accounts with:

PP_DEV=1 python -m parallelpath.cli create-admin

Then sign in at http://localhost:8000/admin/login and invite a person.

Tests

cd app
python -m pytest tests -n auto --dist loadfile

The suite covers the whole user journey (two parents and a professional), access control between families, portal separation, CSRF blocking, security headers, brute-force limits, user-enumeration resistance, audit tamper detection, the source secret-scanner, DST-safe repeating events and schedule parsing.

Screenshots

python tools/screenshots.py

Seeds fictional demo data into a temporary instance and uses a local headless Edge/Chrome over the DevTools protocol to regenerate static/wiki/*.png and the app icons.

Key concepts

Request context and permissions

Every family route depends on app_ctx, which loads the signed-in person, their active family membership, the family's cipher, members and children. ctx.can("expenses.view") / ctx.require(...) implement roles: parents can do everything; others get explicit scopes (messages, calendar.view, files.view, ...). Admin routes use admin_ctx and a different cookie.

Encrypting a field

obj.title_enc = ctx.cipher.enc(title, f"events.title:{obj.id}")      # AAD = table.column:row-id
title = ctx.cipher.dec(obj.title_enc, f"events.title:{obj.id}")

Always set id=uid() explicitly before encrypting so the AAD can include it.

Changing anything

Every update path: require a reason (need_reason), bump version, then call audit.revise(...) with a full snapshot. This writes an encrypted revision and an audit event. Never DELETE - set deleted_at. The PostgreSQL triggers in schema.py will reject updates/deletes on evidence tables, so tests on SQLite alone aren't enough for schema work - run against PostgreSQL too.

Audit trail

audit.record(db, action, actor=..., family_id=..., target_type=..., target_id=..., reason=..., details=...) inside the request's transaction. Reasons/details are encrypted (family or system key) and the row hash covers their ciphertext.

Tone Check providers

Add a provider by writing _name(cfg, text, timeout) -> dict in tone.py and registering it in PROVIDERS. It must return score, labels, flagged, suggestion. Failures fall through to the next provider and finally to local_check.

Front end

No build step. app.js handles preferences, dialogs, the WebSocket, Tone Check, geolocation and PWA install; files.js the explorer; call.js WebRTC; thread.js, forms.js, admin.js small page helpers. Inline scripts and on*= attributes are blocked by the CSP - use data-* hooks.

Contributing

  1. Keep it light: no new heavy dependencies; no external requests from the browser.
  2. Every feature must keep the audit/immutability guarantees.
  3. Add tests (app/tests) and run the full suite.
  4. Keep accessibility: labels, keyboard support, no colour-only meaning.
  5. Licence: contributions are accepted under AGPL-3.0.

Licence

GNU Affero General Public License v3.0 - if you run a modified version as a public service, you must offer your users its source. ParallelPath does this automatically via /source.

Built by DarkCipher0x at DarkCipher Systems.