Files
mic-check/docs/admin/01-admin-site_plan.md
James Wampler 6887d09f9c version-0.1 (#1)
Squash and merge of version-0.1

Co-authored-by: James Wampler <james@wamp.dev>
Co-committed-by: James Wampler <james@wamp.dev>
2026-07-01 13:30:07 -07:00

484 lines
20 KiB
Markdown
Executable File

# MicCheck Admin Site Plan
## Overview
Build a fully functional VueJS 3 + Vuetify 3 + TypeScript single-page admin application for the MicCheck feature flag platform. The site manages the complete lifecycle of feature flags across the Organization → Project → Environment hierarchy exposed by the MicCheck API.
---
## Architecture Decisions
- **State Management**: Pinia (replaces Vuex; first-class Vue 3 support)
- **HTTP Client**: Axios with request/response interceptors for auth token injection and 401 refresh handling
- **Component Library**: Vuetify 3 (already configured)
- **Router**: Vue Router 4 (already configured)
- **Testing**: Jest + Vue Test Utils (already configured)
- **Code Style**: Composition API (`<script setup>`), TypeScript throughout
### Context Model
The app operates in a three-level context:
1. **Organization** — selected at login/org-switcher; stored globally
2. **Project** — selected via project switcher in nav; stored globally
3. **Environment** — selected via environment dropdown in nav; stored globally
All feature, segment, identity, and audit views are scoped to the current org/project/environment context.
---
## Chunk 1: Foundation — API Client, Auth & Stores
### Goals
Set up the core infrastructure that all subsequent chunks depend on: typed API client, Pinia stores, authentication flows, and route guards.
### Tasks
#### 1.1 Install Pinia
- Add `pinia` to `package.json`
- Register Pinia in `main.ts`
#### 1.2 Typed API Client (`src/api/`)
Create an `ApiClient` class using Axios:
- Base URL configured from environment variable (`VITE_API_BASE_URL` or webpack `DefinePlugin`)
- Request interceptor: inject `Authorization: Bearer <token>` for admin calls, or `X-Environment-Key` for flags API calls
- Response interceptor: on 401, attempt token refresh via `POST /api/v1/auth/refresh`; on refresh failure, redirect to `/login`
- Typed methods for each API domain (auth, organizations, projects, environments, features, featureStates, segments, tags, auditLogs, webhooks, identities, apiKeys)
- All responses typed using TypeScript interfaces mirroring the API response models
#### 1.3 Auth Store (`src/stores/auth.ts`)
Pinia store with:
- State: `user`, `accessToken`, `refreshToken`, `expiresAt`, `isAuthenticated`
- Actions: `login(email, password)`, `register(...)`, `logout()`, `refreshToken()`, `loadFromStorage()`
- Persist tokens to `localStorage`; restore on app init
#### 1.4 Context Store (`src/stores/context.ts`)
Pinia store with:
- State: `currentOrganization`, `currentProject`, `currentEnvironment`
- Actions: `setOrganization(org)`, `setProject(project)`, `setEnvironment(env)`
- Persist selections to `localStorage`
#### 1.5 Login & Register Views
- `LoginView.vue`: email/password form → calls auth store `login()` → redirects to dashboard
- `RegisterView.vue`: email, password, first name, last name, organization name → calls `register()` → redirects to dashboard
- Both views displayed without the main `AppLayout` (full-page centered card)
- Client-side validation with Vuetify's built-in form validation
#### 1.6 Route Guards
In `router/index.ts`:
- `beforeEach` guard: if route requires auth and user is not authenticated, redirect to `/login`
- If authenticated user navigates to `/login`, redirect to `/`
- Mark public routes (`/login`, `/register`) with `meta: { public: true }`
#### 1.7 Unit Tests
- Auth store: login success, login failure, token refresh, logout
- API client: interceptors, token injection, refresh on 401
---
## Chunk 2: Navigation & Context Selectors
### Goals
Build the main app shell with a context-aware navigation bar that allows switching between organizations, projects, and environments.
### Tasks
#### 2.1 Update `AppLayout.vue`
- Left sidebar (Vuetify `v-navigation-drawer`) with:
- MicCheck logo at top
- Organization selector (dropdown showing org name)
- Project selector (dropdown scoped to selected org)
- Environment pill/tab selector (shows all environments for current project)
- Navigation links: Features, Segments, Identities, Audit Logs
- Bottom: Settings link
- Top `v-app-bar` with:
- Page title / breadcrumb
- User name and avatar icon → `/profile`
- Gear icon → `/settings`
#### 2.2 Organization Selector Component (`src/components/OrgSelector.vue`)
- Fetches `GET /api/v1/organisations` on mount
- Displays current org name as button; opens dropdown to switch
- On select: updates context store, resets project and environment selection
#### 2.3 Project Selector Component (`src/components/ProjectSelector.vue`)
- Fetches `GET /api/v1/projects?organizationId=` when org changes
- Displays current project name; opens dropdown to switch
- On select: updates context store, resets environment selection
#### 2.4 Environment Tab Bar Component (`src/components/EnvironmentTabBar.vue`)
- Fetches `GET /api/v1/environments?projectId=` when project changes
- Displays environments as tabs (Vuetify `v-tabs`)
- Highlights selected environment; updates context store on click
- "Add Environment" button at the end of the tabs
#### 2.5 Empty States
- If no organization: prompt to create one
- If no project: prompt to create first project
- If no environment: prompt to create first environment
#### 2.6 Update Router
Add routes:
```
/login → LoginView (public)
/register → RegisterView (public)
/ → DashboardView (auth required)
/features → FeaturesView (auth required)
/segments → SegmentsView (auth required)
/identities → IdentitiesView (auth required)
/audit-logs → AuditLogsView (auth required)
/settings → SettingsView (auth required)
/profile → ProfileView (auth required)
```
#### 2.7 Dashboard View
Simple landing page showing:
- Selected org/project/environment summary cards
- Quick stats: number of features, segments, enabled flags in current environment
- Links to main sections
#### 2.8 Unit Tests
- OrgSelector: loads orgs, emits selection
- ProjectSelector: loads projects on org change
- EnvironmentTabBar: loads envs, highlights selected, emits selection
- Route guard: unauthenticated redirect, authenticated bypass
---
## Chunk 3: Feature Flags Management
### Goals
Full CRUD for features (project-level) and their per-environment states (toggle on/off, set value).
### Tasks
#### 3.1 Features List View (`FeaturesView.vue`)
- Table/data-grid using Vuetify `v-data-table-server` with server-side pagination
- Columns: Name, Type (STANDARD/MULTIVARIATE), Description, Default Enabled, Created At, Actions
- Per-row toggle switch for the current environment's feature state (`PATCH /api/v1/environments/{apiKey}/featurestates/{id}`)
- Search/filter by name
- "Create Feature" button → opens dialog
#### 3.2 Feature Create/Edit Dialog (`src/components/features/FeatureDialog.vue`)
- Fields:
- **Name** (text input; validates `^[a-zA-Z0-9_-]+$`, max 150)
- **Type** (select: STANDARD / MULTIVARIATE)
- **Initial Value** (text area; shown for MULTIVARIATE; max 20,000 chars)
- **Description** (text area; optional)
- On create: `POST /api/v1/projects/{projectId}/features`
- On edit: `PUT /api/v1/projects/{projectId}/features/{id}` (name + description only)
- On save: refresh feature list
#### 3.3 Feature Detail Panel / Drawer (`src/components/features/FeatureDetail.vue`)
Slide-out `v-navigation-drawer` or dialog opened on row click:
- **Value tab**:
- Toggle enabled/disabled for current environment (`PATCH featurestates/{id}`)
- Edit value field for current environment
- Tags chip display and management
- **Settings tab**:
- Edit name and description
- `defaultEnabled` toggle (via PATCH feature)
- Danger zone: Delete feature (confirmation requiring re-type of flag name)
#### 3.4 Tags Management (`src/components/features/TagsChipInput.vue`)
- Inline chip input on feature forms
- Autocomplete from `GET /api/v1/projects/{projectId}/tags`
- Create new tag inline (label + color picker)
- `POST /api/v1/projects/{projectId}/tags` on new tag
- Delete unused tags via `DELETE /api/v1/projects/{projectId}/tags/{id}`
#### 3.5 Feature State Value Editor (`src/components/features/FeatureValueEditor.vue`)
- Detects value type (boolean/number/JSON/string) and renders appropriate input
- JSON values get a code editor (simple `v-textarea` with monospace font)
- Saves via `PUT /api/v1/environments/{apiKey}/featurestates/{id}`
#### 3.6 Unit Tests
- FeaturesView: renders list, pagination, toggle state
- FeatureDialog: validation, create call, edit call
- TagsChipInput: loads existing tags, creates new tag
- FeatureDetail: tab switching, delete confirmation
---
## Chunk 4: Segments
### Goals
Full CRUD for project-level segments with a visual rule builder, and segment-level feature state overrides per environment.
### Tasks
#### 4.1 Segments List View (`SegmentsView.vue`)
- Table: Name, Rule Count, Created At, Actions (Edit, Delete)
- "Create Segment" button → opens Segment Editor
- Delete with confirmation dialog
#### 4.2 Segment Editor Dialog (`src/components/segments/SegmentEditor.vue`)
Full-featured rule builder:
- **Name** field
- **Rules section**: List of rule groups (AND/OR type selector)
- Each rule group contains **Conditions**:
- Property (trait key, text input)
- Operator (select from: Equal, NotEqual, Contains, NotContains, Regex, GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual, IsTrue, IsFalse, In, NotIn, IsSet, IsNotSet, PercentageSplit)
- Value (text input; hidden for IsTrue/IsFalse/IsSet/IsNotSet operators; percentage slider for PercentageSplit)
- Add/remove conditions within a group
- Add/remove rule groups
- Nested child rules supported (recursive component)
- On save: `POST` or `PUT /api/v1/projects/{projectId}/segments`
- Constraint display: shows "X / 100 conditions used"
#### 4.3 Segment Overrides on Features
Within the Feature Detail drawer (Chunk 3):
- **Overrides tab**: list of segments that have overrides for this feature in current environment
- Each override shows: Segment Name, Enabled toggle, Value
- "Add Segment Override" button → select segment from dropdown → configure enabled/value
- Saves via Feature State API (`featureSegmentId` populated)
- Delete override button
#### 4.4 Unit Tests
- SegmentsView: list, delete
- SegmentEditor: rule builder add/remove conditions, add/remove groups, validation
- Segment overrides: add, remove, toggle
---
## Chunk 5: Identities
### Goals
Admin view of identities in the current environment, with the ability to view traits and override feature states per identity.
### Tasks
#### 5.1 Identities List View (`IdentitiesView.vue`)
- Server-side paginated table: Identifier, Trait Count, Created At, Actions
- Search by identifier
- Click row → Identity Detail
#### 5.2 Identity Detail View (`src/components/identities/IdentityDetail.vue`)
Slide-out panel or separate route `/identities/{id}`:
- **Traits section**:
- Table of key/value traits
- (Read-only in admin view; traits are set via SDK)
- **Feature Overrides section**:
- Table of all features with current state for this identity
- Columns: Feature Name, Environment Default, Identity Override (toggle + value), Override Active
- "Add Override" — select feature → set enabled/value → `PUT /api/v1/environments/{apiKey}/identities/{id}/featurestates/{featureId}`
- "Remove Override" → `DELETE /api/v1/environments/{apiKey}/identities/{id}/featurestates/{featureId}`
- **Danger Zone**: Delete identity (`DELETE /api/v1/environments/{apiKey}/identities/{id}`)
#### 5.3 Unit Tests
- IdentitiesView: pagination, search
- IdentityDetail: traits display, override toggle, delete identity
---
## Chunk 6: Audit Logs & Webhooks
### Goals
Read-only audit log viewer with filtering and webhook management at organization and environment level.
### Tasks
#### 6.1 Audit Logs View (`AuditLogsView.vue`)
Accessible from both org-level sidebar and within project/environment context:
- Server-side paginated table:
- Columns: Timestamp, Actor, Action, Resource Type, Resource ID, Project, Environment
- The `changes` JSON field expandable inline (show diff)
- Filters (Vuetify filter chips / inputs):
- Date range picker (start/end)
- Resource Type (multi-select: Feature, Environment, Segment, Identity, Organization, Project, ApiKey)
- Action (multi-select: Created, Updated, Deleted)
- Scoped by current context: uses org/project/environment audit-logs endpoint appropriately
#### 6.2 Webhooks Management (`src/components/settings/WebhooksPanel.vue`)
Used in both Settings view (org-level) and Environment settings:
- Table: URL (truncated), Enabled toggle, Created At, Actions
- "Add Webhook" button → Webhook Dialog
- Enabled toggle → `PUT` to update `enabled` field
- Delete with confirmation
#### 6.3 Webhook Dialog (`src/components/settings/WebhookDialog.vue`)
- Fields: URL (required), Secret (optional, masked input), Enabled (toggle)
- On create: `POST /api/v1/organisations/{id}/webhooks` or `POST /api/v1/environments/{apiKey}/webhooks`
- On edit: `PUT`
#### 6.4 Webhook Delivery History (`src/components/settings/WebhookDeliveryHistory.vue`)
- Accessible via "View Deliveries" action on each webhook row
- Table: Timestamp, Status (chip: Success/Failed/Pending), Attempt #, HTTP Response Code
- `GET /api/v1/environments/{apiKey}/webhooks/{id}/deliveries`
#### 6.5 Unit Tests
- AuditLogsView: renders data, filter by resource type, filter by date range
- WebhooksPanel: list, toggle enabled, delete
- WebhookDialog: validation, create, edit
- WebhookDeliveryHistory: renders statuses
---
## Chunk 7: Settings, Permissions & API Keys
### Goals
Organization settings, project-level user permissions, and API key management.
### Tasks
#### 7.1 Settings View (`SettingsView.vue`)
Tabbed layout:
**Tab: Organization**
- Edit organization name → `PUT /api/v1/organisations/{id}`
- Organization webhook management (reuse `WebhooksPanel` component from Chunk 6)
- Audit log link (scoped to org)
**Tab: Project**
- Edit project name and `hideDisabledFlags` toggle → `PUT /api/v1/projects/{id}`
- User Permissions table:
- Columns: User ID, Is Admin, Permissions (chips)
- "Add User" button → `POST /api/v1/projects/{id}/user-permissions`
- Edit permissions inline → `PUT /api/v1/projects/{id}/user-permissions/{userId}`
- Remove user → `DELETE /api/v1/projects/{id}/user-permissions/{userId}`
- Permission checkboxes: ViewProject, CreateFeature, EditFeature, DeleteFeature, CreateEnvironment, EditEnvironment, DeleteEnvironment, CreateSegment, EditSegment, DeleteSegment, ManageWebhooks, ViewAuditLog
**Tab: Environments**
- List of environments for current project
- Create environment: name input → `POST /api/v1/environments`
- Clone environment button → dialog asking for new name → `POST /api/v1/environments/{apiKey}/clone`
- Rename environment → `PUT /api/v1/environments/{apiKey}`
- Delete environment (with confirmation) → `DELETE`
- Environment webhook management (reuse `WebhooksPanel`)
**Tab: API Keys**
- Table: Name, Prefix (e.g. `org-key-ab`), Active, Expires At, Created At, Actions (Delete)
- "Create API Key" button → dialog:
- Name field (required)
- Expiry date picker (optional)
- `POST /api/v1/organisations/{id}/api-keys`
- On success: show `rawKey` once in a copy-to-clipboard dialog with warning "This will not be shown again"
- Delete key → `DELETE`
#### 7.2 Profile View (`ProfileView.vue`)
- Display name and email (read-only for now; no user update endpoint exists in current API)
- Logout button → calls auth store `logout()` → redirect to `/login`
- Display current organization memberships
#### 7.3 Organization Members Panel
In Organization tab:
- List members: `GET /api/v1/organisations/{id}/users` → table of userId + role
- Invite user: `POST /api/v1/organisations/{id}/users/invite` (userId + role)
- Remove member: `DELETE /api/v1/organisations/{id}/users/{userId}`
#### 7.4 Unit Tests
- API key creation: shows raw key once, copy to clipboard
- Permission editor: checkboxes update correctly, admin flag overrides individual permissions
- Environment settings: clone, rename, delete
- Profile: logout flow
---
## Shared Components & Utilities
### `src/components/common/`
- `ConfirmDialog.vue` — reusable confirm dialog (message, confirm label, danger variant)
- `PaginatedTable.vue` — wraps `v-data-table-server` with standard pagination controls
- `CopyTextField.vue` — input with copy-to-clipboard button (used for API keys, env keys)
- `StatusChip.vue` — colored chip for Success/Failed/Pending/Enabled/Disabled
- `DateRangePicker.vue` — reusable date range filter input
- `EmptyState.vue` — centered icon + message + action button for empty lists
### `src/composables/`
- `usePagination.ts` — manages page/pageSize state and server-side data fetching
- `useConfirm.ts` — returns a promise-based confirm dialog trigger
- `useNotifications.ts` — wraps Vuetify `v-snackbar` for success/error toasts
### `src/types/api.ts`
Complete TypeScript interfaces for all API response and request models.
---
## File Structure Target
```
src/admin/src/
├── api/
│ ├── client.ts # Axios instance + interceptors
│ ├── auth.ts
│ ├── organizations.ts
│ ├── projects.ts
│ ├── environments.ts
│ ├── features.ts
│ ├── featureStates.ts
│ ├── segments.ts
│ ├── tags.ts
│ ├── identities.ts
│ ├── auditLogs.ts
│ ├── webhooks.ts
│ └── apiKeys.ts
├── stores/
│ ├── auth.ts
│ └── context.ts
├── types/
│ └── api.ts
├── composables/
│ ├── usePagination.ts
│ ├── useConfirm.ts
│ └── useNotifications.ts
├── components/
│ ├── common/
│ │ ├── ConfirmDialog.vue
│ │ ├── PaginatedTable.vue
│ │ ├── CopyTextField.vue
│ │ ├── StatusChip.vue
│ │ ├── DateRangePicker.vue
│ │ └── EmptyState.vue
│ ├── nav/
│ │ ├── OrgSelector.vue
│ │ ├── ProjectSelector.vue
│ │ └── EnvironmentTabBar.vue
│ ├── features/
│ │ ├── FeatureDialog.vue
│ │ ├── FeatureDetail.vue
│ │ ├── FeatureValueEditor.vue
│ │ └── TagsChipInput.vue
│ ├── segments/
│ │ ├── SegmentEditor.vue
│ │ ├── RuleGroupEditor.vue
│ │ └── ConditionEditor.vue
│ ├── identities/
│ │ └── IdentityDetail.vue
│ └── settings/
│ ├── WebhooksPanel.vue
│ ├── WebhookDialog.vue
│ ├── WebhookDeliveryHistory.vue
│ └── PermissionsEditor.vue
├── views/
│ ├── LoginView.vue
│ ├── RegisterView.vue
│ ├── DashboardView.vue
│ ├── FeaturesView.vue
│ ├── SegmentsView.vue
│ ├── IdentitiesView.vue
│ ├── AuditLogsView.vue
│ ├── SettingsView.vue
│ └── ProfileView.vue
├── plugins/
│ └── vuetify.ts
├── router/
│ └── index.ts
├── App.vue
└── main.ts
```
---
## Build Order Summary
| Chunk | Description | Depends On |
|-------|-------------|------------|
| 1 | Foundation: API client, Auth, Pinia stores, Login/Register | — |
| 2 | Navigation, context selectors, route guards, Dashboard | Chunk 1 |
| 3 | Feature Flags (list, CRUD, env state toggles, tags) | Chunk 2 |
| 4 | Segments (list, rule builder, overrides) | Chunk 3 |
| 5 | Identities (list, detail, per-identity overrides) | Chunk 3 |
| 6 | Audit Logs & Webhooks | Chunk 2 |
| 7 | Settings, Permissions, API Keys, Profile | Chunk 2 |
Each chunk can be built and committed independently after Chunk 2 is complete.