Admin panel for Guard Proxy WAF. React 18 + TypeScript + Vite + Tailwind CSS v4.
pnpm install
pnpm run dev # dev server on http://localhost:5173
pnpm run build # production build
pnpm run type-check # TypeScript compiler check
pnpm run lint # ESLintBackend must be running at http://127.0.0.1:8000 (requests to /api/v1 are proxied to this target).
Copy .env.example to .env if you need to change the proxy target via VITE_DEV_SERVER_PROXY_TARGET.
- pnpm — package manager (no npm/yarn)
- React 18 + TypeScript (strict)
- Vite 6 — bundler
- Tailwind CSS v4 — styling (via
@tailwindcss/vite) - React Router v6 — client-side routing
- Custom design system with CSS custom properties and oklch color tokens
src/
main.tsx # entry point
app/
App.tsx # root component
router.tsx # all routes
providers.tsx # context providers
pages/ # one folder per route
login/LoginPage.tsx
dashboard/DashboardPage.tsx
vhosts/VHostsPage.tsx
vhosts/VHostDetailPage.tsx
policies/PoliciesPage.tsx
forbidden/ForbiddenPage.tsx
layouts/
AppLayout.tsx # topbar + content area
components/
layout/NavBar.tsx # top navigation bar
shared/ # reusable UI components
PageHeader.tsx
SectionCard.tsx
StatCard.tsx
StatusBadge.tsx
RoleBadge.tsx
EmptyState.tsx
LoadingState.tsx
ErrorState.tsx
PagePlaceholder.tsx
features/
auth/ # auth context, login API, token storage
hooks/
use-auth.ts # hook for auth context
lib/
api-client.ts # shared API client (apiRequest + ApiError)
types/
api.ts # shared API types (CurrentUser, TokenResponse, etc.)
styles/
globals.css # design tokens, themes, base styles
All requests go through apiRequest() in lib/api-client.ts:
import { apiRequest } from "@/lib/api-client";
const data = await apiRequest<MyType>("/endpoint", { method: "GET", token });Errors throw ApiError with .status and .detail.
Auth state lives in features/auth/auth-context.tsx. Access via the useAuth() hook:
import { useAuth } from "@/hooks/use-auth";
const { user, isAuthenticated, signIn, signOut, hasRole } = useAuth();ProtectedRoute— redirects unauthenticated users to/loginPublicOnlyRoute— redirects authenticated users to/dashboardRoleRoute— restricts by role (exported but not yet wired)
Build new screens using existing shared components in components/shared/:
PageHeader— page title with eyebrow label and action buttonsSectionCard— card with title, description, icon, and childrenStatCard— metric card with label, value, tone, and iconStatusBadge— colored pill badge (success/warning/error/info/neutral)RoleBadge— badge showing user roleEmptyState,LoadingState,ErrorState— standard state placeholdersPagePlaceholder— full placeholder page for routes not yet built
Colors and radii are CSS custom properties defined in styles/globals.css.
Two themes: emerald (default, green) and frost (blue). Use the token names
in Tailwind classes (e.g. text-fg, bg-surface, text-accent, border-border).
Inline SVG components defined alongside the components that use them. No external icon library.
| Method | Endpoint | Auth |
|---|---|---|
POST |
/auth/login |
public |
POST |
/auth/refresh |
token |
GET |
/auth/me |
token |
GET/POST |
/vhosts |
token (write = admin) |
GET/PATCH/DELETE |
/vhosts/{id} |
token (write = admin) |
GET/POST |
/policies |
token (write = admin) |
GET/PATCH/DELETE |
/policies/{id} |
token (write = admin) |
GET |
/health |
public |
Swagger docs: http://127.0.0.1:8000/docs
styles/globals.cssdesign tokens and theme systemfeatures/auth/auth context architecturelib/api-client.tsshared API clientapp/router.tsxroute structurecomponents/layout/NavBar.tsxnavigation
Dashboard currently shows hardcoded placeholder data. Replace with real API calls when the corresponding endpoints are ready.