Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
42c64cd
fix: adapt docker compose for local Docker Compose v2.16
yanhub Aug 18, 2026
072f877
chore: add manager and member seed credentials to env
yanhub Aug 18, 2026
2ea71ff
feat: add RBAC roles, permissions module, migration, and seed users
yanhub Aug 18, 2026
15861c7
feat: enforce RBAC on user routes and add metrics endpoint
yanhub Aug 18, 2026
06901d3
test: add authorization tests and role fixtures
yanhub Aug 18, 2026
d510c93
feat: add frontend permission helpers and access denied UI
yanhub Aug 18, 2026
0f4f024
feat: wire RBAC into sidebar, routes, and admin UI
yanhub Aug 18, 2026
058680f
docs: document RBAC setup, permissions, and smoke test script
yanhub Aug 18, 2026
b0b97f4
chore: remove agent skill symlinks and ignore IDE tool dirs
yanhub Aug 18, 2026
fd2e247
docs: add English AI conversation exports for submission
yanhub Aug 18, 2026
f731b0a
chore: add compose.override.example.yml and gitignore local override
yanhub Aug 18, 2026
046ad0d
feat: log authorization denials and add coverage test
yanhub Aug 18, 2026
98df383
docs: add RBAC ADRs, NOTES, and bonus submission docs
yanhub Aug 18, 2026
c81c118
docs: add reviewer guide for non-fork template diff
yanhub Aug 18, 2026
ec3fbd8
Revert "docs: add reviewer guide for non-fork template diff"
yanhub Aug 18, 2026
794eea8
chore: add script to fork upstream template and open PR
yanhub Aug 18, 2026
ea15e2d
docs: document fork and PR submission workflow
yanhub Aug 18, 2026
1a6a4e2
fix: use real GitHub CLI path instead of conflicting /usr/bin/gh
yanhub Aug 18, 2026
b92eaa9
fix: rebase onto upstream before fork push for valid PR
yanhub Aug 18, 2026
5f3a741
🎨 Auto format and update with pre-commit
pre-commit-ci-lite[bot] Aug 18, 2026
d78a13f
chore: remove one-time fork setup script after PR is open
yanhub Aug 18, 2026
47b8ca9
🎨 Auto format and update with pre-commit
pre-commit-ci-lite[bot] Aug 18, 2026
3e2b3e7
fix: CI compose override and StrEnum for ruff UP042
yanhub Aug 18, 2026
0ae89fa
fix: sync superuser flag in crud and satisfy ruff in tests
yanhub Aug 18, 2026
1953abc
fix: honor is_superuser=True when creating users with default role
yanhub Aug 18, 2026
124fce2
test: cover auth deps edge cases for 90% coverage threshold
yan Aug 18, 2026
16e0440
test: update admin playwright specs for RBAC roles
yan Aug 18, 2026
4ee58dd
fix: derive is_superuser from role and stop PATCH role demotion
yanhub Aug 18, 2026
7dd186b
🎨 Auto format and update with pre-commit
pre-commit-ci-lite[bot] Aug 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .agents/skills/fastapi

This file was deleted.

4 changes: 0 additions & 4 deletions .agents/skills/library-skills/.library-skills.json

This file was deleted.

37 changes: 0 additions & 37 deletions .agents/skills/library-skills/SKILL.md

This file was deleted.

1 change: 0 additions & 1 deletion .agents/skills/sqlmodel

This file was deleted.

1 change: 0 additions & 1 deletion .claude/skills/fastapi

This file was deleted.

4 changes: 0 additions & 4 deletions .claude/skills/library-skills/.library-skills.json

This file was deleted.

37 changes: 0 additions & 37 deletions .claude/skills/library-skills/SKILL.md

This file was deleted.

1 change: 0 additions & 1 deletion .claude/skills/sqlmodel

This file was deleted.

7 changes: 6 additions & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ FASTAPI_ENV=development

PROJECT_NAME="Full Stack FastAPI Project"

SECRET_KEY=changethis
SECRET_KEY=dev-local-jwt-secret-key-minimum-32-characters-long
FIRST_SUPERUSER=admin@example.com
FIRST_SUPERUSER_PASSWORD=changethis

