3.1 KiB
3.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Flask 2.x Proof-of-Concept to demonstrate fine-grained, dynamic RBAC and multi-tenancy using Zitadel as OIDC IdP. Authentication is fully delegated to Zitadel; authorization and project assignments are handled locally via SQLite.
The full specification is in claude-context.md.
Commands
Local Development (venv)
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # then fill in Zitadel credentials
flask db-init # initialize SQLite schema
flask seed-db # seed mock data (Firma Müller, 3 projects, sample notes)
flask run
Docker / Production
docker compose up --build # builds image from Dockerfile, reads .env
docker compose down
Database CLI commands
flask seed-db # wipes and re-seeds the SQLite database with test fixtures
Architecture
Flat backend, rich local authorization:
- Zitadel (external) — handles login, issues OIDC tokens carrying the user's global role claim (
Admin,Mitarbeiter, orKunde). app/auth.py— Authlib OIDC client; extractssub, role claims, and token scopes from the IdP response; logs token payload to stdout in development.app/models.py— SQLAlchemy models for the local relational layer:User(keyed on Zitadelsub)Client(top-level company, e.g. "Firma Müller")Project(belongs to one Client)ProjectMitarbeiterMapping(N:M: employees ↔ projects)ProjectKundenMapping(N:M: external users ↔ projects)Note(timestamped text entry tied to a Project)
app/routes.py— all routing guards live here; unauthorized access always redirects tologin_error.html(never raises HTTP errors).app/config.py— reads.env; follows 12-Factor style.app/database.py— SQLAlchemy engine/session setup.
Role-Based Access (RBAC) Logic
| Role | Access |
|---|---|
Admin |
Full visibility; all clients, projects, users; global export |
Mitarbeiter |
Only projects linked via ProjectMitarbeiterMapping |
Kunde |
Only projects linked via ProjectKundenMapping for their client |
Routing guard pattern: Every protected route checks (1) Zitadel role from session, (2) local DB mapping for the requested resource. Any mismatch → redirect to /error (renders login_error.html). The error page has a JS back-button to support test flows.
Environment Variables
See .env.example:
FLASK_APP=app
FLASK_ENV=development
SECRET_KEY=...
ZITADEL_CLIENT_ID=...
ZITADEL_CLIENT_SECRET=...
ZITADEL_DISCOVERY_URL=https://<instance>.zitadel.cloud/.well-known/openid-configuration
DATABASE_URL=sqlite:///app.db
Docker Notes
Dockerfileusespython:3.11-slim, runs app viagunicorn.docker-compose.ymlbuilds from source (no pre-built images), mounts a volume for the SQLite file, and reads.envdirectly.- Setting
pull_policy: always(or equivalent) in the compose file ensures a base-image update triggers a rebuild.