- Erklärung: Lokale und erstellte Samba-User bleiben über App-Updates erhalten - Deployment korrigiert: PAM-User mit useradd erstellen statt nicht-existierendem auth_service.add_user() - Neues Kapitel "Data Persistence" mit Details zu: - System-Benutzer (PAM, /etc/passwd) - Samba-User (TDB/Registry) - Samba Shares & Config - NFS Exports - ZFS Pools (Hardware-level persistence) - Klarstellung in "Important Constraints": Benutzer überleben App-Redeployments - Port korrigiert: 9090 → 8090 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
14 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
ZMB Webui is a modern web UI replacing the unstable Cockpit on Raspberry Pi (10.66.120.3 pidata). Built with Python/FastAPI (backend) + Next.js 15 (frontend), deployed on resource-constrained ARM64 systems.
- Primary Target: Raspberry Pi (4GB RAM, ARM64) at 10.66.120.3
- Test Environment: Debian LXC container at 192.168.1.179
- Status: Backend + Frontend complete. Shares management verified. Ready for Phase 3 features.
Architecture
Backend (FastAPI + uvicorn)
backend/
├── main.py # FastAPI app, router mounting, static serving, WebSocket
├── routers/ # API endpoints (auth, pools, datasets, snapshots, files, shares, identities, system)
├── services/ # Business logic (zfs_runner, auth, file_manager, shares, identities, system_info)
├── models/ # Pydantic models (pool, dataset, snapshot, auth, share)
├── static/ # Optional static HTML (fallback UI)
├── config/ # Configuration templates
└── requirements.txt # FastAPI, pydantic, pam, uvicorn
Key Pattern: Routers define endpoints, Services implement logic, Models define request/response shapes.
ZFS commands run via subprocess wrapper (services/zfs_runner.py) with 5s timeout and caching.
Key Features:
- JWT authentication with PAM system users (pam v2.0.2 in venv)
- WebSocket broadcast for pool status (30s interval)
- CORS middleware enabled (change allow_origins in production)
- Caching: pools (30s TTL), snapshots/datasets (60s TTL)
- Static file serving for Next.js frontend (if built)
Frontend (Next.js 15 + TypeScript)
frontend/
├── app/ # Next.js App Router (pages)
│ ├── page.tsx # Dashboard (pools, auto-refresh, ISR: 30s)
│ ├── login/page.tsx # JWT login form
│ ├── snapshots/page.tsx # Snapshot table (ISR: 60s)
│ └── files/page.tsx # File browser placeholder
├── components/ # React components (Header, PoolCard, UI primitives)
├── lib/
│ ├── api.ts # Axios client for backend (40+ methods, type-safe)
│ └── utils.ts # Helpers (formatBytes, cn, color mapping)
├── package.json # 19 dependencies
├── tsconfig.json # Strict TypeScript
├── tailwind.config.ts # Dark mode, custom theme
├── next.config.ts # ISR + compression, static export
└── .env.example # NEXT_PUBLIC_API_URL template
Key Pattern: Pages use ISR for caching, components are functional/typed, api.ts handles all backend calls.
Key Features:
- Incremental Static Regeneration (ISR) for fast loads on weak hardware
- JWT localStorage persistence + auto-refresh on 401
- Full TypeScript (zero
anytypes) - Tailwind CSS with dark mode + custom color scheme
- Responsive mobile-first design
- Static export capability (npm run export → nginx-ready HTML)
Development Commands
Backend (Python/FastAPI)
cd backend
# Setup
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Create default admin user
python3 -c "from services.auth import auth_service; auth_service.add_user('admin', 'yourpassword')"
# Run development server (port 8000)
python3 main.py
# Run with uvicorn directly (same as main.py)
uvicorn main:app --reload --host 0.0.0.0 --port 8000
# Check ZFS availability
zpool list
zfs list
# View API docs
# → http://localhost:8000/docs (auto-generated by FastAPI)
# View logs (if systemd service running)
journalctl -u zmb-webui-backend -f
Frontend (Next.js/TypeScript)
cd frontend
# Setup
npm install
# Development server (port 3000, hot reload)
npm run dev
# Build for production
npm run build
# Start production server
npm start
# Export to static HTML (for nginx)
npm run export
# → Creates ./out/ directory with static HTML
# Lint TypeScript
npm run lint
Common Development Tasks
Add a new API endpoint
- Create/edit router in
backend/routers/yourfeature.py - Import in
backend/main.py:from routers import yourfeature - Mount:
app.include_router(yourfeature.router) - Add corresponding method to
lib/api.tsfrontend client
Example: Adding a new Pools endpoint
# backend/routers/pools.py
@router.post("/refresh")
async def refresh_pools(credentials: HTTPAuthorizationCredentials = Depends(security)):
# verify token, call service
return {"pools": zfs_runner.list_pools()}
# frontend/lib/api.ts
async refreshPools(): Promise<Pool[]> {
return this.authenticated_get("/pools/refresh");
}
Add a new frontend page
- Create directory and page:
frontend/app/newpage/page.tsx - Use layout from
app/layout.tsxas template - Import Header and API client:
import { Header } from "@/components/Header"; import { api } from "@/lib/api"; - Add link to navigation in
components/Header.tsx
Test against test container (192.168.1.179)
# Terminal 1: Backend already running on :8000
# Terminal 2: Frontend dev
cd frontend
npm run dev
# → http://localhost:3000
# Test login: admin / (check container for correct password)
# Watch browser console for API errors
# Check curl:
curl http://192.168.1.179:8000/api/status -H "Authorization: Bearer YOUR_TOKEN"
Deployment
To Raspberry Pi (10.66.120.3)
# Build frontend on faster machine
cd frontend && npm run build && npm run export
# Creates ./out/ with static HTML
# Copy to Pi
scp -r backend root@10.66.120.3:/opt/zmb-webui/
scp -r frontend/out root@10.66.120.3:/opt/zmb-webui/frontend/
# SSH to Pi
ssh root@10.66.120.3
cd /opt/zmb-webui/backend
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Create system user for WebUI login (uses PAM authentication)
useradd -m -s /bin/bash webadmin
echo "webadmin:yourpassword" | chpasswd
# Run via systemd (or nohup for testing)
nohup python3 main.py > /tmp/zfs-backend.log 2>&1 &
To Test Container (192.168.1.179)
# Backend already deployed
# For frontend, either:
# Option 1: Copy static export
npm run export
scp -r frontend/out root@192.168.1.179:/opt/zmb-webui/frontend/
# Option 2: Run dev server (slower, for testing only)
npm run dev -- -p 3000 # Access via http://192.168.1.179:3000
Data Persistence
All user and configuration data is persisted on the system – not stored in the application. This means data survives application restarts, updates, and redeployments:
System Users
- Location:
/etc/passwd,/etc/shadow - Creation:
useradd -m webadmin; echo "webadmin:password" | chpasswd - Persistence: ✅ Survives application updates, restarts, reinstalls
- Management: Via CLI (
useradd,userdel,passwd) or WebUI (/identitiespage) - Note: WebUI uses PAM authentication – users must exist as system users
Samba Users
- Location: Samba TDB database (e.g.,
/var/lib/samba/private/sam.tdb) or Registry - Creation:
smbpasswd -a usernameor via WebUI (/identities→ "Set Samba Password") - Persistence: ✅ Survives application updates, restarts, reinstalls
- Backup tip: Backup
/var/lib/samba/private/directory to preserve user database
Samba Shares & Config
- Location:
/etc/samba/smb.confor Samba Registry (net conf) - Creation: Via WebUI (
/sharespage) or CLI - Persistence: ✅ Survives application updates, restarts, reinstalls
- Editable: Changes made in WebUI are written directly to config files
NFS Exports
- Location:
/etc/exports - Creation: Via WebUI (
/sharespage) or CLI - Persistence: ✅ Survives application updates, restarts, reinstalls
- Reload:
exportfs -ris called automatically after changes
ZFS Pools & Datasets
- Location: ZFS metadata (on-disk, hardware managed)
- Creation: Via WebUI (
/pools,/datasetspages) - Persistence: ✅ Persists across all updates and restarts (hardware level)
- Note: ZFS data is never modified by application code – only read
Update Safety
When deploying updates (redeploying backend/frontend code):
- System users are NOT affected – still exist, still work
- Samba users are NOT affected – database persists
- File shares are NOT affected – config files persist
- All WebUI pages will continue to work with existing data
No user re-creation required on updates.
Architecture Patterns & Key Files
Router Pattern (Backend)
Each router in routers/ defines a feature's endpoints:
- Imports Pydantic models from
models/ - Calls services for business logic
- Uses
HTTPBearer()for auth (reads JWT token) - Returns typed Pydantic response models
File: backend/routers/pools.py — Pool endpoints calling zfs_runner service
Service Pattern (Backend)
Services in services/ implement core logic:
zfs_runner.py: Subprocess wrapper aroundzpool/zfsCLI with cachingauth.py: JWT generation, PAM user authenticationfile_manager.py: Directory traversal in/tank/shareshares.py: Samba/NFS configurationidentities.py: User/group management
Key: All ZFS commands are cached with TTL; mutations clear cache. No direct shell execution.
WebSocket Broadcasting (Backend)
main.py startup task broadcasts pool status every 30s to connected WebSocket clients:
async def pool_status_broadcaster():
while True:
await asyncio.sleep(30)
pools_data = zfs_runner.list_pools()
await ws_broadcast({"type": "pool_status", "data": pools_data})
Frontend can subscribe via ws://host/ws for real-time updates (not yet used in UI).
API Client Pattern (Frontend)
lib/api.ts is a singleton TypeScript class wrapping axios with:
- Automatic JWT token management (localStorage)
- Auto-refresh on 401 Unauthorized
- Type-safe method signatures for all endpoints
- Centralized error handling
Usage in pages:
const { data: pools } = await api.getPools();
ISR Strategy (Frontend)
Pages define revalidation intervals:
export const revalidate = 30; // Dashboard: refresh every 30s
Useful on weak hardware: ISR pre-computes static pages on rebuild, serving cached HTML + on-demand updates.
Performance Notes (Raspberry Pi 4GB RAM)
Backend Optimizations
- Gunicorn: 2 workers (low memory footprint)
- ZFS queries: max depth 2 (avoid deep dataset trees)
- Snapshot limit: 50 by default (adjustable with
?limit=N) - Subprocess timeout: 5s (prevents hung processes)
- TTL cache: no external Redis needed
Frontend Optimizations
- ISR for page caching (static HTML)
- Bundle size: ~120KB gzipped
- No heavy libraries (minimal dependencies)
- Static export mode: nginx serves pure HTML (fastest)
For Extreme Constraints (2GB RAM)
- Use static export only (
npm run export) - Single gunicorn worker
- Aggressive cache TTLs (increase in
zfs_runner.py) - Consider disabling WebSocket broadcaster (comment in
main.py)
Important Constraints & Gotchas
- PAM Authentication: Uses system PAM (via
pampackage). Must run as root for/etc/shadowaccess. Users must exist as system users (useradd) – no local user database. Users created in WebUI are persisted to/var/lib/samba/private/(Samba users) or system groups. - User Persistence: System users (Linux) and Samba users are stored on disk and survive application updates. No user re-creation needed on redeployment.
- ZFS Commands: Require root or proper sudo configuration. Test with
sudo zpool list. - Frontend Build on Pi: Node.js build is slow on ARM64 (4-10 min). Build on x86 and copy instead.
- CORS in Production: Default allows all origins (
["*"]). Change inmain.pybefore exposing. - Static Export Mode: Cannot use dynamic API routes in Next.js. All data fetched client-side.
- Port 8090: Default for ZMB Webui (HTTPS via nginx). Adjust in nginx/systemd if needed.
Memory Usage
- Backend: ~50-100MB (Python + FastAPI)
- Frontend (dev): ~200-300MB (Node.js)
- Frontend (static): ~5-10MB (just HTML files)
- Total on Pi: ~150-200MB with backend + static frontend
If over 300MB, restart backend service or increase swap.
Debugging
Backend Issues
# Check logs
tail -f /tmp/zfs-backend.log
journalctl -u zmb-webui-backend -f
# Check ZFS availability
zpool list
zfs list
# Clear cache manually (if needed)
# Edit services/zfs_runner.py and restart
# Test an endpoint manually
curl -X POST http://localhost:8000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"testpass123"}'
Frontend Issues
# Check browser console (F12) for API errors
# Check .env.local points to correct backend
# Verify API connectivity
curl http://localhost:8000/health
curl http://localhost:8000/api/status
# Rebuild if cache issues
rm -rf .next
npm run build
npm start
Useful References
- PHASE1_SUMMARY.md — Initial backend setup & architecture
- PHASE2_SUMMARY.md — Frontend build & features
- DEPLOYMENT_MATRIX.md — Multi-platform deployment guide
- BACKEND_COMPLETE.md — Feature status (routers, endpoints, services)
- backend/README.md — API endpoint examples (curl commands)
- frontend/README.md — Frontend configuration & components
Next Phase (Phase 3)
Planned features (currently scaffolded):
- Advanced snapshot management (rollback, clone, retention)
- Dataset creation/deletion UI
- Share management UI (NFS/Samba)
- File manager with upload/download
- WebSocket-based real-time alerts
- SMART disk monitoring
- Email/Webhook notifications
See PHASE2_SUMMARY.md for detailed roadmap.