Portfolio

Case study

Rendered from the project README. The demo uses fictional data.

CaseNote

Django helpdesk for a portfolio demo. The tenant is the fictional retailer Northwind Outfitters. Shoppers, tickets, and staff accounts are generated by reset_demo. Nothing here is a client engagement, a review, or a measured outcome.

What it shows

Demo logins

UsernamePasswordRole
demodemoviewer, read-only, writes return 403
agentagentagent, own tickets only
leadleadlead, can reassign and close

The login page shows the same three rows. API tokens for these accounts are created by reset_demo and shown on the dashboard after login.

Run locally

Python 3.9 or newer. Django stays on 4.2 so the app can run on a 3.9 host.

python3 -m venv .venv
      .venv/bin/pip install -r requirements-dev.txt
      export SECRET_KEY=casenote-demo-key-change-before-any-real-use
      .venv/bin/python manage.py migrate
      .venv/bin/python manage.py reset_demo
      .venv/bin/pytest -q

./run.sh creates .venv if needed, migrates, loads the seed the first time the sqlite file is missing, and starts gunicorn with 2 workers. The default bind is 127.0.0.1:18808. Open http://127.0.0.1:18808/portfolio/casenote/.

reset_demo deletes the seeded desk and writes it again. A second run does not duplicate tickets.

Subpath

FORCE_SCRIPT_NAME defaults to /portfolio/casenote. STATIC_URL defaults to /portfolio/casenote/static/. Generated links include that prefix. Requests that already include the prefix, and requests whose prefix was stripped by a reverse proxy, both resolve. Static files are served by WhiteNoise.

Settings that stay off the defaults

Process

deploy/casenote.service runs gunicorn with 2 workers, MemoryMax=200M, and the same hardening lines as the other portfolio units (NoNewPrivileges, PrivateTmp, ProtectSystem=strict, ProtectHome, ReadWritePaths on the data directory). The unit does not install itself.

SLA windows are clock hours from created_at: urgent 4, high 8, normal 24, low 72. Closed tickets are not marked breached.

Open the live demo