# Development Guide
This guide covers local development setup for contributing to nself-admin.
## Table of Contents
1. [Getting Started](#getting-started)
2. [Project Structure](#project-structure)
3. [Development Workflow](#development-workflow)
4. [Code Style Guide](#code-style-guide)
5. [Testing](#testing)
6. [Building](#building)
7. [Common Development Tasks](#common-development-tasks)
8. [Debugging](#debugging)
9. [Common Issues](#common-issues)
10. [Contributing](#contributing)
---
## Getting Started
### Prerequisites
- **Node.js**: 18.x or later
- **pnpm**: 8.x or later
- **Docker**: 20.10+ (for testing)
- **Git**: Any recent version
- **Code Editor**: VS Code recommended
### Initial Setup
```bash
# Clone the repository
git clone https://github.com/nself-org/admin.git
cd nself-admin
# Install dependencies
pnpm install
# Copy environment file (optional)
cp .env.example .env.local
# Start development server
PORT=3021 pnpm dev
```
Open http://localhost:3021
### VS Code Setup
Recommended extensions:
```json
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"bradlc.vscode-tailwindcss",
"yoavbls.pretty-ts-errors",
"streetsidesoftware.code-spell-checker"
]
}
```
Settings (`.vscode/settings.json`):
```json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"typescript.tsdk": "node_modules/typescript/lib",
"tailwindCSS.experimental.classRegex": [["clsx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]]
}
```
---
## Project Structure
```
nself-admin/
├── .claude/ # Project instructions for Claude
│ └── CLAUDE.md # Development guidelines
├── docs/ # Documentation
│ ├── ARCHITECTURE.md # Architecture details
│ ├── API.md # API documentation
│ ├── DEPLOYMENT.md # Deployment guide
│ ├── DEVELOPMENT.md # This file
│ ├── MIGRATION.md # Migration guides
│ └── CHANGELOG.md # Release notes
├── public/ # Static assets
│ ├── sw.js # Service worker
│ └── offline.html # Offline page
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── api/ # API routes
│ │ ├── login/ # Login page
│ │ ├── build/ # Build wizard
│ │ ├── config/ # Configuration pages
│ │ ├── database/ # Database pages
│ │ ├── services/ # Service management pages
│ │ ├── deployment/ # Deployment pages
│ │ ├── cloud/ # Cloud provider pages
│ │ ├── plugins/ # Plugin pages
│ │ ├── monitor/ # Monitoring pages
│ │ ├── settings/ # Settings pages
│ │ ├── layout.tsx # Root layout
│ │ └── page.tsx # Dashboard
│ ├── components/ # React components
│ │ ├── ui/ # UI primitives
│ │ ├── build/ # Build wizard components
│ │ ├── config/ # Config components
│ │ ├── database/ # Database components
│ │ ├── services/ # Service components
│ │ ├── skeletons/ # Loading skeletons
│ │ ├── Header.tsx # Top navigation
│ │ ├── Layout.tsx # Main layout
│ │ └── Navigation.tsx # Sidebar navigation
│ ├── contexts/ # React contexts
│ │ └── AuthContext.tsx # Auth state
│ ├── hooks/ # Custom hooks
│ │ ├── useDashboardData.ts
│ │ ├── useServiceStatus.ts
│ │ ├── useSession.ts
│ │ └── useWebSocket.ts
│ ├── lib/ # Utilities and libraries
│ │ ├── api-client.ts # API client
│ │ ├── auth-db.ts # Auth database
│ │ ├── database.ts # LokiJS database
│ │ ├── nselfCLI.ts # nself CLI wrapper
│ │ ├── validation.ts # Zod schemas
│ │ └── utils.ts # Utility functions
│ └── services/ # Background services
│ └── SimplifiedPolling.ts # Polling service
├── tests/ # Test files
│ ├── e2e/ # Playwright tests
│ └── accessibility/ # Accessibility tests
├── .env.example # Example environment file
├── .eslintrc.json # ESLint configuration
├── .prettierrc # Prettier configuration
├── jest.config.js # Jest configuration
├── next.config.mjs # Next.js configuration
├── package.json # Dependencies
├── pnpm-lock.yaml # Lock file
├── tailwind.config.ts # Tailwind configuration
└── tsconfig.json # TypeScript configuration
```
### Key Directories
**`src/app/`** - Next.js App Router pages and API routes
- Every folder is a route
- `page.tsx` = page component
- `route.ts` = API endpoint
**`src/components/`** - Reusable React components
- `ui/` = Base components (buttons, inputs, etc.)
- Feature-specific folders for complex components
**`src/lib/`** - Utilities, helpers, and services
- Business logic, database access, API clients
**`src/hooks/`** - Custom React hooks
- Data fetching, WebSocket, state management
---
## Development Workflow
### Starting Development Server
```bash
# Start with default port (3021)
pnpm dev
# Start with custom port
PORT=4000 pnpm dev
# Start with turbo mode (faster builds)
pnpm dev --turbo
```
### Making Changes
1. **Create a branch**
```bash
git checkout -b feature/my-feature
```
2. **Make your changes**
- Edit files
- Add tests
- Update documentation
3. **Run quality checks**
```bash
pnpm run lint # Check for errors
pnpm run format # Auto-format code
pnpm run type-check # TypeScript validation
pnpm test # Run unit tests
```
4. **Test manually**
- Start dev server
- Test in browser
- Check console for errors
5. **Commit changes**
```bash
git add .
git commit -m "feat: add new feature"
```
6. **Push and create PR**
```bash
git push origin feature/my-feature
# Open PR on GitHub
```
### Hot Reload
Next.js supports hot module replacement:
- Changes to components → instant reload
- Changes to API routes → automatic restart
- Changes to config → manual restart needed
---
## Code Style Guide
### TypeScript
**Use strict typing:**
```typescript
// Good
interface ServiceStatus {
name: string
status: 'running' | 'stopped' | 'error'
uptime: number
}
function getServiceStatus(name: string): ServiceStatus {
// ...
}
// Avoid
function getServiceStatus(name: any): any {
// ...
}
```
**Prefer interfaces over types:**
```typescript
// Good
interface User {
id: string
name: string
}
// OK for unions
type Status = 'active' | 'inactive'
```
**Use proper error handling:**
```typescript
// Good
try {
await someOperation()
} catch (error) {
const err = error as Error
console.error('Operation failed:', err.message)
return { success: false, error: err.message }
}
// Avoid
try {
await someOperation()
} catch (error) {
console.error(error) // Unknown type
}
```
### React Components
**Functional components with TypeScript:**
```typescript
// Good
interface ButtonProps {
label: string
onClick: () => void
variant?: 'primary' | 'secondary'
}
export function Button({ label, onClick, variant = 'primary' }: ButtonProps) {
return (
)
}
```
**Use proper hooks:**
```typescript
// Good
function MyComponent() {
const [count, setCount] = useState(0)
const [data, setData] = useState(null)
useEffect(() => {
fetchData().then(setData)
}, [])
return {count}
}
```
### API Routes
**Standard response format:**
```typescript
// Good
export async function GET(request: Request) {
try {
const data = await fetchData()
return NextResponse.json({ success: true, data })
} catch (error) {
return NextResponse.json(
{
success: false,
error: 'Failed to fetch data',
details: error instanceof Error ? error.message : 'Unknown error',
},
{ status: 500 }
)
}
}
```
### Naming Conventions
**Files:**
- Components: `PascalCase.tsx` (e.g., `ServiceCard.tsx`)
- Utilities: `camelCase.ts` (e.g., `apiClient.ts`)
- API routes: `route.ts`
- Pages: `page.tsx`
**Variables:**
- Constants: `UPPER_SNAKE_CASE`
- Variables: `camelCase`
- Components: `PascalCase`
- Types/Interfaces: `PascalCase`
**Functions:**
- Regular functions: `camelCase`
- React components: `PascalCase`
- Custom hooks: `useCamelCase`
### Imports
**Order:**
1. External libraries
2. Internal utilities
3. Components
4. Types
5. Styles
```typescript
// Good
import { useState, useEffect } from 'react'
import { NextResponse } from 'next/server'
import { apiClient } from '@/lib/api-client'
import { Button } from '@/components/ui/button'
import type { ServiceStatus } from '@/types'
```
**Use path aliases:**
```typescript
// Good
import { Button } from '@/components/ui/button'
import { apiClient } from '@/lib/api-client'
// Avoid
import { Button } from '../../../components/ui/button'
```
---
## Testing
### Unit Tests (Jest)
**Run tests:**
```bash
pnpm test # Run all tests
pnpm test:watch # Watch mode
pnpm test:coverage # With coverage report
```
**Example test:**
```typescript
// src/lib/__tests__/utils.test.ts
import { formatUptime } from '../utils'
describe('formatUptime', () => {
it('formats seconds correctly', () => {
expect(formatUptime(30)).toBe('30s')
})
it('formats minutes correctly', () => {
expect(formatUptime(90)).toBe('1m 30s')
})
it('formats hours correctly', () => {
expect(formatUptime(3665)).toBe('1h 1m 5s')
})
})
```
### E2E Tests (Playwright)
**Run E2E tests:**
```bash
pnpm test:e2e # Run all E2E tests
pnpm test:e2e:headed # Run with browser visible
pnpm test:e2e:ui # Interactive mode
pnpm test:e2e:debug # Debug mode
```
**Example E2E test:**
```typescript
// tests/e2e/login.spec.ts
import { test, expect } from '@playwright/test'
test('should login successfully', async ({ page }) => {
await page.goto('http://localhost:3021/login')
await page.fill('input[name="password"]', 'testpassword123')
await page.click('button[type="submit"]')
await expect(page).toHaveURL('http://localhost:3021/')
await expect(page.locator('h1')).toContainText('Dashboard')
})
```
### Accessibility Tests
**Run accessibility audit:**
```bash
pnpm test:a11y
```
Uses Pa11y to check WCAG 2.1 AA compliance.
---
## Building
### Development Build
```bash
pnpm build
```
Outputs to `.next/` directory.
### Production Build
```bash
NODE_ENV=production pnpm build
```
Optimizes for production:
- Minification
- Code splitting
- Tree shaking
- Image optimization
### Docker Build
```bash
# Build image
pnpm docker:build
# Push to registry
pnpm docker:push
# Or use script
./scripts/docker-release.sh
```
### Build Analysis
Analyze bundle size:
```bash
ANALYZE=true pnpm build
```
Opens interactive bundle analyzer.
---
## Common Development Tasks
### Adding a New Page
1. Create page file:
```bash
mkdir -p src/app/my-feature
touch src/app/my-feature/page.tsx
```
2. Create page component:
```typescript
export default function MyFeaturePage() {
return My Feature
}
```
3. Add to navigation:
```typescript
// src/components/Navigation.tsx
{
name: 'My Feature',
href: '/my-feature',
icon: SparklesIcon
}
```
### Adding an API Route
1. Create route file:
```bash
mkdir -p src/app/api/my-feature
touch src/app/api/my-feature/route.ts
```
2. Implement handlers:
```typescript
import { NextResponse } from 'next/server'
export async function GET(request: Request) {
try {
const data = await fetchData()
return NextResponse.json({ success: true, data })
} catch (error) {
return NextResponse.json({ success: false, error: 'Failed' }, { status: 500 })
}
}
export async function POST(request: Request) {
// ...
}
```
### Adding a Component
1. Create component file:
```bash
touch src/components/MyComponent.tsx
```
2. Implement component:
```typescript
interface MyComponentProps {
title: string
}
export function MyComponent({ title }: MyComponentProps) {
return {title}
}
```
3. Export from index (if in ui/):
```typescript
// src/components/ui/index.ts
export { MyComponent } from './MyComponent'
```
### Adding a Custom Hook
1. Create hook file:
```bash
touch src/hooks/useMyHook.ts
```
2. Implement hook:
```typescript
import { useState, useEffect } from 'react'
export function useMyHook(param: string) {
const [data, setData] = useState(null)
useEffect(() => {
// Fetch data
}, [param])
return { data }
}
```
### Adding Database Fields
LokiJS is used for nAdmin's internal database.
1. Update schema:
```typescript
// src/lib/database.ts
interface MyCollection {
key: string
value: any
timestamp: number
}
```
2. Add collection:
```typescript
const collection =
db.getCollection('my_collection') ||
db.addCollection('my_collection', {
unique: ['key'],
ttl: 3600000, // 1 hour
})
```
---
## Debugging
### Browser DevTools
**React DevTools:**
- Install extension
- Inspect component tree
- View props and state
**Network Tab:**
- Monitor API requests
- Check response times
- Debug failed requests
**Console:**
- View logs and errors
- Test JavaScript
### VS Code Debugging
Create `.vscode/launch.json`:
```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Next.js: debug server-side",
"type": "node-terminal",
"request": "launch",
"command": "pnpm dev"
},
{
"name": "Next.js: debug client-side",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3021"
}
]
}
```
### Debugging API Routes
Add breakpoints or console.log:
```typescript
export async function GET(request: Request) {
console.log('Request received:', request.url)
debugger // Pauses execution
// ...
}
```
### Debugging nself CLI Calls
Enable CLI debug output:
```typescript
// src/lib/nselfCLI.ts
const result = await execFile('nself', ['status'], {
cwd: projectPath,
env: { ...process.env, DEBUG: '1' },
})
console.log('CLI output:', result.stdout)
```
---
## Common Issues
### Port Already in Use
**Error:** `EADDRINUSE: address already in use :::3021`
**Solution:**
```bash
# Find process using port
lsof -i :3021
# Kill process
kill -9
# Or use different port
PORT=4000 pnpm dev
```
### Module Not Found
**Error:** `Cannot find module '@/components/...'`
**Solution:**
```bash
# Reinstall dependencies
rm -rf node_modules pnpm-lock.yaml
pnpm install
```
### TypeScript Errors
**Error:** Type errors during development
**Solution:**
```bash
# Run type check
pnpm run type-check
# Restart TypeScript server in VS Code
Cmd+Shift+P → "TypeScript: Restart TS Server"
```
### Hot Reload Not Working
**Solution:**
```bash
# Restart dev server
Ctrl+C
pnpm dev
# Clear Next.js cache
rm -rf .next
pnpm dev
```
### Docker Socket Permission Denied
**Error:** `permission denied while trying to connect to the Docker daemon socket`
**Solution:**
```bash
# Add user to docker group
sudo usermod -aG docker $USER
newgrp docker
# Verify
docker ps
```
---
## Contributing
### Before Submitting PR
**Checklist:**
- [ ] Code follows style guide
- [ ] TypeScript compiles (`pnpm run type-check`)
- [ ] Linting passes (`pnpm run lint`)
- [ ] Code is formatted (`pnpm run format`)
- [ ] Tests pass (`pnpm test`)
- [ ] E2E tests pass (if applicable)
- [ ] Documentation updated
- [ ] Commit messages follow convention
### Commit Message Convention
Format: `(): `
**Types:**
- `feat` - New feature
- `fix` - Bug fix
- `docs` - Documentation
- `style` - Formatting
- `refactor` - Code restructuring
- `test` - Adding tests
- `chore` - Maintenance
**Examples:**
```bash
feat(database): add backup scheduling
fix(auth): resolve session timeout issue
docs(api): update API documentation
refactor(services): simplify service status logic
test(auth): add login flow tests
```
### Code Review Process
1. Submit PR with description
2. Automated checks run (CI)
3. Reviewer provides feedback
4. Make requested changes
5. Approved and merged
---
## Additional Resources
- [Next.js Documentation](https://nextjs.org/docs)
- [React Documentation](https://react.dev)
- [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html)
- [Tailwind CSS](https://tailwindcss.com/docs)
- [Jest](https://jestjs.io/docs/getting-started)
- [Playwright](https://playwright.dev/docs/intro)
---
**Questions?** Open an issue on [GitHub](https://github.com/nself-org/admin/issues).