3.5 KiB
3.5 KiB
Phase 15: UX Polish + Super Admin Ops Tools
Status: Not started Depends on: All previous phases
Goal
Production-ready polish: audit log viewer, global search, bulk operations, mobile-responsive portal, keyboard shortcuts, error boundaries, and production security hardening.
Planned Scope
Backend
Audit log viewer endpoint
GET /api/audit-logs— paginated, filterable by school, action, actor, date range- Already have
audit_logstable — just need the endpoint + frontend
Global search endpoint
GET /api/search?q={query}— searches across schools, invoices, tickets- Returns grouped results:
{ schools: [...], invoices: [...], tickets: [...] } - Limit 5 results per category
Bulk school actions
POST /api/schools/export-csv— export school list as CSV (name, status, tier, credits, license)POST /api/schools/bulk-status— change status for multiple school IDs (super admin)
Rate limiting on auth endpoints
- Add
slowapimiddleware:POST /auth/login— max 10 req/min per IP - Return
429 Too Many Requestswith Retry-After header
HTTPS redirect
- Add redirect middleware in
main.py(X-Forwarded-Proto check) - Update
nginx.confto pass X-Forwarded-Proto header
Frontend
Audit log page (AuditLogPage.vue — new or sub-section in admin)
- Table: timestamp, actor, action, entity type, entity name, IP
- Filters: date range, actor, action type
Global search (keyboard shortcut /)
SearchModal.vue— command palette style- Press
/anywhere → modal opens with search input - Results grouped by type, click navigates to entity
Keyboard shortcuts
/— open global searchN— new school (when on /schools)Esc— close any open modal
Mobile-responsive portal
- PortalSidebar: collapsible on mobile (hamburger menu)
- PortalLayout: responsive header
- All portal pages: responsive table → card layout on mobile
Error boundary component (ErrorBoundary.vue)
- Wraps page content in AppLayout/PortalLayout
- On uncaught error: shows friendly "Something went wrong" card with retry button
Empty state illustrations
- SchoolsPage: "No schools yet" with Add School CTA
- TicketsPage: "No tickets" with Submit Ticket CTA
- BillingPage: "No invoices yet" with Generate Invoices CTA
Dashboard refresh UX
- Auto-refresh every 5 minutes (setInterval)
- Show "Data may be stale" banner after 10 minutes without refresh
CSV export button in SchoolsPage toolbar
Key Files to Create/Modify
backend/app/routers/search.py(new)backend/app/routers/audit.py(new — expose existing audit_logs table)backend/app/routers/schools.py— bulk-status + export-csv endpointsbackend/app/main.py— include search + audit routers, add rate limit + HTTPS middlewarebackend/requirements.txt— addslowapifrontend/src/pages/AuditLogPage.vue(new)frontend/src/components/ui/SearchModal.vue(new)frontend/src/components/ui/ErrorBoundary.vue(new)frontend/src/layouts/AppLayout.vue— global keyboard shortcut handlerfrontend/src/layouts/PortalLayout.vue— mobile responsivefrontend/src/components/sidebar/PortalSidebar.vue— mobile collapsiblefrontend/src/pages/SchoolsPage.vue— bulk actions, CSV export, empty statefrontend/src/router/index.ts— /audit-logs routefrontend/src/components/sidebar/AppSidebar.vue— audit logs nav itemfrontend/src/lib/api.ts— globalSearch, getAuditLogs, exportSchoolsCsv, bulkSchoolStatus