# Route Auth Audit (2026-05-09)

Generated from frontend/auth/dashboard view decorators and classified against global middleware rules in main.py.

## Summary

- Total routes found: 104
- Requires login: 93
- Mission PIN protected: 6
- Public: 5

## Rules used

- Public: /health, /login, /api/v1/auth/login, /mission/pin*
- Mission PIN protected: /dashboard/mission-control*, /api/v1/mission/*
- All other listed routes: Requires login

## Route Matrix

| File | Line | Method | Path | Expected auth rule | Note |
|---|---:|---|---|---|---|
| app/auth/backend/views.py | 12 | GET | /login | Public | Allowed in public_paths |
| app/auth/backend/views.py | 27 | GET | /2fa/setup | Requires login | Redirect to /login when unauthenticated |
| app/backups/frontend/views.py | 14 | GET | /backups | Requires login | Redirect to /login when unauthenticated |
| app/billing/frontend/views.py | 14 | GET | /billing/supplier-invoices | Requires login | Redirect to /login when unauthenticated |
| app/billing/frontend/views.py | 23 | GET | /billing/supplier-invoices2 | Requires login | Redirect to /login when unauthenticated |
| app/billing/frontend/views.py | 32 | GET | /billing/template-builder | Requires login | Redirect to /login when unauthenticated |
| app/billing/frontend/views.py | 41 | GET | /billing/templates | Requires login | Redirect to /login when unauthenticated |
| app/billing/frontend/views.py | 50 | GET | /billing/sync-dashboard | Requires login | Redirect to /login when unauthenticated |
| app/conversations/frontend/views.py | 11 | GET | /conversations/my | Requires login | Redirect to /login when unauthenticated |
| app/dashboard/backend/views.py | 161 | GET | /mission/pin | Public | Mission PIN entry/verify/logout are public |
| app/dashboard/backend/views.py | 168 | GET | /mission/pin/ | Public | Mission PIN entry/verify/logout are public |
| app/dashboard/backend/views.py | 173 | POST | /mission/pin/verify | Public | Mission PIN entry/verify/logout are public |
| app/dashboard/backend/views.py | 195 | POST | /mission/pin/logout | Public | Mission PIN entry/verify/logout are public |
| app/dashboard/backend/views.py | 201 | GET | / | Requires login | Redirect to /login when unauthenticated |
| app/dashboard/backend/views.py | 292 | GET | /dashboard/sales | Requires login | Redirect to /login when unauthenticated |
| app/dashboard/backend/views.py | 413 | POST | /dashboard/default | Requires login | Redirect to /login when unauthenticated |
| app/dashboard/backend/views.py | 452 | GET | /dashboard/default | Requires login | Redirect to /login when unauthenticated |
| app/dashboard/backend/views.py | 457 | POST | /dashboard/default/clear | Requires login | Redirect to /login when unauthenticated |
| app/dashboard/backend/views.py | 481 | GET | /dashboard/default/clear | Requires login | Redirect to /login when unauthenticated |
| app/dashboard/backend/views.py | 486 | GET | /dashboard/mission-control | Mission PIN protected | Redirect/401 to mission PIN flow when unauthenticated |
| app/dashboard/backend/views.py | 499 | GET | /dashboard/mission-control/ | Mission PIN protected | Redirect/401 to mission PIN flow when unauthenticated |
| app/dashboard/backend/views.py | 504 | GET | /dashboard/mission-control/projects | Mission PIN protected | Redirect/401 to mission PIN flow when unauthenticated |
| app/dashboard/backend/views.py | 518 | GET | /dashboard/mission-control/projects/ | Mission PIN protected | Redirect/401 to mission PIN flow when unauthenticated |
| app/dashboard/backend/views.py | 523 | GET | /dashboard/mission-control.old | Mission PIN protected | Redirect/401 to mission PIN flow when unauthenticated |
| app/dashboard/backend/views.py | 534 | GET | /dashboard/mission-control.old/ | Mission PIN protected | Redirect/401 to mission PIN flow when unauthenticated |
| app/economy/frontend/views.py | 9 | GET | /economy/time-queue | Requires login | Redirect to /login when unauthenticated |
| app/emails/frontend/views.py | 18 | GET | /emails | Requires login | Redirect to /login when unauthenticated |
| app/fixed_price/frontend/views.py | 16 | GET | /fixed-price-agreements | Requires login | Redirect to /login when unauthenticated |
| app/fixed_price/frontend/views.py | 48 | GET | /fixed-price-agreements/{agreement_id} | Requires login | Redirect to /login when unauthenticated |
| app/fixed_price/frontend/views.py | 117 | GET | /fixed-price-agreements/reports/dashboard | Requires login | Redirect to /login when unauthenticated |
| app/fixed_price/frontend/views.py | 196 | GET | /api/fixed-price-agreements/customers | Requires login | Redirect to /login when unauthenticated |
| app/modules/_template/frontend/views.py | 22 | GET | /template | Requires login | Redirect to /login when unauthenticated |
| app/modules/calendar/frontend/views.py | 15 | GET | /calendar | Requires login | Redirect to /login when unauthenticated |
| app/modules/fedex/frontend/views.py | 9 | GET | /support/fedex | Requires login | Redirect to /login when unauthenticated |
| app/modules/hardware/frontend/views.py | 219 | GET | /hardware | Requires login | Redirect to /login when unauthenticated |
| app/modules/hardware/frontend/views.py | 301 | GET | /hardware/customers | Requires login | Redirect to /login when unauthenticated |
| app/modules/hardware/frontend/views.py | 348 | GET | /hardware/new | Requires login | Redirect to /login when unauthenticated |
| app/modules/hardware/frontend/views.py | 360 | GET | /hardware/eset | Requires login | Redirect to /login when unauthenticated |
| app/modules/hardware/frontend/views.py | 423 | GET | /hardware/eset/test | Requires login | Redirect to /login when unauthenticated |
| app/modules/hardware/frontend/views.py | 431 | GET | /hardware/eset/import | Requires login | Redirect to /login when unauthenticated |
| app/modules/hardware/frontend/views.py | 439 | GET | /hardware/{hardware_id:int} | Requires login | Redirect to /login when unauthenticated |
| app/modules/hardware/frontend/views.py | 687 | GET | /hardware/{hardware_id:int}/edit | Requires login | Redirect to /login when unauthenticated |
| app/modules/hardware/frontend/views.py | 708 | POST | /hardware/{hardware_id:int}/location | Requires login | Redirect to /login when unauthenticated |
| app/modules/hardware/frontend/views.py | 754 | POST | /hardware/{hardware_id:int}/owner | Requires login | Redirect to /login when unauthenticated |
| app/modules/hardware/frontend/views.py | 829 | POST | /hardware/{hardware_id:int}/contacts/add | Requires login | Redirect to /login when unauthenticated |
| app/modules/hardware/frontend/views.py | 851 | POST | /hardware/{hardware_id:int}/contacts/{contact_id:int}/delete | Requires login | Redirect to /login when unauthenticated |
| app/modules/links/frontend/views.py | 12 | GET | /links | Requires login | Redirect to /login when unauthenticated |
| app/modules/locations/frontend/views.py | 117 | GET | /app/locations | Requires login | Redirect to /login when unauthenticated |
| app/modules/locations/frontend/views.py | 249 | GET | /app/locations/create | Requires login | Redirect to /login when unauthenticated |
| app/modules/locations/frontend/views.py | 316 | GET | /app/locations/wizard | Requires login | Redirect to /login when unauthenticated |
| app/modules/locations/frontend/views.py | 362 | GET | /app/locations/{id} | Requires login | Redirect to /login when unauthenticated |
| app/modules/locations/frontend/views.py | 533 | GET | /app/locations/{id}/edit | Requires login | Redirect to /login when unauthenticated |
| app/modules/locations/frontend/views.py | 605 | POST | /app/locations/{id}/edit | Requires login | Redirect to /login when unauthenticated |
| app/modules/locations/frontend/views.py | 661 | GET | /app/locations/map | Requires login | Redirect to /login when unauthenticated |
| app/modules/manual/frontend/views.py | 32 | GET | /manual | Requires login | Redirect to /login when unauthenticated |
| app/modules/manual/frontend/views.py | 106 | GET | /manual/admin | Requires login | Redirect to /login when unauthenticated |
| app/modules/manual/frontend/views.py | 123 | GET | /manual/{slug} | Requires login | Redirect to /login when unauthenticated |
| app/modules/orders/frontend/views.py | 12 | GET | /ordre/create/new | Requires login | Redirect to /login when unauthenticated |
| app/modules/orders/frontend/views.py | 18 | GET | /ordre/{draft_id} | Requires login | Redirect to /login when unauthenticated |
| app/modules/orders/frontend/views.py | 27 | GET | /ordre | Requires login | Redirect to /login when unauthenticated |
| app/modules/sag/frontend/views.py | 161 | GET | /sag | Requires login | Redirect to /login when unauthenticated |
| app/modules/sag/frontend/views.py | 414 | GET | /sag/new | Requires login | Redirect to /login when unauthenticated |
| app/modules/sag/frontend/views.py | 424 | GET | /sag/{sag_id}/work-orders/print | Requires login | Redirect to /login when unauthenticated |
| app/modules/sag/frontend/views.py | 437 | GET | /sag/{sag_id}/labels/hardware/print | Requires login | Redirect to /login when unauthenticated |
| app/modules/sag/frontend/views.py | 449 | GET | /sag/varekob-salg | Requires login | Redirect to /login when unauthenticated |
| app/modules/sag/frontend/views.py | 456 | GET | /sag/{sag_id} | Requires login | Redirect to /login when unauthenticated |
| app/modules/sag/frontend/views.py | 833 | GET | /sag/{sag_id}/v3 | Requires login | Redirect to /login when unauthenticated |
| app/modules/sag/frontend/views.py | 1159 | GET | /sag/{sag_id}/edit | Requires login | Redirect to /login when unauthenticated |
| app/modules/solution/frontend/views.py | 22 | GET | /solution | Requires login | Redirect to /login when unauthenticated |
| app/modules/telefoni/frontend/views.py | 13 | GET | /telefoni | Requires login | Redirect to /login when unauthenticated |
| app/modules/test_module/frontend/views.py | 22 | GET | /test_module | Requires login | Redirect to /login when unauthenticated |
| app/modules/webshop/frontend/views.py | 18 | GET | /webshop | Requires login | Redirect to /login when unauthenticated |
| app/opportunities/frontend/views.py | 9 | GET | /opportunities | Requires login | Redirect to /login when unauthenticated |
| app/products/frontend/views.py | 12 | GET | /products | Requires login | Redirect to /login when unauthenticated |
| app/products/frontend/views.py | 19 | GET | /products/{product_id} | Requires login | Redirect to /login when unauthenticated |
| app/subscriptions/frontend/views.py | 14 | GET | /subscriptions | Requires login | Redirect to /login when unauthenticated |
| app/subscriptions/frontend/views.py | 22 | GET | /subscriptions/simply-imports | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 35 | GET | / | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 101 | GET | /mockups/1 | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 106 | GET | /mockups/2 | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 111 | GET | /mockups/3 | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 117 | GET | /worklog/review | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 256 | POST | /worklog/{worklog_id}/approve | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 313 | POST | /worklog/{worklog_id}/reject | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 369 | GET | /tickets/new | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 719 | GET | /dashboard/technician | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 741 | GET | /dashboard/technician/v1 | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 763 | GET | /dashboard/technician/v2 | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 785 | GET | /dashboard/technician/v3 | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 807 | GET | /dashboard | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 878 | GET | /tickets | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 959 | GET | /archived | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 1052 | GET | /archived/{archived_ticket_id} | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 1113 | GET | /tickets/{ticket_id} | Requires login | Redirect to /login when unauthenticated |
| app/ticket/frontend/views.py | 1187 | GET | /{path:path} | Requires login | Redirect to /login when unauthenticated |
| app/timetracking/frontend/views.py | 19 | GET | /timetracking | Requires login | Redirect to /login when unauthenticated |
| app/timetracking/frontend/views.py | 25 | GET | /timetracking/wizard | Requires login | Redirect to /login when unauthenticated |
| app/timetracking/frontend/views.py | 31 | GET | /timetracking/wizard2 | Requires login | Redirect to /login when unauthenticated |
| app/timetracking/frontend/views.py | 37 | GET | /timetracking/registrations | Requires login | Redirect to /login when unauthenticated |
| app/timetracking/frontend/views.py | 43 | GET | /timetracking/customers | Requires login | Redirect to /login when unauthenticated |
| app/timetracking/frontend/views.py | 49 | GET | /timetracking/orders | Requires login | Redirect to /login when unauthenticated |
| app/timetracking/frontend/views.py | 55 | GET | /timetracking/service-contract-wizard | Requires login | Redirect to /login when unauthenticated |
| app/timetracking/frontend/views.py | 61 | GET | /timetracking/service-contract-report | Requires login | Redirect to /login when unauthenticated |
| app/timetracking/frontend/views.py | 67 | GET | /timetracking/employee-log | Requires login | Redirect to /login when unauthenticated |
