2025-12-22 14:09:32 +01:00
|
|
|
# CLAUDE.md — LetsBe Hub
|
|
|
|
|
|
|
|
|
|
## Purpose
|
|
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
You are the engineering assistant for the LetsBe Hub Dashboard.
|
|
|
|
|
This is the admin dashboard and API for managing the LetsBe Cloud platform.
|
2025-12-22 14:09:32 +01:00
|
|
|
|
|
|
|
|
The Hub provides:
|
|
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
- **Admin Dashboard**: Next.js admin UI for platform management
|
|
|
|
|
- **Customer Management**: Create/manage customers and subscriptions
|
|
|
|
|
- **Order Management**: Process and track provisioning orders
|
|
|
|
|
- **Server Monitoring**: View and manage tenant servers
|
2026-01-17 12:33:11 +01:00
|
|
|
- **Netcup Integration**: Full server management via Netcup SCP API
|
2026-01-06 12:35:01 +01:00
|
|
|
- **Token Usage Tracking**: Monitor AI token consumption
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
## Tech Stack
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
- **Next.js 15** (App Router)
|
|
|
|
|
- **TypeScript** (strict mode)
|
|
|
|
|
- **Prisma** (PostgreSQL ORM)
|
|
|
|
|
- **TanStack Query** (React Query v5)
|
|
|
|
|
- **Tailwind CSS** + shadcn/ui components
|
|
|
|
|
- **NextAuth.js** (authentication)
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
## Project Structure
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
```
|
|
|
|
|
src/
|
|
|
|
|
├── app/ # Next.js App Router
|
|
|
|
|
│ ├── admin/ # Admin dashboard pages
|
|
|
|
|
│ │ ├── customers/ # Customer management
|
2026-01-17 12:33:11 +01:00
|
|
|
│ │ │ └── [id]/ # Customer detail with order creation
|
2026-01-06 12:35:01 +01:00
|
|
|
│ │ ├── orders/ # Order management
|
2026-01-17 12:33:11 +01:00
|
|
|
│ │ │ └── [id]/ # Order detail with DNS, provisioning
|
2026-01-06 12:35:01 +01:00
|
|
|
│ │ ├── servers/ # Server monitoring
|
2026-01-17 12:33:11 +01:00
|
|
|
│ │ │ └── netcup/ # Netcup servers management
|
|
|
|
|
│ │ │ └── [id]/ # Netcup server detail
|
|
|
|
|
│ │ ├── settings/ # Admin settings
|
2026-01-06 12:35:01 +01:00
|
|
|
│ │ └── layout.tsx # Admin layout with sidebar
|
|
|
|
|
│ ├── api/v1/ # API routes
|
|
|
|
|
│ │ ├── admin/ # Admin API endpoints
|
2026-01-17 12:33:11 +01:00
|
|
|
│ │ │ ├── customers/ # Customer CRUD
|
|
|
|
|
│ │ │ ├── orders/ # Order CRUD + provisioning
|
|
|
|
|
│ │ │ ├── netcup/ # Netcup SCP API integration
|
|
|
|
|
│ │ │ └── servers/ # Server management
|
2026-01-06 12:35:01 +01:00
|
|
|
│ │ └── public/ # Public API endpoints
|
|
|
|
|
│ └── (auth)/ # Authentication pages
|
|
|
|
|
├── components/
|
|
|
|
|
│ ├── admin/ # Admin-specific components
|
2026-01-17 12:33:11 +01:00
|
|
|
│ │ ├── create-order-dialog.tsx # Order creation wizard
|
|
|
|
|
│ │ ├── netcup-auth-setup.tsx # Netcup OAuth setup
|
|
|
|
|
│ │ ├── netcup-server-link.tsx # Link orders to Netcup servers
|
|
|
|
|
│ │ └── dns-verification-panel.tsx # DNS verification UI
|
|
|
|
|
│ └── ui/ # Reusable UI components (shadcn/ui)
|
2026-01-06 12:35:01 +01:00
|
|
|
├── hooks/ # React Query hooks
|
2026-01-17 12:33:11 +01:00
|
|
|
│ ├── use-customers.ts # Customer data hooks
|
|
|
|
|
│ ├── use-orders.ts # Order data hooks
|
|
|
|
|
│ ├── use-netcup.ts # Netcup API hooks
|
|
|
|
|
│ └── use-dns.ts # DNS verification hooks
|
2026-01-06 12:35:01 +01:00
|
|
|
├── lib/ # Utilities and shared code
|
2026-01-17 12:33:11 +01:00
|
|
|
│ ├── prisma.ts # Prisma client singleton
|
|
|
|
|
│ └── services/ # Backend services
|
|
|
|
|
│ ├── netcup-service.ts # Netcup SCP API client
|
|
|
|
|
│ ├── dns-service.ts # DNS verification service
|
|
|
|
|
│ └── settings-service.ts # System settings storage
|
2026-01-06 12:35:01 +01:00
|
|
|
└── types/ # TypeScript type definitions
|
|
|
|
|
```
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
## API Routes
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
### Admin Endpoints (authenticated)
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
```
|
|
|
|
|
# Customers
|
|
|
|
|
GET /api/v1/admin/customers # List customers
|
|
|
|
|
GET /api/v1/admin/customers/[id] # Get customer detail
|
|
|
|
|
PATCH /api/v1/admin/customers/[id] # Update customer
|
|
|
|
|
|
|
|
|
|
# Orders
|
|
|
|
|
GET /api/v1/admin/orders # List orders
|
|
|
|
|
POST /api/v1/admin/orders # Create order
|
|
|
|
|
GET /api/v1/admin/orders/[id] # Get order detail
|
|
|
|
|
PATCH /api/v1/admin/orders/[id] # Update order
|
|
|
|
|
GET /api/v1/admin/orders/[id]/logs # Get provisioning logs (SSE)
|
2026-01-17 12:33:11 +01:00
|
|
|
POST /api/v1/admin/orders/[id]/provision # Start provisioning
|
|
|
|
|
|
|
|
|
|
# DNS Verification
|
|
|
|
|
GET /api/v1/admin/orders/[id]/dns # Get DNS status
|
|
|
|
|
POST /api/v1/admin/orders/[id]/dns/verify # Trigger DNS verification
|
|
|
|
|
POST /api/v1/admin/orders/[id]/dns/skip # Manual DNS override
|
2026-01-06 12:35:01 +01:00
|
|
|
|
|
|
|
|
# Servers
|
|
|
|
|
GET /api/v1/admin/servers # List servers (derived from orders)
|
|
|
|
|
|
2026-01-17 12:33:11 +01:00
|
|
|
# Netcup Integration
|
|
|
|
|
GET /api/v1/admin/netcup/auth # Get auth status / poll for token
|
|
|
|
|
POST /api/v1/admin/netcup/auth # Initiate device auth flow
|
|
|
|
|
DELETE /api/v1/admin/netcup/auth # Disconnect Netcup account
|
|
|
|
|
GET /api/v1/admin/netcup/servers # List all Netcup servers
|
|
|
|
|
GET /api/v1/admin/netcup/servers/[id] # Get server detail
|
|
|
|
|
POST /api/v1/admin/netcup/servers/[id]/power # Power actions
|
|
|
|
|
POST /api/v1/admin/netcup/servers/[id]/rescue # Rescue mode
|
|
|
|
|
GET /api/v1/admin/netcup/servers/[id]/metrics # Performance metrics
|
|
|
|
|
GET /api/v1/admin/netcup/servers/[id]/snapshots # List snapshots
|
|
|
|
|
POST /api/v1/admin/netcup/servers/[id]/snapshots # Create snapshot
|
|
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
# Dashboard
|
|
|
|
|
GET /api/v1/admin/dashboard/stats # Dashboard statistics
|
|
|
|
|
```
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-17 12:33:11 +01:00
|
|
|
## Netcup SCP Integration
|
|
|
|
|
|
|
|
|
|
The Hub integrates with Netcup's Server Control Panel API for full server management.
|
|
|
|
|
|
|
|
|
|
### Authentication
|
|
|
|
|
Uses OAuth2 Device Flow:
|
|
|
|
|
1. Hub initiates device auth, gets `user_code` and `verification_uri`
|
|
|
|
|
2. User visits Netcup and enters the code
|
|
|
|
|
3. Hub polls for token exchange
|
|
|
|
|
4. Tokens stored in `SystemSettings` table
|
|
|
|
|
5. Access tokens auto-refresh (5min expiry, offline refresh token)
|
|
|
|
|
|
|
|
|
|
### Capabilities
|
|
|
|
|
- **Server List**: View all Netcup servers with live status
|
|
|
|
|
- **Power Control**: ON/OFF/POWERCYCLE/RESET/POWEROFF
|
|
|
|
|
- **Rescue Mode**: Activate/deactivate rescue system
|
|
|
|
|
- **Metrics**: CPU, disk I/O, network throughput (up to 30 days)
|
|
|
|
|
- **Snapshots**: Create, list, delete, revert snapshots
|
|
|
|
|
- **Server Linking**: Link orders to Netcup servers by IP
|
|
|
|
|
|
|
|
|
|
### Key Service: `netcup-service.ts`
|
|
|
|
|
```typescript
|
|
|
|
|
// Core methods
|
|
|
|
|
netcupService.initiateDeviceAuth() // Start OAuth flow
|
|
|
|
|
netcupService.pollForToken(deviceCode) // Complete OAuth
|
|
|
|
|
netcupService.getServers() // List with IPs from interfaces
|
|
|
|
|
netcupService.getServer(id, liveInfo) // Detail with live status
|
|
|
|
|
netcupService.powerAction(id, action) // Power control
|
|
|
|
|
netcupService.getServerInterfaces(id) // Get IP addresses
|
|
|
|
|
netcupService.getAllMetrics(id, hours) // CPU/disk/network metrics
|
|
|
|
|
```
|
|
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
## Development Commands
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
```bash
|
2026-01-17 12:33:11 +01:00
|
|
|
# Start database (required first)
|
|
|
|
|
docker compose up -d
|
|
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
# Install dependencies
|
|
|
|
|
npm install
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
# Start development server
|
|
|
|
|
npm run dev
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
# Run database migrations
|
|
|
|
|
npx prisma migrate dev
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
# Generate Prisma client
|
|
|
|
|
npx prisma generate
|
|
|
|
|
|
|
|
|
|
# Seed database
|
|
|
|
|
npm run db:seed
|
|
|
|
|
|
|
|
|
|
# Type checking
|
|
|
|
|
npm run typecheck
|
|
|
|
|
|
|
|
|
|
# Build for production
|
|
|
|
|
npm run build
|
|
|
|
|
|
|
|
|
|
# App available at http://localhost:3000
|
2025-12-22 14:09:32 +01:00
|
|
|
```
|
|
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
## Key Patterns
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
### React Query Hooks
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
All data fetching uses React Query hooks in `src/hooks/`:
|
|
|
|
|
- `useCustomers()`, `useCustomer(id)` - Customer data
|
|
|
|
|
- `useOrders()`, `useOrder(id)` - Order data
|
|
|
|
|
- `useServers()` - Server list
|
|
|
|
|
- `useDashboardStats()` - Dashboard metrics
|
2026-01-17 12:33:11 +01:00
|
|
|
- `useNetcupServers()`, `useNetcupServer(id)` - Netcup servers
|
|
|
|
|
- `useNetcupAuth()` - Netcup authentication status
|
|
|
|
|
- `useServerMetrics(id, hours)` - Server performance metrics
|
|
|
|
|
- `useServerSnapshots(id)` - Server snapshots
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
Mutations follow the pattern:
|
|
|
|
|
- `useCreateOrder()`, `useUpdateOrder()`
|
2026-01-17 12:33:11 +01:00
|
|
|
- `useNetcupPowerAction()`, `useNetcupRescue()`
|
|
|
|
|
- `useCreateSnapshot()`, `useDeleteSnapshot()`, `useRevertSnapshot()`
|
2026-01-06 12:35:01 +01:00
|
|
|
- Automatic cache invalidation via `queryClient.invalidateQueries()`
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
### API Route Pattern
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
```typescript
|
|
|
|
|
export async function GET(request: NextRequest) {
|
2026-01-17 12:33:11 +01:00
|
|
|
// Auth check
|
|
|
|
|
const session = await auth()
|
|
|
|
|
if (!session || session.user.userType !== 'staff') {
|
|
|
|
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
// Parse query params
|
|
|
|
|
const searchParams = request.nextUrl.searchParams
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
// Database query with Prisma
|
|
|
|
|
const data = await prisma.model.findMany({...})
|
|
|
|
|
|
|
|
|
|
// Return JSON response
|
|
|
|
|
return NextResponse.json(data)
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Component Pattern
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
```typescript
|
|
|
|
|
'use client'
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
export function MyComponent() {
|
|
|
|
|
const { data, isLoading, error } = useMyData()
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
if (isLoading) return <Skeleton />
|
|
|
|
|
if (error) return <ErrorMessage error={error} />
|
2025-12-22 14:09:32 +01:00
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
return <div>...</div>
|
|
|
|
|
}
|
2025-12-22 14:09:32 +01:00
|
|
|
```
|
|
|
|
|
|
2026-01-17 12:33:11 +01:00
|
|
|
### Service Pattern
|
|
|
|
|
|
|
|
|
|
Backend services in `src/lib/services/`:
|
|
|
|
|
```typescript
|
|
|
|
|
class MyService {
|
|
|
|
|
private static instance: MyService
|
|
|
|
|
|
|
|
|
|
static getInstance(): MyService {
|
|
|
|
|
if (!MyService.instance) {
|
|
|
|
|
MyService.instance = new MyService()
|
|
|
|
|
}
|
|
|
|
|
return MyService.instance
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async doSomething(): Promise<Result> {
|
|
|
|
|
// Implementation
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const myService = MyService.getInstance()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Database Schema (Key Models)
|
|
|
|
|
|
|
|
|
|
```prisma
|
|
|
|
|
model Customer {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
name String
|
|
|
|
|
email String @unique
|
|
|
|
|
company String?
|
|
|
|
|
orders Order[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Order {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
status OrderStatus
|
|
|
|
|
domain String
|
|
|
|
|
customerId String
|
|
|
|
|
serverIp String?
|
|
|
|
|
serverPassword String?
|
|
|
|
|
netcupServerId String? # Linked Netcup server
|
|
|
|
|
automationMode AutomationMode @default(MANUAL)
|
|
|
|
|
customer Customer @relation(...)
|
|
|
|
|
dnsVerification DnsVerification?
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model SystemSettings {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
key String @unique
|
|
|
|
|
value String @db.Text
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2025-12-22 14:09:32 +01:00
|
|
|
## Coding Conventions
|
|
|
|
|
|
2026-01-06 12:35:01 +01:00
|
|
|
- Use `'use client'` directive for client components
|
|
|
|
|
- All API routes return `NextResponse.json()`
|
|
|
|
|
- Use Prisma for all database operations
|
|
|
|
|
- Follow existing shadcn/ui component patterns
|
|
|
|
|
- Use React Query for server state management
|
|
|
|
|
- TypeScript strict mode - no `any` types
|
2026-01-17 12:33:11 +01:00
|
|
|
- Services are singletons exported from `lib/services/`
|
|
|
|
|
- Environment variables in `.env.local` (never commit)
|