Skip to content

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 front

2. Install Dependencies

bash
npm install

3. Environment Configuration

bash
# Copy example environment file
cp src/.env.local.example src/.env.local

# Edit with your values
nano src/.env.local

Required 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.com

4. Start Development Server

bash
npm run dev

Opens at http://localhost:3000

Note: Uses Turbopack for fast development builds

Available Scripts

ScriptDescription
npm run devStart development server with Turbo
npm run buildBuild for production
npm run startStart production server
npm run lintRun ESLint
npm run formatFormat code with Prettier
npm run cleanRemove node_modules, .next, .cache
npm run generate-iconsGenerate 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 dev

API 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

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-staged

Lint-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-feature

2. 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 feature
  • fix: Bug fix
  • docs: Documentation
  • style: Formatting
  • refactor: Code refactoring
  • test: Tests
  • chore: Maintenance

4. Push and Create PR

bash
git push origin feature/my-feature

Create Pull Request in Azure DevOps.

Creating New Pages

1. Create Route Folder

bash
mkdir -p src/app/(hydrogen)/my-page

2. 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 start

Troubleshooting

Common Issues

Port already in use:

bash
lsof -ti:3000 | xargs kill -9

Clear cache:

bash
npm run clean
npm install

TypeScript errors:

bash
npx tsc --noEmit

ESLint errors:

bash
npm run lint -- --fix

Ctrl-Audio Platform Documentation