`, no padding.
Tab components currently live at depth frontend/src/components/admin/ (two levels deep from src/). Extracted views live at frontend/src/views/admin/ (also two levels deep). Therefore relative imports of the form ../../api/..., ../../stores/..., ../../utils/... resolve identically from the new location — no relative import paths need adjustment. Any imports that go through ../layout/... (one level up to components/) would break, but these tab components do NOT import any sibling component under components/.
Verify before extracting each file: grep -E "^import" frontend/src/components/admin/<TabFile>.vue — every import path should already start with ../../ (relative to components/admin/). If any import uses a different depth, document the rewrite in the SUMMARY.
Task 1: Extract AdminUsersTab.vue and AdminQuotasTab.vue to views/admin/
frontend/src/views/admin/AdminUsersView.vue, frontend/src/views/admin/AdminQuotasView.vue
- frontend/src/components/admin/AdminUsersTab.vue (entire file — this is the source being promoted)
- frontend/src/components/admin/AdminQuotasTab.vue (entire file — this is the source being promoted)
- frontend/src/views/AdminView.vue (current parent — confirm which props/events these tab components rely on so the standalone views can drop the prop-passing layer)
- `AdminUsersView.vue` template + script behave identically to `AdminUsersTab.vue` for the user CRUD flows (create user, deactivate user, set quota, set AI provider, etc.).
- `AdminQuotasView.vue` template + script behave identically to `AdminQuotasTab.vue` for the quota management flows.
- Both files compile under Vite with no warnings about unused imports or unresolved paths.
- No prop is required to mount either view (AdminLayout passes nothing to its children).
Copy the entire contents of `frontend/src/components/admin/AdminUsersTab.vue` into a new file `frontend/src/views/admin/AdminUsersView.vue`. Rename the component if the script defines a `name:` field (Options-API style) or sets `defineOptions({ name: 'AdminUsersTab' })` (Composition-API) — change `'AdminUsersTab'` to `'AdminUsersView'`. If neither convention is used, no rename is needed. Verify every import line resolves from the new path (use the rule in ``: `../../` resolves identically). If `AdminUsersTab.vue` declares props that were used to receive data from `AdminView.vue` and they are no longer relevant (e.g. a `currentUser` prop), remove the `defineProps` block AND audit where those props were referenced — if a prop was only used as a passthrough, replace its template references with direct store reads (`useAuthStore().user`). Do NOT change template DOM, do NOT change `onMounted` fetches, do NOT change emitted events (emitted events are dropped at the view boundary — they no longer have a parent listening; check whether any emit was the sole trigger of a fetch on the parent — if so, replace the emit with a direct re-fetch inside the view). Repeat the same extraction for `AdminQuotasTab.vue` → `frontend/src/views/admin/AdminQuotasView.vue`.
cd frontend && [ -f src/views/admin/AdminUsersView.vue ] && [ -f src/views/admin/AdminQuotasView.vue ] && diff <(sed -n '//,/<\/template>/p' src/components/admin/AdminUsersTab.vue | wc -l) <(sed -n '//,/<\/template>/p' src/views/admin/AdminUsersView.vue | wc -l) && npm run build 2>&1 | grep -E "AdminUsersView|AdminQuotasView" | grep -i error | wc -l
- `frontend/src/views/admin/AdminUsersView.vue` exists.
- `frontend/src/views/admin/AdminQuotasView.vue` exists.
- First non-comment template element of each is `
` (no `p-8`, `p-6`, `max-w-` class on the root).
- Line count of each new view is within ±10% of its source tab (no large unintended changes).
- `cd frontend && npm run build` succeeds with no Vite errors referencing the new view files.
- `grep -E "defineProps|props:" frontend/src/views/admin/AdminUsersView.vue` either returns no match OR every declared prop is also USED inside the template (no dead prop declarations).
- Same check for `AdminQuotasView.vue`.
- All existing API client calls in the source files appear identically in the new files (`grep -E "from '../../api/" frontend/src/views/admin/AdminUsersView.vue` returns the same count as the source).
AdminUsersView and AdminQuotasView are standalone views that build cleanly; behavior preserved; no top-level padding.
Task 2: Extract AdminAiConfigTab.vue and AuditLogTab.vue to views/admin/
frontend/src/views/admin/AdminAiView.vue, frontend/src/views/admin/AdminAuditView.vue
- frontend/src/components/admin/AdminAiConfigTab.vue (entire file)
- frontend/src/components/admin/AuditLogTab.vue (entire file — D-13: promote as-is, no feature changes)
- frontend/src/views/AdminView.vue (confirm prop-passing pattern)
- `AdminAiView.vue` template + script behave identically to `AdminAiConfigTab.vue` for the AI provider configuration flows (global system AI providers section + per-user AI assignment table, both preserved exactly per Phase 7 plan-05 pitfall 6).
- `AdminAuditView.vue` template + script behave identically to `AuditLogTab.vue` for the audit log view: filter bar, paginated table, CSV download, daily-export list (all Phase 6.2 features preserved exactly).
- Both files compile under Vite with no warnings.
- Dynamic color classes used in `AuditLogTab.vue` (`bg-blue-50 text-blue-600`, `bg-purple-50 text-purple-600`, `bg-amber-50 text-amber-700`, `bg-gray-100 text-gray-600`) continue to be generated via the same `actionTypeClass()` helper in the new view — DO NOT inline these classes or hardcode them.
Copy `frontend/src/components/admin/AdminAiConfigTab.vue` to `frontend/src/views/admin/AdminAiView.vue`. Apply the same rules as Task 1: rename component name if explicit, drop dead `defineProps`, replace orphaned `emit` calls with direct re-fetch where the emit was the only refresh trigger. Note: the cross-cutting constraint from Phase 7 (AdminAiConfigTab.vue per-user assignment table is preserved untouched; global system section is ABOVE it) must remain — do not reorder sections. Copy `frontend/src/components/admin/AuditLogTab.vue` to `frontend/src/views/admin/AdminAuditView.vue`. D-13 mandates **as-is** promotion — no new features, no template tweaks. The `actionTypeClass()` function MUST be preserved verbatim (its `bg-amber-50 text-amber-700` etc. drive the safelist requirement closed in 09-04). Verify the import paths still resolve from `views/admin/` (the depth is unchanged from `components/admin/`).
cd frontend && [ -f src/views/admin/AdminAiView.vue ] && [ -f src/views/admin/AdminAuditView.vue ] && grep -c "actionTypeClass" src/views/admin/AdminAuditView.vue && npm run build 2>&1 | grep -E "AdminAiView|AdminAuditView" | grep -i error | wc -l
- `frontend/src/views/admin/AdminAiView.vue` exists.
- `frontend/src/views/admin/AdminAuditView.vue` exists.
- First non-comment template element of each is `
` (no top-level padding).
- `grep -c "actionTypeClass" frontend/src/views/admin/AdminAuditView.vue` returns at least 1 (helper preserved).
- `grep -c "bg-amber-50" frontend/src/views/admin/AdminAuditView.vue` returns at least 1 (D-13 as-is preservation).
- `grep -c "bg-purple-50" frontend/src/views/admin/AdminAuditView.vue` returns at least 1.
- `grep -c "System AI" frontend/src/views/admin/AdminAiView.vue` returns at least 1 (global system section title preserved from Phase 7).
- `cd frontend && npm run build` succeeds.
- Line counts within ±10% of source tab components.
AdminAiView + AdminAuditView are standalone, build cleanly, preserve all Phase 6.2/7 behavior; dynamic color classes still produced through `actionTypeClass()`.
<threat_model>
Trust Boundaries
| Boundary |
Description |
| (none new) |
Behavior-preserving extraction; no new ingress, egress, or trust transitions |
STRIDE Threat Register
| Threat ID |
Category |
Component |
Disposition |
Mitigation Plan |
| T-09-03-01 |
Tampering |
Tab-to-view extraction |
mitigate |
Verbatim copy of template + script preserves behavior; line-count check ±10% catches accidental edits; npm run build catches resolution errors |
| T-09-03-02 |
Information Disclosure |
Orphaned emit handlers |
mitigate |
Action step audits every emit(...) for orphaned parent listeners and replaces them with direct re-fetches so no admin action silently no-ops (e.g., user creation modal closing without triggering list refresh) |
| </threat_model> |
|
|
|
|
- `cd frontend && npm run build` → succeeds.
- All four new view files exist under `frontend/src/views/admin/`.
- Each view's first template element is `
` with no top-level padding class.
- Original tab components in `frontend/src/components/admin/` are untouched (deletion happens in 09-04).
<success_criteria>
- ADMIN-08: Four standalone admin view files exist under
frontend/src/views/admin/.
- ADMIN-10: Each view is a self-contained component that the router can mount as a child of
/admin (router wiring lands in 09-04).
- Behavior preserved: every admin CRUD/filter/download interaction continues to work after wiring in 09-04.
</success_criteria>
Create `.planning/phases/09-admin-panel-rearchitecture/09-03-SUMMARY.md` when done. List the four new files, any dead-prop removals, and any orphaned-emit-to-fetch replacements made during extraction.