curo1305 456681fdfa Add admin user management with role-gated access
Backend:
- schemas/user.py: is_admin (validation_alias=is_superuser) on UserOut and
  UserAdminOut; UserAdminCreate extends UserCreate with is_admin flag
- deps.py: get_current_admin dependency — 403 for non-superusers
- routers/admin.py: GET/POST /api/admin/users, DELETE and PATCH /active per
  user; self-delete and self-deactivate blocked
- main.py: register /api/admin router
- scripts/seed.py: seed test user with is_superuser=True; promotes existing
  user if already created without the flag

Frontend:
- api/client.ts: UserData type with is_admin, admin API functions
- components/Nav.tsx: Admin link visible only when user.is_admin is true
- pages/AdminPage.tsx: user table with add-user form, delete, toggle active
- App.tsx: AdminRoute guard (403-redirects non-admins to /); /admin route

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 18:40:05 +02:00

destroying_sap

A fullstack SaaS web application built with FastAPI, React, and PostgreSQL.

Stack

Layer Tech
Backend FastAPI (async), SQLAlchemy 2, Alembic, PostgreSQL 16
Auth JWT bearer tokens, bcrypt password hashing
Frontend React 18, TypeScript, Vite, React Router v6, TanStack Query

Current State

  • User registration and login (JWT auth)
  • Protected dashboard with nav bar (Dashboard | Profile | Logout)
  • /api/users/me — authenticated user info
  • /api/profile/me — GET/PUT personal profile (position, phone, date of birth, address)
  • Profile data stored in a dedicated profiles table; auto-created on first access
  • Admin role flag (is_superuser) stored in users table; exposed as is_admin in API (false for regular users, true for admins)
  • Admin-only user management at /admin: list all users, add users, delete users, toggle active status
  • All input sanitized before reaching the DB (null-byte rejection, length caps, format validation)
  • 3 separate Docker containers: db (PostgreSQL), backend (FastAPI), frontend (nginx)
  • All containers run as non-root users (UID 1001 for backend and frontend, UID 70 for db)
  • Dev environment seeds a test user automatically on startup (test@example.com / Test123!)
  • Password policy: min 8 chars, upper + lowercase, digit, special character, no common words
  • Pre-commit security hook (scripts/security_check.py) runs inside Docker on every commit

Containers

Container Image Port User (UID:GID) Description
db postgres:16-alpine 5432 70:70 (postgres) PostgreSQL database
backend custom (python:3.12-slim) 8000 1001:1001 (appuser) FastAPI management API
frontend custom (nginxinc/nginx-unprivileged:alpine) 80 1001:1001 (appuser) React UI served by nginx (internal port 8080)

The frontend nginx container proxies /api/* to the backend container internally — no CORS headers needed in production.

Installation

Prerequisites

  • Docker + Docker Compose

Production

git clone <repo>
cd destroying_sap
cp .env.example backend/.env   # edit SECRET_KEY at minimum
docker compose up --build -d

Development (hot reload)

docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build

Local (no Docker)

1. Start PostgreSQL

docker compose up db -d

2. Backend

cd backend
python -m venv .venv && source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
cp ../.env.example .env
alembic upgrade head
uvicorn app.main:app --reload

3. Frontend

cd frontend && npm install && npm run dev

Environment Variables

Copy .env.example to backend/.env and adjust:

Variable Default Description
DATABASE_URL postgresql+asyncpg://postgres:password@localhost:5432/destroying_sap Async PostgreSQL URL
SECRET_KEY change-me-in-production JWT signing key
CORS_ORIGINS ["http://localhost:5173"] Allowed frontend origins

Development

# Backend lint + format
cd backend && ruff check . && ruff format .

# Backend tests
cd backend && pytest

# Frontend type check + lint
cd frontend && npm run typecheck && npm run lint

# New DB migration (after changing models)
cd backend && alembic revision --autogenerate -m "describe change"
cd backend && alembic upgrade head
S
Description
No description provided
Readme 1.4 MiB
Languages
Python 53.2%
TypeScript 44.1%
Dockerfile 1%
CSS 0.9%
Shell 0.5%
Other 0.2%