89 lines
3.5 KiB
Markdown
89 lines
3.5 KiB
Markdown
# 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_logs` table — 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 `slowapi` middleware: `POST /auth/login` — max 10 req/min per IP
|
|
- Return `429 Too Many Requests` with Retry-After header
|
|
|
|
**HTTPS redirect**
|
|
- Add redirect middleware in `main.py` (X-Forwarded-Proto check)
|
|
- Update `nginx.conf` to 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 search
|
|
- `N` — 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 endpoints
|
|
- `backend/app/main.py` — include search + audit routers, add rate limit + HTTPS middleware
|
|
- `backend/requirements.txt` — add `slowapi`
|
|
- `frontend/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 handler
|
|
- `frontend/src/layouts/PortalLayout.vue` — mobile responsive
|
|
- `frontend/src/components/sidebar/PortalSidebar.vue` — mobile collapsible
|
|
- `frontend/src/pages/SchoolsPage.vue` — bulk actions, CSV export, empty state
|
|
- `frontend/src/router/index.ts` — /audit-logs route
|
|
- `frontend/src/components/sidebar/AppSidebar.vue` — audit logs nav item
|
|
- `frontend/src/lib/api.ts` — globalSearch, getAuditLogs, exportSchoolsCsv, bulkSchoolStatus
|