MANAGER_USER=manager@example.com
MANAGER_USER_PASSWORD=changethis
MEMBER_USER=member@example.com
MEMBER_USER_PASSWORD=changethis

# Emails
SMTP_HOST=localhost
EMAILS_FROM_EMAIL=info@example.com
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ jobs:
if: ${{ needs.changes.outputs.changed == 'true' }}
timeout-minutes: 15
runs-on: ubuntu-latest
env:
COMPOSE_FILE: compose.yml:compose.override.example.yml
strategy:
matrix:
shardIndex: [1, 2, 3, 4]
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test-backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ jobs:
test-backend:
runs-on: ubuntu-latest
timeout-minutes: 5
env:
COMPOSE_FILE: compose.yml:compose.override.example.yml
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test-docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ jobs:
test-docker-compose:
runs-on: ubuntu-latest
timeout-minutes: 10
env:
COMPOSE_FILE: compose.yml:compose.override.example.yml
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
.vscode/*
!.vscode/extensions.json
.idea/
.agents/
.claude/
node_modules/
backend/app/frontend/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
compose.override.yml
41 changes: 41 additions & 0 deletions NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Notes for Reviewers

Supplementary context for the [Fullstack Dev Test Task](https://github.com/evios/Fullstack-Dev-Test-Task). Required deliverables are in `README.md`; this file covers scope, trade-offs, and follow-ups.

## What Was Prioritized

1. **Centralized backend policy** — `permissions.py` + `require_permission()` dependencies.
2. **Consistent frontend UX** — hidden nav, route guards, `AccessDenied` component.
3. **Focused tests** — eight authorization scenarios (allow + deny paths), including denial logging.
4. **Runnable setup** — Docker Compose, seed users, migration, smoke script.

## Scope Cuts (and Why)

| Cut | Reason |
|-----|--------|
| E2E Playwright tests for RBAC | Backend tests + manual smoke cover critical paths within timebox |
| `/me/permissions` API | Small static matrix; mirroring in frontend is simpler (see ADR 002) |
| Row-level / resource ownership rules | Assignment surface is role-based, not object-level ACL |
| Regenerating OpenAPI client for `role` | Patched `types.gen.ts` manually; `generate-client.sh` needs running stack |

## Trade-offs

- **`is_superuser` is derived from `role`** — PostgreSQL generated column plus read-only `@computed_field` in API responses; writable schemas accept `role` only (`extra="forbid"` blocks legacy `is_superuser` input).
- **Items use the permission layer** — Admin holds `items:list_any` / `items:manage_any`; manager and member manage only their own items.
- **Frontend permission duplication** — Acceptable for three roles; would generate or fetch capabilities in a larger system.

## Observability

Denied authorization attempts are logged at `WARNING` from `app.api.deps` with user id, email, role, and requested permission or required roles. Useful for audit trails and debugging mistaken 403 responses.

## With More Time

- Add Playwright flows: login as member → direct `/admin` → see Access Denied.
- Expose read-only permissions in OpenAPI and regenerate the frontend client.
- Structured audit log table for denied access (not only application logs).
- Feature flags or admin UI to assign roles without DB access.

## Architecture Docs

- ADRs: `docs/adr/001-permission-based-rbac.md`, `docs/adr/002-frontend-permission-mirror.md`
- Auth flow diagram: `README.md` (Mermaid)
122 changes: 122 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,125 @@
# Full Stack FastAPI Template — RBAC Extension

This project extends the [Full Stack FastAPI Template](https://github.com/fastapi/full-stack-fastapi-template) with role-based access control (RBAC) for the [Fullstack Dev Test Task](https://github.com/evios/Fullstack-Dev-Test-Task).

## Submission

Fork PR: https://github.com/fastapi/full-stack-fastapi-template/pull/2445
Fork: https://github.com/yanhub/full-stack-fastapi-template

## Quick Start (Docker)

Requires [Docker Desktop](https://www.docker.com/products/docker-desktop/) (macOS, Linux, or Windows).

```bash
git clone <repository-url>
cd <project-directory>
cp compose.override.example.yml compose.override.yml
docker compose build backend
docker compose run --rm backend bash scripts/prestart.sh
docker compose up -d
```

Open:

| Service | URL |
|---------|-----|
| App (API + frontend) | http://localhost:8000 |
| API docs | http://localhost:8000/docs |
| Adminer | http://localhost:8080 |
| Mailpit | http://localhost:8025 |
| Traefik (via proxy) | http://localhost |

`compose.override.yml` is local-only (see `compose.override.example.yml`). Adjust ports there if `80` or `5432` are already in use on your machine.

## Seed Users

| Email | Password | Role |
|-------|----------|------|
| admin@example.com | changethis | admin |
| manager@example.com | changethis | manager |
| member@example.com | changethis | member |

Credentials are configured in `.env` (`FIRST_SUPERUSER*`, `MANAGER_USER*`, `MEMBER_USER*`).

## Permission Matrix

| Action | admin | manager | member |
|--------|:-----:|:-------:|:------:|
| List all users | yes | yes | no |
| Create user | yes | no | no |
| View metrics | yes | yes | no |
| Update own profile | yes | yes | yes |
| Update any profile | yes | no | no |
| Global settings | yes | no | no |
| List all items | yes | no | no |
| Manage any item (read/update/delete) | yes | no | no |
| Manage own items | yes | yes | yes |

## Authorization Approach

Roles are stored on the `User.role` column (`admin`, `manager`, `member`) with an Alembic migration backfilling existing superusers to `admin`.

Backend authorization is centralized in `backend/app/core/permissions.py`. FastAPI dependencies in `backend/app/api/deps.py` expose `require_permission(...)` and enforce checks on route handlers (users, metrics). The API returns HTTP `403` with a clear message when access is denied.

The frontend mirrors the same permission matrix in `frontend/src/lib/permissions.ts`. The `usePermissions()` hook drives sidebar visibility, route-level UI guards, and an `AccessDenied` component for direct navigation to forbidden pages. The backend remains the source of truth; the UI only hides or blocks navigation for better UX.

Denied access attempts are logged at `WARNING` level from `app.api.deps` (user id, email, role, permission) for observability.

### Authorization Flow

```mermaid
flowchart TB
subgraph client [Frontend]
Login[Login / JWT stored]
Hook[usePermissions from user.role]
Nav[Sidebar hides forbidden links]
Guard[Route guard / AccessDenied]
Login --> Hook --> Nav
Hook --> Guard
end

subgraph api [Backend API]
JWT[get_current_user validates JWT]
Perm[require_permission dependency]
Matrix[user_has_permission in permissions.py]
Route[Route handler]
JWT --> Perm --> Matrix
Matrix -->|allowed| Route
Matrix -->|denied| Log403[Log WARNING + HTTP 403]
end

Guard -->|API call| JWT
Nav -->|API call| JWT
```

Further reading:

- [NOTES.md](NOTES.md) — scope cuts, trade-offs, follow-ups
- [docs/ai-conversations/](docs/ai-conversations/) — English copies of AI-assisted development sessions (submission requirement)
- [docs/adr/001-permission-based-rbac.md](docs/adr/001-permission-based-rbac.md)
- [docs/adr/002-frontend-permission-mirror.md](docs/adr/002-frontend-permission-mirror.md)

## Running Tests

```bash
# Authorization-focused tests (rebuild backend image after pulling changes)
docker compose run --rm backend pytest tests/api/routes/test_authorization.py -v

# Smoke check (Python 3 on the host; stack must be up)
python3 scripts/smoke_rbac.py
```

## Database Migrations

```bash
docker compose run --rm backend alembic upgrade head
```

New migration: `a1b2c3d4e5f6_add_user_role.py` (adds `role` column).

---

# Full Stack FastAPI Template

[![Test Docker Compose](../../actions/workflows/test-docker-compose.yml/badge.svg)](../../actions/workflows/test-docker-compose.yml)
Expand Down
Loading
Loading