A Next.js frontend application for the AdMorph.AI platform - an AI-powered ad morphing and optimization system.
- Quick Start
- Environment Setup
- Development
- Backend Integration
- AWS Deployment
- Docker Deployment
- Project Structure
- API Integration
- Troubleshooting
- Node.js 18+
- pnpm (recommended) or npm
- Docker (for containerized deployment)
- AWS CLI (for AWS deployment)
# Clone the repository
git clone <your-repo-url>
cd NEXT_AdMorph.AI
# Install dependencies
pnpm install
# Copy environment variables
cp .env.example .env.local
# Start development server
pnpm devThe application will be available at http://localhost:3000.
Create a .env.local file in the root directory:
# API Configuration
NEXT_PUBLIC_API_URL=http://localhost:8000
NEXT_PUBLIC_WS_URL=ws://localhost:8001
# AWS Configuration
NEXT_PUBLIC_AWS_REGION=us-east-1
NEXT_PUBLIC_S3_BUCKET_NAME=your-bucket-name
# Environment
NEXT_PUBLIC_NODE_ENV=development
# Optional Feature Flags
NEXT_PUBLIC_VOICE_ENABLED=true
NEXT_PUBLIC_CHAT_ENABLED=true
NEXT_PUBLIC_ANALYTICS_ENABLED=true.env.local- Local development (not committed to git).env.production- Production environment variables.env.example- Template with all required variables
# Development
pnpm dev # Start development server
pnpm build # Build for production
pnpm start # Start production server
pnpm lint # Run ESLint
pnpm type-check # Run TypeScript type checking
# Production builds
pnpm build:production # Build with production environment
pnpm start:production # Start with production environment
# Docker commands
pnpm docker:build # Build Docker image
pnpm docker:run # Run Docker container
pnpm docker:compose # Run with docker-compose
# Analysis
pnpm analyze # Analyze bundle size
pnpm export # Export static files-
Start development server:
pnpm dev
-
Make changes to components in:
components/- Reusable UI componentsapp/- Pages and layoutslib/- Utilities and services
-
Test your changes:
pnpm lint pnpm type-check
-
Build for production:
pnpm build
The application includes a complete API service layer in lib/api.ts and lib/services.ts.
-
Update environment variables:
NEXT_PUBLIC_API_URL=https://your-backend-api.com NEXT_PUBLIC_WS_URL=wss://your-backend-websocket.com
-
Backend API Endpoints Expected:
GET /ads # Get all ads POST /ads # Create new ad GET /ads/:id # Get specific ad PUT /ads/:id # Update ad DELETE /ads/:id # Delete ad POST /ads/:id/assets # Upload ad assets GET /processing/jobs # Get processing jobs POST /processing/start # Start processing POST /processing/jobs/:id/cancel # Cancel processing GET /analytics/performance # Get performance metrics GET /analytics/performance/:id # Get ad-specific metrics POST /agents/chat # Send chat message POST /agents/voice/narrate # Get voice narration WebSocket /processing # Processing updates WebSocket /agents/chat/:sessionId # Chat updates -
Backend Response Format:
interface ApiResponse<T> { data: T; message?: string; error?: string; }
import { adService, processingService, analyticsService, agentService } from '@/lib/services';
// Get all ads
const ads = await adService.getAds();
// Create new ad
const newAd = await adService.createAd({
title: 'My Ad',
description: 'Ad description'
});
// Start processing
const job = await processingService.startProcessing(adId);
// Get performance metrics
const metrics = await analyticsService.getPerformanceMetrics();
// Send chat message
const response = await agentService.sendChatMessage('Hello');import { processingService, agentService } from '@/lib/services';
// Processing updates
const wsClient = processingService.createProcessingWebSocket((job) => {
console.log('Processing update:', job);
});
// Chat updates
const chatWs = agentService.createChatWebSocket(sessionId, (message) => {
console.log('Chat message:', message);
});
// Clean up
wsClient.disconnect();
chatWs.disconnect();-
Install AWS CLI:
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" unzip awscliv2.zip sudo ./aws/install
-
Configure AWS credentials:
aws configure
-
Install Amplify CLI:
npm install -g @aws-amplify/cli amplify configure
-
Initialize Amplify:
amplify init amplify add hosting amplify publish
-
Create EC2 instance (Amazon Linux 2)
-
Install CodeDeploy agent on EC2:
sudo yum update -y sudo yum install -y ruby wget cd /home/ec2-user wget https://aws-codedeploy-us-east-1.s3.us-east-1.amazonaws.com/latest/install chmod +x ./install sudo ./install auto -
Create CodeDeploy application:
aws deploy create-application \ --application-name AdMorph-Frontend \ --compute-platform Server
-
Create deployment group:
aws deploy create-deployment-group \ --application-name AdMorph-Frontend \ --deployment-group-name Production \ --service-role-arn arn:aws:iam::ACCOUNT:role/CodeDeployRole \ --ec2-tag-filters Key=Name,Value=AdMorph-Frontend,Type=KEY_AND_VALUE
-
Deploy using provided scripts:
# The deployment will use: # - buildspec.yml for CodeBuild # - appspec.yml for CodeDeploy # - scripts/ directory for deployment hooks
-
Create ECR repository:
aws ecr create-repository --repository-name admorph-frontend
-
Build and push Docker image:
# Get login token aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com # Build image docker build -t admorph-frontend . # Tag image docker tag admorph-frontend:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/admorph-frontend:latest # Push image docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/admorph-frontend:latest
-
Create ECS cluster:
aws ecs create-cluster --cluster-name admorph-cluster
-
Create task definition (create
task-definition.json):{ "family": "admorph-frontend", "networkMode": "awsvpc", "requiresCompatibilities": ["FARGATE"], "cpu": "256", "memory": "512", "executionRoleArn": "arn:aws:iam::ACCOUNT:role/ecsTaskExecutionRole", "containerDefinitions": [ { "name": "admorph-frontend", "image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/admorph-frontend:latest", "portMappings": [ { "containerPort": 3000, "protocol": "tcp" } ], "environment": [ { "name": "NEXT_PUBLIC_API_URL", "value": "https://your-api-domain.com" } ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/ecs/admorph-frontend", "awslogs-region": "us-east-1", "awslogs-stream-prefix": "ecs" } } } ] } -
Register task definition:
aws ecs register-task-definition --cli-input-json file://task-definition.json
-
Create service:
aws ecs create-service \ --cluster admorph-cluster \ --service-name admorph-frontend-service \ --task-definition admorph-frontend \ --desired-count 1 \ --launch-type FARGATE \ --network-configuration "awsvpcConfiguration={subnets=[subnet-12345],securityGroups=[sg-12345],assignPublicIp=ENABLED}"
Update .env.production:
NEXT_PUBLIC_API_URL=https://your-api-domain.com
NEXT_PUBLIC_WS_URL=wss://your-ws-domain.com
NEXT_PUBLIC_AWS_REGION=us-east-1
NEXT_PUBLIC_S3_BUCKET_NAME=your-production-bucket
NEXT_PUBLIC_NODE_ENV=production-
Build Docker image:
docker build -t admorph-frontend . -
Run container:
docker run -p 3000:3000 admorph-frontend
-
With environment variables:
docker run -p 3000:3000 \ -e NEXT_PUBLIC_API_URL=http://localhost:8000 \ -e NEXT_PUBLIC_WS_URL=ws://localhost:8001 \ admorph-frontend
-
Start services:
docker-compose up --build
-
Run in background:
docker-compose up -d --build
-
Stop services:
docker-compose down
-
Build production image:
docker build -t admorph-frontend:production . -
Run with production environment:
docker run -p 3000:3000 \ --env-file .env.production \ admorph-frontend:production
NEXT_AdMorph.AI/
├── app/ # Next.js app directory
│ ├── globals.css # Global styles
│ ├── layout.tsx # Root layout
│ └── page.tsx # Home page
├── components/ # React components
│ ├── ui/ # Base UI components
│ ├── ad-gallery.tsx # Ad gallery component
│ ├── chat-interface.tsx # Chat interface
│ ├── processing-panel.tsx # Processing panel
│ ├── sidebar.tsx # Navigation sidebar
│ ├── upload-interface.tsx # File upload
│ └── voice-*.tsx # Voice components
├── lib/ # Utility libraries
│ ├── api.ts # API client
│ ├── services.ts # Service layer
│ ├── config.ts # Configuration
│ └── utils.ts # Utilities
├── public/ # Static assets
├── scripts/ # Deployment scripts
│ ├── install_dependencies.sh
│ ├── start_server.sh
│ └── stop_server.sh
├── styles/ # Stylesheets
├── .env.example # Environment template
├── .env.local # Local environment (not committed)
├── .env.production # Production environment
├── Dockerfile # Docker configuration
├── docker-compose.yml # Docker Compose configuration
├── buildspec.yml # AWS CodeBuild specification
├── appspec.yml # AWS CodeDeploy specification
├── next.config.mjs # Next.js configuration
├── package.json # Dependencies and scripts
└── README.md # This file
The application uses a layered architecture:
- API Client (
lib/api.ts): Low-level HTTP and WebSocket client - Services (
lib/services.ts): Business logic and data transformation - Components: UI components that consume services
-
Add to API client:
// lib/api.ts async patch<T>(endpoint: string, data?: any): Promise<ApiResponse<T>> { return this.request<T>(endpoint, { method: 'PATCH', body: data ? JSON.stringify(data) : undefined, }); }
-
Add to service layer:
// lib/services.ts export const newService = { async updatePartial(id: string, data: Partial<Entity>): Promise<Entity> { const response = await apiClient.patch<Entity>(`/entities/${id}`, data); return response.data; } };
-
Use in components:
import { newService } from '@/lib/services'; const handleUpdate = async () => { const updated = await newService.updatePartial(id, { status: 'active' }); // Handle response };
The API client includes automatic error handling:
try {
const data = await adService.getAds();
} catch (error) {
console.error('Failed to fetch ads:', error);
// Handle error in UI
}Implement loading states in components:
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const fetchData = async () => {
setLoading(true);
setError(null);
try {
const data = await adService.getAds();
// Handle success
} catch (err) {
setError(err instanceof Error ? err.message : 'An error occurred');
} finally {
setLoading(false);
}
};-
Environment variables not loading:
# Ensure variables are prefixed with NEXT_PUBLIC_ # Restart development server after changes pnpm dev
-
Build failures:
# Clear Next.js cache rm -rf .next # Reinstall dependencies rm -rf node_modules pnpm-lock.yaml pnpm install # Check TypeScript errors pnpm type-check
-
Docker build issues:
# Clean Docker cache docker system prune -a # Rebuild without cache docker build --no-cache -t admorph-frontend .
-
API connection issues:
# Check if backend is running curl http://localhost:8000/health # Verify environment variables echo $NEXT_PUBLIC_API_URL
-
WebSocket connection failures:
# Check WebSocket URL format # Ensure ws:// for development, wss:// for production # Verify backend WebSocket server is running
-
Hot reload not working:
# Restart development server pnpm dev # Check for TypeScript errors pnpm type-check
-
Styling issues:
# Ensure Tailwind classes are correct # Check for conflicting CSS # Verify component imports
-
Component not rendering:
# Check console for errors # Verify component exports # Check for missing dependencies
-
Enable debug logging:
// Add to lib/config.ts export const DEBUG = process.env.NODE_ENV === 'development'; // Use in components if (DEBUG) console.log('Debug info:', data);
-
Network debugging:
# Check network requests in browser dev tools # Verify API responses # Check for CORS issues
-
Performance debugging:
# Analyze bundle size pnpm analyze # Check for memory leaks # Use React DevTools Profiler
-
Check logs:
- Browser console for client-side errors
- Server logs for API issues
- Docker logs for container issues
-
Verify configuration:
- Environment variables are correct
- API endpoints are accessible
- Network connectivity is available
-
Test components individually:
- Isolate problematic components
- Test API calls separately
- Verify data flow
For additional support, check the component documentation in the respective files or consult the Next.js documentation.