09 - Development Guide
Prerequisites
- Node.js 22.x or higher
- npm 10.x or higher
- Git
- VS Code (recommended)
Initial Setup
1. Clone Repository
bash
# From Azure DevOps (primary)
git clone https://dev.azure.com/FF8Dev/AudioStudio/_git/AudioStudio
cd AudioStudio/wavic-webapp
# Checkout front branch
git checkout front2. Install Dependencies
bash
npm install3. Environment Configuration
bash
# Copy example environment file
cp src/.env.local.example src/.env.local
# Edit with your values
nano src/.env.localRequired environment variables:
bash
# API
NEXT_PUBLIC_API_BASE_URL=http://localhost:8080
# NextAuth
NEXTAUTH_SECRET=your-secret-key-at-least-32-characters
NEXTAUTH_URL=http://localhost:3000
# Optional: Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
# Optional: Email
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=user@example.com
SMTP_PASSWORD=password
SMTP_FROM_EMAIL=noreply@example.com4. Start Development Server
bash
npm run devOpens at http://localhost:3000
Note: Uses Turbopack for fast development builds
Available Scripts
| Script | Description |
|---|---|
npm run dev | Start development server with Turbo |
npm run build | Build for production |
npm run start | Start production server |
npm run lint | Run ESLint |
npm run format | Format code with Prettier |
npm run clean | Remove node_modules, .next, .cache |
npm run generate-icons | Generate icon data file |
Backend Setup
The webapp requires the wavic-api backend running:
bash
# In separate terminal
cd ../wavic-api
# Start MongoDB (Docker)
docker compose -f docker-compose.local.yml up -d
# Start API
npm run devAPI runs at http://localhost:8080
Project Structure Recap
wavic-webapp/
├── src/
│ ├── app/ # Pages and routes (App Router)
│ ├── components/ # React components
│ ├── config/ # Configuration files
│ ├── contexts/ # React contexts
│ ├── hooks/ # Custom hooks
│ ├── layouts/ # Layout components
│ ├── lib/ # Utility libraries
│ ├── server-actions/# Server-side API calls
│ ├── store/ # Jotai state atoms
│ └── utils/ # Utility functions
├── public/ # Static assets
├── types/ # TypeScript types
└── docs/ # Documentation (you are here)VS Code Setup
Recommended Extensions
json
// .vscode/extensions.json
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"bradlc.vscode-tailwindcss",
"formulahendry.auto-rename-tag",
"dsznajder.es7-react-js-snippets"
]
}Settings
json
// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"tailwindCSS.experimental.classRegex": [["cn\\(([^)]*)\\)", "'([^']*)'"]]
}Code Quality Tools
ESLint
Configuration in eslint.config.mjs (ESLint 9 flat config):
javascript
import { FlatCompat } from '@eslint/eslintrc';
const eslintConfig = [
...compat.extends('next/core-web-vitals'),
{
linterOptions: { reportUnusedDisableDirectives: 'off' },
rules: {
'react-hooks/exhaustive-deps': 'off',
'@next/next/no-img-element': 'off',
},
},
];
export default eslintConfig;Prettier
Configuration in prettier.config.mjs:
javascript
export default {
semi: true,
singleQuote: true,
tabWidth: 2,
trailingComma: 'es5',
plugins: ['prettier-plugin-tailwindcss'],
};Husky (Git Hooks)
Pre-commit hooks run automatically:
bash
# .husky/pre-commit
npm run lint-stagedLint-Staged
javascript
// lint-staged.config.mjs
export default {
'*.{js,jsx,ts,tsx}': ['eslint --fix', 'prettier --write'],
'*.{json,md,css}': ['prettier --write'],
};Development Workflow
1. Create Feature Branch
bash
git checkout front
git pull origin front
git checkout -b feature/my-feature2. Make Changes
- Create/modify components
- Add server actions if needed
- Update types
- Test locally
3. Commit Changes
bash
git add .
git commit -m "feat: add new feature"Commit message conventions:
feat:New featurefix:Bug fixdocs:Documentationstyle:Formattingrefactor:Code refactoringtest:Testschore:Maintenance
4. Push and Create PR
bash
git push origin feature/my-featureCreate Pull Request in Azure DevOps.
Creating New Pages
1. Create Route Folder
bash
mkdir -p src/app/(hydrogen)/my-page2. Create Page Component
typescript
// src/app/(hydrogen)/my-page/page.tsx
import { metaObject } from '@/config/site.config';
export const metadata = {
...metaObject('My Page'),
};
export default function MyPage() {
return (
<div className="@container">
<h1>My Page</h1>
</div>
);
}3. Add Route to Config (Optional)
typescript
// src/config/routes.ts
export const routes = {
// ...existing routes
myPage: '/my-page',
};Creating New Components
1. Create Component File
typescript
// src/components/my-component.tsx
'use client';
import cn from '@/utils/class-names';
interface MyComponentProps {
title: string;
className?: string;
}
export default function MyComponent({
title,
className
}: MyComponentProps) {
return (
<div className={cn('p-4 bg-white rounded-lg', className)}>
<h2>{title}</h2>
</div>
);
}2. Export from Index (Optional)
typescript
// src/components/index.ts
export { default as MyComponent } from './my-component';Creating Server Actions
typescript
// src/server-actions/my-feature/actions.tsx
'use server';
export async function myAction(token: string, data: any) {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_BASE_URL}/endpoint`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
}
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
}Debugging
React Developer Tools
Install browser extension for component inspection.
Network Debugging
Use browser DevTools Network tab to inspect API calls.
Console Logging
typescript
// Development only logging
if (process.env.NODE_ENV === 'development') {
console.log('Debug info:', data);
}Error Boundaries
typescript
// src/components/ErrorBoundary.tsx
'use client';
import { Component, ReactNode } from 'react';
interface Props {
children: ReactNode;
fallback?: ReactNode;
}
interface State {
hasError: boolean;
}
export default class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return this.props.fallback || <div>Something went wrong</div>;
}
return this.props.children;
}
}Building for Production
bash
# Build
npm run build
# Test production build locally
npm run startTroubleshooting
Common Issues
Port already in use:
bash
lsof -ti:3000 | xargs kill -9Clear cache:
bash
npm run clean
npm installTypeScript errors:
bash
npx tsc --noEmitESLint errors:
bash
npm run lint -- --fix