Skip to content

Commit 0bbb888

Browse files
authored
feat: add admin portal with audit dashboard, tool execution, and dev environment (#91)
* docs: regenerate swagger docs.go for audit metrics endpoints * docs: regenerate swagger.json for audit metrics endpoints * docs: regenerate swagger.yaml for audit metrics endpoints * build: add admin-ui build artifacts to .gitignore * ci: add audit metrics and admin portal packages to linter config * build: include admin-ui dist in goreleaser config * build: add admin-ui build targets and audit metrics to Makefile * deps: add squirrel query builder dependency * deps: update go.sum for squirrel dependency * feat: wire admin-ui static file serving into HTTP server * refactor: remove unused config field * fix: correct OAuth server endpoint registration * feat: add audit metrics types for timeseries, breakdown, overview, and performance * feat: implement PostgreSQL audit metrics store with squirrel query builder * test: add comprehensive tests for audit metrics store * feat: add audit metrics REST endpoints to admin handler * feat: implement audit metrics handler with timeseries, breakdown, overview, and performance * test: add tests for admin audit metrics endpoints * refactor: replace hand-built SQL with squirrel in audit postgres store * test: update audit store tests for squirrel query builder migration * refactor: replace hand-built SQL with squirrel in knowledge insight store * test: update knowledge store tests for squirrel query builder migration * refactor: replace hand-built SQL with squirrel in knowledge changeset store * test: update changeset store tests for squirrel query builder migration * refactor: add squirrel import to knowledge types * test: update knowledge toolkit tests for revised store interface * test: update migration column consistency test for squirrel auditColumns pattern * test: update audit adapter test for revised audit store interface * test: update middleware fuzz test for revised audit store interface * test: update MCP audit middleware test for revised audit store interface * feat: add Go embed handler for serving admin-ui static assets * test: add tests for admin-ui embed handler * feat: add Storybook config for admin-ui component development * feat: add Storybook config for admin-ui component development * feat: add ESLint config for admin-ui React frontend * feat: add HTML entry point for admin-ui SPA * feat: add package.json for admin-ui with React, Recharts, and TanStack Query * deps: add admin-ui package-lock.json * feat: add TypeScript config for admin-ui * feat: add Vite build config for admin-ui with API proxy * feat: add Vitest config for admin-ui unit tests * feat: add Vite client type declarations for admin-ui * feat: add base CSS styles for admin-ui dark theme * feat: add React entry point with MSW and QueryClient setup * feat: add root App component with React Router navigation * test: add smoke test for admin-ui App component * feat: add utility helpers for admin-ui * test: add Vitest setup with testing-library matchers * feat: add API client with auth header injection for admin-ui * feat: add TypeScript types for admin API responses * feat: add TanStack Query hooks for audit metrics and system info * feat: add Zustand auth store for API key management * feat: add Zustand time range store for dashboard date filtering * feat: add AppShell layout with sidebar and header slots * feat: add Header component with time range selector and auth status * feat: add Sidebar navigation component with route links * feat: add API key login form component * feat: add StatCard component for dashboard KPI display * feat: add StatusBadge component for success/error/warning indicators * feat: add TimeseriesChart component with Recharts area chart * feat: add BarChart component for audit breakdown visualization * feat: add ChartSkeleton loading placeholder for dashboard charts * feat: add dashboard page with overview stats, timeseries, and breakdown charts * feat: add audit log page with filterable event table and detail view * feat: add MSW service worker for admin-ui API mocking * feat: add MSW browser worker setup for development mode * feat: add MSW server setup for admin-ui unit tests * feat: add MSW request handlers for admin API mock endpoints * feat: add mock audit metrics data for development and testing * feat: add mock system info data for development and testing * feat: replace mock system data with ACME Corporation retail platform 20 tools across 6 connections (2 Trino, 2 DataHub, 2 S3), all features enabled including OAuth, 6 toolkits and 6 personas. * feat: replace mock audit data with ACME Corporation retail events Seeded PRNG (mulberry32) for deterministic screenshots, 12 weighted users, 19 tool definitions with realistic parameters and error messages, business-hours timestamp distribution, 200 events, and breakdown arrays for persona, connection, and toolkit dimensions. * feat: add persona, connection, and toolkit breakdown endpoints to MSW handlers * fix: auto-authenticate in MSW mode and fix service worker registration Skip login screen when VITE_MSW=true, register service worker from root path so it can intercept /api/* requests outside /admin/ scope, and render the app even if MSW startup fails. * fix: serve MSW service worker from root to cover /api/* scope Vite plugin serves mockServiceWorker.js at / so the service worker can intercept API requests that fall outside the /admin/ base path. * fix: snap time range timestamps to the minute for stable query keys Date.now() produced a new string every render, causing React Query to treat each render as a new query and never settle to loaded state. * feat: rename sidebar title from MCP Admin to MCP Platform * feat: update page title to MCP Platform * feat: add dark theme CSS variables Standard shadcn/ui dark palette applied via .dark class on html root. * feat: add theme store with system preference detection Defaults to system theme, persists choice to localStorage, and listens for OS-level theme changes. Guards against missing matchMedia/localStorage in test environments. * feat: add light/dark/system theme toggle to header Three-button toggle using Sun, Moon, and Monitor icons from lucide-react, positioned next to the time range selector. * test: update assertion to match MCP Platform rename * feat: add PostgreSQL dev compose for ACME local environment * feat: add ACME seed data with 5000 audit events and knowledge insights Business-hours weighted timestamps over 7 days, consistent user and tool distributions, 8 knowledge insights in various review states, and 2 changesets (1 applied, 1 rolled back). * feat: add ACME platform config with 6 personas and dev API key Configures admin, data-engineer, inventory-analyst, regional-director, finance-executive, and store-manager personas with appropriate tool access. Audit and knowledge features enabled, noop providers. * feat: add dev-up and dev-down Makefile targets for ACME environment * docs: add ACME local dev environment quick-start guide * feat: add admin portal UI enhancements and tool execution endpoints - Add GET /tools/schemas and POST /tools/call backend endpoints for executing MCP tools from the admin UI via in-memory transport - Remove Settings section from admin portal (deferred for redesign) - Make sidebar title configurable via admin.portal_title config - Add Home, Knowledge, Personas, and Tools pages with mock data - Enhance dashboard and audit log pages with richer UI components - Fix cyclomatic complexity in Breakdown and ListChangesets functions - Replace acme-corp.com with example.com in dev seed data * fix: commit admin-ui dist/.gitkeep so go:embed compiles in CI The //go:embed all:dist directive requires the dist directory to exist. The top-level dist/ gitignore pattern was blocking the .gitkeep from being tracked. Scope the pattern to /dist/ (root only) so the negation rule for internal/adminui/dist/.gitkeep takes effect.
1 parent d696e7b commit 0bbb888

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+23830
-427
lines changed

.gitignore

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ settings.local.json
4040
site/
4141

4242
# Build artifacts
43-
dist/
43+
/dist/
4444
build/
4545
/mcp-data-platform
4646
NOTES_*
@@ -54,3 +54,9 @@ codeql-results.sarif
5454

5555
# MCP Apps test host
5656
ext-apps/
57+
58+
# Admin UI
59+
admin-ui/node_modules/
60+
admin-ui/dist/
61+
internal/adminui/dist/*
62+
!internal/adminui/dist/.gitkeep

.golangci.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,35 @@ linters:
326326
- revive
327327
text: "cognitive-complexity|cyclomatic"
328328

329+
# Test files use literal values for fixtures — extracting constants hurts readability
330+
- path: _test\.go
331+
linters:
332+
- revive
333+
text: "add-constant"
334+
335+
# DTO/types packages naturally exceed 5 public structs — their job is to define types
336+
- path: pkg/audit/
337+
linters:
338+
- revive
339+
text: "max-public-structs"
340+
- path: pkg/admin/
341+
linters:
342+
- revive
343+
text: "max-public-structs"
344+
- path: pkg/oauth/
345+
linters:
346+
- revive
347+
text: "max-public-structs"
348+
- path: pkg/platform/config\.go
349+
linters:
350+
- revive
351+
text: "max-public-structs"
352+
- path: pkg/toolkits/knowledge/types\.go
353+
linters:
354+
- revive
355+
text: "max-public-structs"
356+
357+
329358
issues:
330359
max-issues-per-linter: 50
331360
max-same-issues: 10

.goreleaser.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ before:
1212
hooks:
1313
- go mod download
1414
- go mod verify
15+
- bash -c "if [ -f admin-ui/package.json ]; then cd admin-ui && npm ci && npm run build && rm -rf ../internal/adminui/dist/* && cp -r dist/* ../internal/adminui/dist/; fi"
1516

1617
builds:
1718
- id: mcp-data-platform

Makefile

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ LDFLAGS := -ldflags "-X github.com/txn2/mcp-data-platform/internal/server.Versio
1111
CMD_DIR := ./cmd/mcp-data-platform
1212
BUILD_DIR := ./build
1313
DIST_DIR := ./dist
14+
ADMIN_UI_DIR := ./admin-ui
15+
ADMIN_UI_EMBED_DIR := ./internal/adminui/dist
1416

1517
# Tool versions — keep in sync with .github/workflows/ci.yml
1618
GOLANGCI_LINT_VERSION := v2.8.0
@@ -27,7 +29,9 @@ GOLINT := golangci-lint
2729
.PHONY: all build test lint fmt clean install help docs-serve docs-build verify \
2830
tools-check dead-code mutate patch-coverage doc-check swagger swagger-check \
2931
semgrep codeql sast \
30-
e2e-up e2e-down e2e-seed e2e-test e2e e2e-logs e2e-clean
32+
frontend-install frontend-build frontend-dev frontend-test frontend-storybook \
33+
e2e-up e2e-down e2e-seed e2e-test e2e e2e-logs e2e-clean \
34+
dev-up dev-down
3135

3236
## all: Build and test
3337
all: build test lint
@@ -86,6 +90,9 @@ clean:
8690
@echo "Cleaning..."
8791
@rm -rf $(BUILD_DIR) $(DIST_DIR)
8892
@rm -f coverage.out coverage.html
93+
@rm -rf $(ADMIN_UI_DIR)/dist $(ADMIN_UI_DIR)/node_modules
94+
@# Reset embed dir but keep .gitkeep
95+
@find $(ADMIN_UI_EMBED_DIR) -not -name '.gitkeep' -not -path $(ADMIN_UI_EMBED_DIR) -delete 2>/dev/null || true
8996
@echo "Clean complete."
9097

9198
## install: Install the binary
@@ -269,6 +276,40 @@ help:
269276
@echo "Targets:"
270277
@grep -E '^## ' $(MAKEFILE_LIST) | sed 's/## / /'
271278

279+
# =============================================================================
280+
# Admin UI Frontend Targets
281+
# =============================================================================
282+
283+
## frontend-install: Install admin UI dependencies
284+
frontend-install:
285+
@echo "Installing admin UI dependencies..."
286+
cd $(ADMIN_UI_DIR) && npm ci
287+
@echo "Admin UI dependencies installed."
288+
289+
## frontend-build: Build admin UI and copy to embed directory
290+
frontend-build: frontend-install
291+
@echo "Building admin UI..."
292+
cd $(ADMIN_UI_DIR) && npm run build
293+
@echo "Copying dist to embed directory..."
294+
@rm -rf $(ADMIN_UI_EMBED_DIR)/*
295+
@cp -r $(ADMIN_UI_DIR)/dist/* $(ADMIN_UI_EMBED_DIR)/
296+
@echo "Admin UI built and embedded."
297+
298+
## frontend-dev: Run admin UI dev server (hot reload)
299+
frontend-dev:
300+
cd $(ADMIN_UI_DIR) && npm run dev
301+
302+
## frontend-test: Run admin UI tests
303+
frontend-test:
304+
cd $(ADMIN_UI_DIR) && npm run test
305+
306+
## frontend-storybook: Run Storybook for component development
307+
frontend-storybook:
308+
cd $(ADMIN_UI_DIR) && npm run storybook
309+
310+
## build-with-ui: Build Go binary with embedded admin UI
311+
build-with-ui: frontend-build build
312+
272313
# =============================================================================
273314
# E2E Testing Targets
274315
# =============================================================================
@@ -334,3 +375,46 @@ e2e-clean: e2e-down
334375
@echo "Cleaning E2E artifacts..."
335376
@docker volume rm -f mcp-data-platform_postgres_data mcp-data-platform_minio_data 2>/dev/null || true
336377
@echo "E2E cleanup complete."
378+
379+
# =============================================================================
380+
# Local Dev Environment (ACME Corporation)
381+
# =============================================================================
382+
383+
DEV_COMPOSE := docker compose -f dev/docker-compose.yml
384+
385+
## dev-up: Start ACME dev environment (PostgreSQL)
386+
dev-up:
387+
@echo "Starting ACME dev environment..."
388+
$(DEV_COMPOSE) up -d
389+
@echo "Waiting for PostgreSQL to be healthy..."
390+
@for i in 1 2 3 4 5 6 7 8 9 10; do \
391+
if docker exec acme-dev-postgres pg_isready -U platform -d mcp_platform -q 2>/dev/null; then \
392+
echo "PostgreSQL is ready."; \
393+
break; \
394+
fi; \
395+
if [ $$i -eq 10 ]; then echo "ERROR: PostgreSQL failed to start"; exit 1; fi; \
396+
sleep 1; \
397+
done
398+
@echo ""
399+
@echo "=== ACME Dev Environment Ready ==="
400+
@echo ""
401+
@echo "Start the Go server:"
402+
@echo " go run ./cmd/mcp-data-platform --config dev/platform.yaml"
403+
@echo ""
404+
@echo "(Optional) Seed historical data:"
405+
@echo " psql -h localhost -U platform -d mcp_platform -f dev/seed.sql"
406+
@echo ""
407+
@echo "Start the admin UI:"
408+
@echo " cd admin-ui && npm run dev"
409+
@echo ""
410+
@echo "Or use MSW mode (no backend needed):"
411+
@echo " cd admin-ui && VITE_MSW=true npm run dev"
412+
@echo ""
413+
@echo "API Key: acme-dev-key-2024"
414+
@echo ""
415+
416+
## dev-down: Stop ACME dev environment and remove volumes
417+
dev-down:
418+
@echo "Stopping ACME dev environment..."
419+
$(DEV_COMPOSE) down -v
420+
@echo "ACME dev environment stopped."

admin-ui/.storybook/main.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { StorybookConfig } from "@storybook/react-vite";
2+
3+
const config: StorybookConfig = {
4+
stories: ["../src/**/*.stories.@(ts|tsx)"],
5+
addons: ["@storybook/addon-essentials"],
6+
framework: {
7+
name: "@storybook/react-vite",
8+
options: {},
9+
},
10+
};
11+
12+
export default config;

admin-ui/.storybook/preview.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { Preview } from "@storybook/react";
2+
import "../src/index.css";
3+
4+
const preview: Preview = {
5+
parameters: {
6+
controls: {
7+
matchers: {
8+
color: /(background|color)$/i,
9+
date: /Date$/i,
10+
},
11+
},
12+
},
13+
};
14+
15+
export default preview;

admin-ui/eslint.config.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import js from "@eslint/js";
2+
import globals from "globals";
3+
import reactHooks from "eslint-plugin-react-hooks";
4+
import tseslint from "typescript-eslint";
5+
6+
export default tseslint.config(
7+
{ ignores: ["dist"] },
8+
{
9+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
10+
files: ["**/*.{ts,tsx}"],
11+
languageOptions: {
12+
ecmaVersion: 2020,
13+
globals: globals.browser,
14+
},
15+
plugins: {
16+
"react-hooks": reactHooks,
17+
},
18+
rules: {
19+
...reactHooks.configs.recommended.rules,
20+
},
21+
}
22+
);

admin-ui/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>MCP Platform</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="/src/main.tsx"></script>
11+
</body>
12+
</html>

0 commit comments

Comments
 (0)