# RBAC roles + user → role mapping. # # Single source of truth for both main backend (backend/app/core/auth.py) and # tradein backend (tradein-mvp/backend/app/core/auth.py). Mounted into both # containers at /app/auth/roles.yaml via docker-compose bind-mount. # # Glob semantics (fnmatch-based, see app.core.auth.is_path_allowed): # - "/**" → matches any path (admin scope). # - "/foo/**" → matches /foo, /foo/, /foo/bar, /foo/bar/baz/... # - "/foo" → matches exactly /foo. # # A path is allowed iff (1) it matches one of `paths` AND (2) it does NOT match # any pattern in `deny`. `deny` overrides `paths` (deny-by-default within # match scope). # # Username list MUST match exactly the entries in caddy/users.caddy.snippet # — Caddy basic_auth sets X-Authenticated-User from {http.auth.user.id}, and # unknown users hit /me with 403 ("user not in roles config"). # # Last updated: 2026-05-26 (pilot scope narrowed to /trade-in/** only — decision # 2026-05-26: pilot аккаунты пилот-программы видят ТОЛЬКО раздел Trade-In; # Analytics / Site Finder / Concept / landing — admin-only). roles: admin: paths: - "/**" deny: [] pilot: # Pilot имеет доступ ТОЛЬКО к разделу Trade-In (оценка вторички). # Landing (/), analytics, site-finder, concept, остальной /api/v1/* — закрыты. # Backend middleware всё равно пропускает known users на все non-admin paths # (path-level enforcement делает frontend RouteGuard через `allowed_paths`), # но для UX/security принципов keep deny список explicit. paths: - "/trade-in/**" - "/trade-in/api/v1/**" deny: - "/admin/**" - "/api/v1/admin/**" - "/trade-in/api/v1/admin/**" users: admin: admin kopylov: pilot user1: pilot user2: pilot user3: pilot user4: pilot user5: pilot user6: pilot user7: pilot user8: pilot user9: pilot user10: pilot praktika: pilot # пилот-аккаунт агентства «Практика» 2026-05-29 admintest: admin # temp QA 2026-05-26 pilottest: pilot # temp QA 2026-05-26