20 KiB
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:
- Organization — selected at login/org-switcher; stored globally
- Project — selected via project switcher in nav; stored globally
- 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
piniatopackage.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_URLor webpackDefinePlugin) - Request interceptor: inject
Authorization: Bearer <token>for admin calls, orX-Environment-Keyfor 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 storelogin()→ redirects to dashboardRegisterView.vue: email, password, first name, last name, organization name → callsregister()→ 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:
beforeEachguard: 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) withmeta: { 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-barwith:- 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/organisationson 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-serverwith 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)
- Name (text input; validates
- 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
- Toggle enabled/disabled for current environment (
- Settings tab:
- Edit name and description
defaultEnabledtoggle (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}/tagson 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-textareawith 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)
- Each rule group contains Conditions:
- On save:
POSTorPUT /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 (
featureSegmentIdpopulated) - 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
changesJSON 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 →
PUTto updateenabledfield - 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}/webhooksorPOST /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
WebhooksPanelcomponent from Chunk 6) - Audit log link (scoped to org)
Tab: Project
- Edit project name and
hideDisabledFlagstoggle →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
rawKeyonce 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— wrapsv-data-table-serverwith standard pagination controlsCopyTextField.vue— input with copy-to-clipboard button (used for API keys, env keys)StatusChip.vue— colored chip for Success/Failed/Pending/Enabled/DisabledDateRangePicker.vue— reusable date range filter inputEmptyState.vue— centered icon + message + action button for empty lists
src/composables/
usePagination.ts— manages page/pageSize state and server-side data fetchinguseConfirm.ts— returns a promise-based confirm dialog triggeruseNotifications.ts— wraps Vuetifyv-snackbarfor 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.