No description
  • HTML 49.3%
  • Python 48.9%
  • JavaScript 0.8%
  • Dockerfile 0.8%
  • CSS 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
edward 5ea0f28707
All checks were successful
Build & Publish Nightly Container / Build & Publish Container (:nightly) (push) Successful in 10s
Merge pull request 'add apt fallback if cache not available' (#2) from aptcache-fallback into main
Reviewed-on: #2
2026-10-13 21:45:28 +00:00
.forgejo/workflows add apt fallback if cache not available 2026-10-13 23:44:27 +02:00
app allow deletion 2026-10-13 18:49:21 +02:00
data vibe dump 2026-10-13 16:47:50 +02:00
tests use trusted proxy 2026-10-13 23:09:49 +02:00
.dockerignore vibe dump 2026-10-13 16:47:50 +02:00
.env vibe dump 2026-10-13 16:47:50 +02:00
.env.example add aptcache support 2026-10-13 23:25:10 +02:00
.gitignore fix gitignore 2026-10-13 18:09:16 +02:00
docker-compose.yml add aptcache support 2026-10-13 23:25:10 +02:00
Dockerfile add apt fallback if cache not available 2026-10-13 23:44:27 +02:00
README.md first commit 2026-10-13 16:47:41 +02:00
requirements.txt vibe dump 2026-10-13 16:47:50 +02:00

Spesen Portal

A modern, containerized web application for registering and managing volunteer expense reimbursements ("Spesen") for small volunteer-based non-profit organizations.


🌟 Key Features

  • OpenID Connect (OIDC) Authentication: Exclusively authenticates against your Identity Provider (Keycloak, Authentik, Zitadel, Google Workspace, Azure AD, etc.).
  • User Auto-Provisioning: Users are automatically provisioned and synchronized on login with their username, display_name, and email.
  • Payout Information Management: Seamlessly stores and allows updating of each volunteer's IBAN and Postal Address, with automatic IBAN grouping formatting.
  • Admin Privilege Mapping: Admin status is derived dynamically from the OIDC groups claim (groups contains 'admin').
  • Refund Requests:
    • Expense Name / Title, Amount (CHF/EUR/etc.), and Destination / Vendor.
    • Receipt image/document upload directly from mobile phone camera (capture="environment") or desktop drag-and-drop (JPG, PNG, WEBP, PDF).
    • Linked to the submitting volunteer and categorized by an admin-defined Project.
    • Volunteer view of all their requests and live status (pending, completed).
  • Admin & Treasurer Features:
    • Comprehensive view of all refund requests across all volunteers.
    • Direct visibility into volunteer IBAN and postal address for one-click payment processing.
    • Mark requests as Completed with optional payment references / audit notes.
    • Financial Project Overview: All requests sorted by project with individual and grand totals for pending, completed, and overall amounts.
    • Project Management: Create and manage projects (activate/archive).
    • CSV Export: Export all records for bookkeepers and financial audits.
  • Email Notifications:
    • Dispatched automatically via SMTP when a new refund request is registered (alert to treasurer + confirmation to volunteer).
    • Dispatched automatically to the volunteer when their refund is marked as completed and paid out.
    • Graceful dev fallback if SMTP is unconfigured.
  • Docker-Ready: Packaged with a lightweight Dockerfile and docker-compose.yml with persistent storage for SQLite data and receipts.

🚀 Quick Start with Docker

1. Clone or Navigate to the App Directory

cd /home/edward/.gemini/antigravity/scratch/spesen-app

2. Configure Environment Variables

Copy the template configuration file:

cp .env.example .env

Edit .env to configure your OIDC provider and SMTP settings. (For quick local testing without an external IdP, leave ENABLE_DEV_LOGIN=true).

3. Build & Run with Docker Compose

docker compose up -d --build

The web app is now available at: 👉 http://localhost:8000


🔐 OpenID Connect (OIDC) Configuration

The application uses standard OIDC Authorization Code Flow with PKCE.

Configure the following variables in .env:

OIDC_DISCOVERY_URL="https://auth.example.org/realms/nonprofit/.well-known/openid-configuration"
OIDC_CLIENT_ID="spesen-client"
OIDC_CLIENT_SECRET="your-client-secret"
OIDC_SCOPES="openid profile email groups"
OIDC_ADMIN_GROUP="admin"

Redirect URI

In your Identity Provider's client settings, set the Allowed Redirect URI to:

http://<your-domain-or-localhost:8000>/auth/oidc/callback

Admin Privilege Determination

Admin rights are granted if the user's OIDC token or userinfo contains:

  • groups: containing 'admin' (e.g. ["admin", "volunteers"] or comma-delimited "admin,volunteers")
  • Or fallback: group: "admin", roles: ["admin"], or Keycloak realm_access.roles: ["admin"].

📧 Email Notifications Setup

Configure your organization's SMTP server in .env:

SMTP_ENABLED=true
SMTP_HOST="smtp.example.org"
SMTP_PORT=587
SMTP_USER="spesen@example.org"
SMTP_PASSWORD="your-secure-password"
SMTP_FROM="spesen@example.org"
SMTP_FROM_NAME="Nonprofit Spesen Portal"
SMTP_STARTTLS=true
ADMIN_NOTIFICATION_EMAIL="treasurer@example.org"

When Emails are Sent:

  1. New Request Created:
    • Treasurer: Receives full expense details, project name, amount, volunteer name, IBAN, and a direct review link.
    • Volunteer: Receives submission confirmation.
  2. Request Completed:
    • Volunteer: Receives notification that their refund has been processed, the amount paid, payment reference/notes, and the destination IBAN.

📂 Project Structure

spesen-app/
├── app/
│   ├── config.py             # App settings and environment loading
│   ├── database.py           # SQLAlchemy database connection and session
│   ├── models.py             # User, Project, and RefundRequest database models
│   ├── auth.py               # OIDC authentication, claims extraction, auto-provisioning
│   ├── mailer.py             # SMTP email dispatcher with HTML templates
│   ├── main.py               # FastAPI application setup and middlewares
│   ├── routes/
│   │   ├── auth.py           # Login, OIDC exchange, logout, dev demo login
│   │   ├── requests.py       # Volunteer refund requests (list, create, detail)
│   │   ├── admin.py          # Admin project overview, all requests, complete, projects, CSV export
│   │   ├── profile.py        # User profile, IBAN & address management
│   │   └── receipts.py       # Secure receipt image & PDF serving with auth checks
│   ├── templates/            # Responsive Jinja2 templates styled with Tailwind CSS
│   └── static/               # Static CSS and JS assets (drag-and-drop, IBAN auto-format)
├── tests/                    # Pytest test suite (13 passing tests)
├── Dockerfile                # Production Dockerfile
├── docker-compose.yml        # Multi-container orchestration with persistent storage
├── .env.example              # Documented environment variables template
└── requirements.txt          # Python dependencies

🧪 Running Automated Tests

To run the test suite locally:

source .venv/bin/activate
PYTHONPATH=. pytest -v tests

Tests verify:

  • OIDC claim extraction and auto-provisioning
  • Group-based admin detection
  • User IBAN and address persistence
  • Volunteer request isolation and receipt authorization
  • Admin overview calculations (totals grouped by project)
  • Admin completion workflow and notes
  • Email notification triggers
  • CSV accounting exports