Secure, role-aware API documentation portal built with Laravel 13 + Inertia 3 + React 19 + TypeScript + Tailwind 4 + shadcn/ui, using Scalar for OpenAPI rendering.
- What this project solves
- Innovations
- Key Features
- Architecture
- Quick Start (clean clone)
- Environment
- Testing & Quality Gates
- Security Notes
- Roadmap
- Contributing
This app exposes internal APIs through a safe, filter-on-the-fly docs layer:
- authenticate users with Fortify (
admin,userroles), - define what each user can see (tags + operation grants),
- define which playground servers each user can use (per-user server grants, deny-by-default),
- serve only the granted operations and granted servers from
openapi.json, - and block direct access to unauthorized routes and actions in both backend and UI.
The full spec is never sent to non-admin users; filtering happens server-side.
- Server-side per-user spec filtering
- A user receives only operations authorized by tags/endpoint grants.
- UNION semantics for grants
taggrant ORendpointgrant authorization is enough to keep an operation.
- Per-user server grants (deny-by-default)
- Each user sees only the playground servers granted to them; admins see all active servers, and a user with no grants sees none.
- Transitive component pruning
- Full
$ref/callback/webhook/schema reachability pruning avoids hidden-component leaks and dangling references.
- Full
- Anti-tampering grant validation
- User-submitted grants are checked against the live upstream spec before persistence.
- Stale-on-error upstream fallback
- Proxy keeps serving last known-good spec if upstream is unavailable or malformed.
- Audit and hardening by default
- Auth events (
login,logout,failed) are persisted; cache headers, CSRF, rate limit and mass-assignment hardening are enforced.
- Auth events (
- RBAC with
spatie/laravel-permissionand Fortify auth. /scalardocs page behind role checks./api-docs/openapi.jsonproxy endpoint:- filters spec per viewer grants,
- injects only the active playground servers granted to the viewer (admins see all active; users see only their grants; none ⇒ no servers),
- always returns
Cache-Control: private, no-store.
- Admin dashboard:
- users CRUD + grant management (tags/endpoints/servers),
- server catalog management,
- authentication log viewer,
- cache flush UI.
- OpenAPI hardening:
- SSRF checks for upstream URL,
- strict spec validation before cache,
- stale cache controls.
- Backend: Laravel 13, PHP 8.5, Pest, Larastan, Fortify, Spatie Permission.
- Frontend: Inertia 3 + React 19 + TypeScript + Tailwind 4 + shadcn/ui.
- Docs UI: Scalar + custom auth-aware shell.
- Cache: Redis in dev (Herd), array in tests.
- DB: MySQL in dev (Herd), SQLite memory in tests.
These steps are the verified local bootstrap:
- Clone and enter the repo
git clone https://github.com/padosoft/scalar-openapi-doc.git
cd scalar-openapi-doc- Install backend/frontend deps
composer install
npm install- Prepare environment
cp .env.example .env # Windows: copy .env.example .env
php artisan key:generate- Configure
.env
- Confirm the following before first run:
DB_DATABASE=scalar_openapi_docCACHE_STORE=redisADMIN_EMAIL,ADMIN_PASSWORDfor seeding/admin loginOPENAPI_UPSTREAM_URLpoints to your real spec sourceOPENAPI_ALLOWED_HOSTSincludes every approved upstream host
- Migrate + seed
php artisan migrate
php artisan db:seed --class=DatabaseSeeder --force- Start services
php artisan serve
npm run dev- Open app
- Go to
http://127.0.0.1:8000 - Login with
ADMIN_EMAIL/ADMIN_PASSWORD - Admin can open: dashboard, users, servers, auth logs, cache controls.
- Users can only access authorized docs and APIs.
Optional default:
OPENAPI_LOGIN_RATE_LIMIT_ATTEMPTSin.env.exampleis set to5for starter hardening.
Copy and keep .env.example as your template (do not commit real secrets in .env).
- PHP:
8.5recommended (Herd) - Node: modern LTS (CI runs on latest stable for this repo)
- Redis: required for local caching (
CACHE_STORE=redis) - Queue: database queue (
QUEUE_CONNECTION=database) - Tests: Laravel config automatically uses SQLite
:memory:andCACHE_STORE=array.
vendor/bin/pint --test
vendor/bin/phpstan analyse --level=max
php artisan test
npm run test
npm run build
npx playwright testFor E2E on environments that can reuse an existing dev server:
CI=1 npx playwright testauthand role checks are enforced in routes/controllers.- The client never decides authorization; backend decides what to expose.
- Grants are normalized and validated against the current spec before save.
- Per-user server grants are deny-by-default and anti-tampered server-side (only active or already-assigned servers are grantable); injected servers are filtered per viewer.
- Spec proxy is hardened with host/scheme allow-lists, method allow-lists, and malformed-server filtering.
- Auth events are immutable and logged server-side.
- Core auth + RBAC + role-based permissions
- Server-side filtering + scalar proxy
- Admin user + server + auth-log management
- Per-user server grants (deny-by-default)
- Hardening + full E2E + security polish
- WOW README and release knowledge consolidation
Follow the repository operating contract in AGENTS.md before opening PRs:
- read
docs/PLAN.md,docs/PROGRESS.md,docs/LESSON.md,docs/RULES.md - keep quality gates green on every subtask
- use the PR review loop defined there
- release notes:
CHANGELOG.md