Frontend Application Documentation¶
Purpose: Complete documentation of MachineAvatars Next.js frontend application
Audience: Frontend Developers, UI/UX Team, Technical Auditors
Owner: Frontend Lead
Last Updated: 2025-12-29
Version: 2.0
Executive Summary¶
MachineAvatars frontend is a Next.js 14 application built with React 18, featuring cutting-edge 3D avatar rendering using Three.js, real-time chat interfaces, and comprehensive dashboard management. The application emphasizes performance, user experience, and maintainability.
Key Technologies:
- ✅ Next.js 14.1.6 - App Router, Server Components, API Routes
- ✅ React 18.2.0 - Modern React with Hooks, Context API
- ✅ Three.js 0.171.0 - 3D avatar rendering
- ✅ TypeScript 5 - Type-safe development
- ✅ Tailwind CSS 3.4 - Utility-first styling
- ✅ Material-UI 7.3 - Component library
- ✅ Framer Motion 12.6 - Advanced animations
Architecture Overview¶
Technology Stack¶
graph TB
A[Next.js 14 App Router] --> B[React 18 Components]
B --> C[UI Layer]
B --> D[3D Rendering]
B --> E[State Management]
C --> F[Tailwind CSS]
C --> G[Material-UI]
C --> H[Framer Motion]
D --> I[Three.js]
D --> J[@react-three/fiber]
D --> K[@react-three/drei]
E --> L[Context API]
E --> M[React Hooks]
style A fill:#4CAF50
style D fill:#FF9800
style E fill:#2196F3
Directory Structure¶
machineagents-fe/
├── src/
│ ├── app/ # Next.js 14 App Router (179 files)
│ │ ├── (auth)/ # Authentication routes
│ │ │ ├── login/
│ │ │ ├── register/
│ │ │ └── forgot-password/
│ │ ├── dashboard/ # Main dashboard
│ │ │ ├── chatbots/
│ │ │ ├── analytics/
│ │ │ ├── settings/
│ │ │ └── billing/
│ │ ├── chatbot/ # Chatbot interfaces
│ │ │ ├── [id]/ # Dynamic chatbot routes
│ │ │ ├── 3d/
│ │ │ ├── text/
│ │ │ └── voice/
│ │ ├── api/ # API routes (Next.js)
│ │ ├── layout.tsx # Root layout
│ │ ├── page.tsx # Homepage
│ │ └── globals.css # Global styles
│ │
│ ├── components/ # Reusable components (19 files)
│ │ ├── Avatar3D/ # 3D avatar components
│ │ ├── ChatInterface/ # Chat UI components
│ │ ├── Dashboard/ # Dashboard widgets
│ │ ├── Forms/ # Form components
│ │ └── ui/ # Shared UI components
│ │
│ ├── contexts/ # React Context providers (1 file)
│ │ └── AuthContext.tsx # Global auth state
│ │
│ ├── hooks/ # Custom React hooks (5 files)
│ │ ├── useAuth.ts
│ │ ├── useChatbot.ts
│ │ ├── useWebSocket.ts
│ │ ├── use3DRenderer.ts
│ │ └── useAnalytics.ts
│ │
│ ├── lib/ # Utility libraries (1 file)
│ │ └── utils.ts
│ │
│ ├── server/ # Server-side code (3 files)
│ │ ├── actions/ # Server Actions
│ │ └── api/ # API utils
│ │
│ ├── utils/ # Client utilities (3 files)
│ │ ├── api.ts # API client
│ │ ├── validation.ts # Form validation
│ │ └── formatters.ts # Data formatters
│ │
│ └── middleware.ts # Next.js middleware (auth, redirects)
│
├── public/ # Static assets (71 files)
│ ├── avatars/ # 3D avatar models
│ ├── images/
│ ├── fonts/
│ └── icons/
│
├── k8s-manifests/ # Kubernetes deployment configs
├── .github/ # GitHub Actions CI/CD
│
├── next.config.js # Next.js configuration
├── tailwind.config.ts # Tailwind CSS config
├── tsconfig.json # TypeScript config
├── package.json # Dependencies
└── Dockerfile # Containerization
Total Structure:
- 212 source files in
src/ - 71 public assets
- 179 app route files (pages, layouts, components)
- 19 reusable components
Core Dependencies¶
Production Dependencies¶
| Package | Version | Purpose |
|---|---|---|
| next | 14.1.6 | React framework with App Router |
| react | 18.2.0 | UI library |
| react-dom | 18.2.0 | React DOM renderer |
| three | 0.171.0 | 3D graphics library |
| @react-three/fiber | 8.17.10 | React renderer for Three.js |
| @react-three/drei | 9.122.0 | Three.js helpers and abstractions |
| typescript | 5 | Type-safe JavaScript |
| tailwindcss | 3.4.1 | Utility-first CSS framework |
| @mui/material | 7.3.0 | Material Design components |
| @emotion/react | 11.14.0 | CSS-in-JS for Material-UI |
| framer-motion | 12.6.2 | Animation library |
| axios | 1.10.0 | HTTP client |
| recharts | 2.15.3 | Charting library (analytics) |
| react-toastify | 11.0.5 | Toast notifications |
| react-spinners | 0.15.0 | Loading spinners |
| react-icons | 5.4.0 | Icon library |
| lucide-react | 0.511.0 | Modern icon system |
| posthog-js | 1.261.0 | Product analytics |
| leva | 0.9.35 | GUI controls for 3D debugging |
| sass | 1.85.0 | CSS preprocessor |
Application Architecture¶
Next.js App Router Structure¶
App Router Benefits:
- ✅ Server Components - Default server rendering
- ✅ Streaming - Instant page loads with Suspense
- ✅ Layouts - Shared UI across routes
- ✅ Loading States - Built-in loading.tsx
- ✅ Error Handling - Built-in error.tsx
Route Organization:
// app/layout.tsx - Root Layout
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<AuthProvider>
<Navbar />
{children}
<Footer />
</AuthProvider>
</body>
</html>
);
}
// app/dashboard/layout.tsx - Dashboard Layout
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex">
<Sidebar />
<main className="flex-1">{children}</main>
</div>
);
}
State Management Strategy¶
No Redux/Zustand - Using React Built-Ins:
1. Context API for Global State¶
// src/contexts/AuthContext.tsx
export const AuthContext = createContext<AuthContextType>({
user: null,
login: async () => {},
logout: async () => {},
isAuthenticated: false,
});
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const login = async (email: string, password: string) => {
const response = await api.post("/auth/login", { email, password });
setUser(response.data.user);
localStorage.setItem("token", response.data.access_token);
};
const logout = async () => {
await api.post("/auth/logout");
setUser(null);
localStorage.removeItem("token");
router.push("/login");
};
return (
<AuthContext.Provider
value={{ user, login, logout, isAuthenticated: !!user }}
>
{children}
</AuthContext.Provider>
);
}
2. Custom Hooks for Feature State¶
// src/hooks/useChatbot.ts
export function useChatbot(chatbotId: string) {
const [chatbot, setChatbot] = useState<Chatbot | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
async function fetchChatbot() {
try {
setLoading(true);
const response = await api.get(`/chatbots/${chatbotId}`);
setChatbot(response.data);
} catch (err) {
setError("Failed to load chatbot");
} finally {
setLoading(false);
}
}
fetchChatbot();
}, [chatbotId]);
return { chatbot, loading, error };
}
// Usage in components:
function ChatbotPage({ params }: { params: { id: string } }) {
const { chatbot, loading, error } = useChatbot(params.id);
if (loading) return <Spinner />;
if (error) return <ErrorMessage message={error} />;
return <ChatbotInterface chatbot={chatbot} />;
}
3. Server State via Server Components¶
// app/dashboard/chatbots/page.tsx (Server Component)
async function getChatbots(userId: string) {
const response = await fetch(`${API_URL}/chatbots/user/${userId}`, {
cache: "no-store", // or 'force-cache' for static
});
return response.json();
}
export default async function ChatbotsPage() {
const chatbots = await getChatbots("user_123");
return (
<div>
<h1>Your Chatbots</h1>
<ChatbotGrid chatbots={chatbots} />
</div>
);
}
3D Avatar Rendering¶
Three.js Integration¶
Core Libraries:
- three - Base 3D library
- @react-three/fiber - React renderer for Three.js
- @react-three/drei - Helper components (OrbitControls, Environment, etc.)
3D Avatar Component Architecture¶
// components/Avatar3D/Avatar3DRenderer.tsx
import { Canvas } from "@react-three/fiber";
import { OrbitControls, Environment, useGLTF } from "@react-three/drei";
export function Avatar3DRenderer({
avatarUrl,
animation,
cameraPosition = [0, 0, 5],
}: Avatar3DProps) {
return (
<Canvas
camera={{ position: cameraPosition, fov: 50 }}
style={{ width: "100%", height: "100vh" }}
>
{/* Lighting */}
<ambientLight intensity={0.5} />
<spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} />
{/* Environment */}
<Environment preset="studio" />
{/* 3D Model */}
<AvatarModel url={avatarUrl} animation={animation} />
{/* Camera Controls */}
<OrbitControls
enableZoom={false}
enablePan={false}
minPolarAngle={Math.PI / 2.5}
maxPolarAngle={Math.PI / 1.5}
/>
</Canvas>
);
}
function AvatarModel({ url, animation }: { url: string; animation: string }) {
const gltf = useGLTF(url); // Load 3D model
// Animation mixer for avatar animations
const mixer = useMemo(() => new THREE.AnimationMixer(gltf.scene), [gltf]);
useEffect(() => {
if (animation && gltf.animations.length > 0) {
const action = mixer.clipAction(gltf.animations[0]);
action.play();
}
return () => mixer.stopAllAction();
}, [animation, mixer, gltf]);
return <primitive object={gltf.scene} />;
}
3D Performance Optimizations¶
Techniques Used:
-
Model Compression
-
GLTF/GLB format (efficient binary)
- Draco compression for geometry
-
Texture atlasing
-
Lazy Loading
// Load 3D model only when in viewport
const Avatar3D = lazy(() => import('@/components/Avatar3D'))
<Suspense fallback={<AvatarSkeleton />}>
<Avatar3D avatarId={id} />
</Suspense>
-
Level of Detail (LOD)
-
Multiple model versions (high/medium/low poly)
-
Switch based on camera distance
-
Frame Rate Optimization
Routing & Navigation¶
Route Structure¶
| Route | Type | Purpose | Auth Required |
|---|---|---|---|
/ |
Public | Homepage/Landing | No |
/login |
Public | User login | No |
/register |
Public | User registration | No |
/forgot-password |
Public | Password reset | No |
/dashboard |
Protected | Main dashboard | Yes |
/dashboard/chatbots |
Protected | Chatbot management | Yes |
/dashboard/chatbots/create |
Protected | Create chatbot | Yes |
/dashboard/chatbots/[id] |
Protected | Edit chatbot | Yes |
/dashboard/analytics |
Protected | Analytics dashboard | Yes |
/dashboard/settings |
Protected | User settings | Yes |
/dashboard/billing |
Protected | Subscription/billing | Yes |
/chatbot/[id] |
Public | Embedded chatbot | No |
/chatbot/3d/[id] |
Public | 3D chatbot interface | No |
/chatbot/text/[id] |
Public | Text chatbot interface | No |
/chatbot/voice/[id] |
Public | Voice chatbot interface | No |
Middleware (Authentication)¶
// src/middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const token = request.cookies.get("auth_token")?.value;
const isAuthPage =
request.nextUrl.pathname.startsWith("/login") ||
request.nextUrl.pathname.startsWith("/register");
const isProtectedPage = request.nextUrl.pathname.startsWith("/dashboard");
// Redirect to login if accessing protected page without token
if (isProtectedPage && !token) {
return NextResponse.redirect(new URL("/login", request.url));
}
// Redirect to dashboard if logged in and trying to access auth pages
if (isAuthPage && token) {
return NextResponse.redirect(new URL("/dashboard", request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ["/dashboard/:path*", "/login", "/register"],
};
Component Library¶
Design System Structure¶
Component Categories:
1. UI Components (components/ui/)¶
Button.tsx- Primary, secondary, outline variantsInput.tsx- Text, password, email inputsCard.tsx- Container componentModal.tsx- Overlay dialogsDropdown.tsx- Select menusToast.tsx- Notification system
Example:
// components/ui/Button.tsx
export function Button({
variant = "primary",
size = "md",
children,
...props
}: ButtonProps) {
const baseStyles = "rounded-lg font-medium transition-colors";
const variantStyles = {
primary: "bg-blue-600 text-white hover:bg-blue-700",
secondary: "bg-gray-200 text-gray-900 hover:bg-gray-300",
outline: "border-2 border-blue-600 text-blue-600 hover:bg-blue-50",
};
const sizeStyles = {
sm: "px-3 py-1.5 text-sm",
md: "px-4 py-2 text-base",
lg: "px-6 py-3 text-lg",
};
return (
<button
className={`${baseStyles} ${variantStyles[variant]} ${sizeStyles[size]}`}
{...props}
>
{children}
</button>
);
}
2. Dashboard Components (components/Dashboard/)¶
Sidebar.tsx- Navigation sidebarNavbar.tsx- Top navigationStatCard.tsx- Metrics displayChatbotCard.tsx- Chatbot previewAnalyticsChart.tsx- Data visualization
3. Chat Interface Components (components/ChatInterface/)¶
ChatWindow.tsx- Main chat containerMessageBubble.tsx- Chat message displayInputBar.tsx- Message inputTypingIndicator.tsx- "Bot is typing..."VoiceControls.tsx- Voice chat UI
4. Form Components (components/Forms/)¶
ChatbotForm.tsx- Create/edit chatbotLoginForm.tsx- AuthenticationProfileForm.tsx- User profileBillingForm.tsx- Payment details
Styling Approach¶
Tailwind CSS Configuration¶
// tailwind.config.ts
export default {
content: ["./src/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {
colors: {
primary: {
50: "#eff6ff",
500: "#3b82f6",
900: "#1e3a8a",
},
// Custom brand colors
},
fontFamily: {
sans: ["Inter", "sans-serif"],
},
animation: {
"fade-in": "fadeIn 0.3s ease-in",
"slide-up": "slideUp 0.4s ease-out",
},
},
},
plugins: [],
};
CSS Organization¶
Global Styles (app/globals.css):
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
html {
@apply scroll-smooth;
}
body {
@apply bg-gray-50 text-gray-900 antialiased;
}
}
@layer components {
.card {
@apply bg-white rounded-lg shadow-md p-6;
}
.btn {
@apply px-4 py-2 rounded-md transition-colors;
}
}
@layer utilities {
.text-balance {
text-wrap: balance;
}
}
API Integration¶
API Client Setup¶
// src/utils/api.ts
import axios from "axios";
const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL || "https://api.machineavatars.com",
timeout: 15000,
headers: {
"Content-Type": "application/json",
},
});
// Request interceptor (add auth token)
api.interceptors.request.use((config) => {
const token = localStorage.getItem("auth_token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// Response interceptor (handle errors)
api.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
// Token expired, redirect to login
localStorage.removeItem("auth_token");
window.location.href = "/login";
}
return Promise.reject(error);
}
);
export default api;
API Usage Pattern¶
// src/hooks/useAuth.ts
import api from "@/utils/api";
export function useAuth() {
const login = async (email: string, password: string) => {
try {
const response = await api.post("/auth/login", { email, password });
localStorage.setItem("auth_token", response.data.access_token);
return response.data.user;
} catch (error) {
throw new Error("Login failed");
}
};
const register = async (userData: RegisterData) => {
const response = await api.post("/auth/register", userData);
return response.data;
};
return { login, register };
}
Performance Optimization¶
Next.js Optimizations¶
1. Image Optimization¶
import Image from "next/image";
<Image
src="/avatars/avatar_01.png"
alt="Avatar"
width={400}
height={400}
priority // Load immediately for above-the-fold
placeholder="blur" // Show blur while loading
/>;
2. Code Splitting¶
// Automatic route-based code splitting
// Each page is its own bundle
// Manual code splitting with dynamic imports
const HeavyComponent = dynamic(() => import("@/components/HeavyComponent"), {
loading: () => <Spinner />,
ssr: false, // Client-only rendering
});
3. Font Optimization¶
// app/layout.tsx
import { Inter } from "next/font/google";
const inter = Inter({
subsets: ["latin"],
display: "swap",
variable: "--font-inter",
});
export default function RootLayout({ children }) {
return (
<html className={inter.variable}>
<body>{children}</body>
</html>
);
}
React Optimizations¶
1. Memoization¶
import { memo, useMemo, useCallback } from "react";
// Memo for expensive components
const ChatMessage = memo(({ message }: { message: Message }) => {
return <div>{message.content}</div>;
});
// useMemo for expensive calculations
function ChatWindow({ messages }: { messages: Message[] }) {
const sortedMessages = useMemo(() => {
return messages.sort((a, b) => a.timestamp - b.timestamp);
}, [messages]);
return (
<div>
{sortedMessages.map((msg) => (
<ChatMessage key={msg.id} message={msg} />
))}
</div>
);
}
// useCallback for event handlers
function InputBar() {
const sendMessage = useCallback((content: string) => {
api.post("/chat/send", { content });
}, []);
return <input onSubmit={() => sendMessage(value)} />;
}
2. Lazy Loading¶
import { lazy, Suspense } from "react";
const Avatar3D = lazy(() => import("@/components/Avatar3D"));
function ChatbotPage() {
return (
<Suspense fallback={<div>Loading 3D avatar...</div>}>
<Avatar3D />
</Suspense>
);
}
Build Configuration¶
Next.js Config¶
// next.config.js
const nextConfig = {
// TypeScript error handling
typescript: {
ignoreBuildErrors: false, // Set true for CI/CD if needed
},
// Image domains
images: {
domains: ["strapii.demo.machineagents.ai", "localhost"],
remotePatterns: [
{
protocol: "http",
hostname: "localhost",
pathname: "/uploads/**",
},
],
},
// Security headers
async headers() {
return [
{
source: "/(.*)",
headers: [
{
key: "Permissions-Policy",
value: "microphone=(self), camera=(self), autoplay=(self)",
},
{
key: "X-Frame-Options",
value: "SAMEORIGIN",
},
{
key: "X-Content-Type-Options",
value: "nosniff",
},
],
},
];
},
// Redirects
async redirects() {
return [
{
source: "/dashboard/:path*",
destination: "/login",
permanent: false,
// Conditional redirect handled by middleware
},
];
},
// Environment variables
env: {
API_URL: process.env.NEXT_PUBLIC_API_URL,
},
};
export default nextConfig;
Deployment¶
Docker Configuration¶
# Dockerfile
FROM node:20-alpine AS base
# Install dependencies
FROM base AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
# Build application
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Production image
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
CMD ["node", "server.js"]
Kubernetes Deployment¶
Configuration in: k8s-manifests/
Key Manifests:
deployment.yaml- Application deploymentservice.yaml- Load balancer serviceingress.yaml- External traffic routingconfigmap.yaml- Environment variablessecrets.yaml- Sensitive data
CI/CD Pipeline¶
GitHub Actions (.github/workflows/)
Build & Deploy Flow:
- Run tests (
npm test) - Lint code (
npm run lint) - Build Docker image
- Push to container registry
- Deploy to Kubernetes (dev → qa → prod)
Testing Strategy¶
Testing Tools¶
Planned (not yet implemented):
- Jest - Unit testing
- React Testing Library - Component testing
- Cypress/Playwright- E2E testing
Current State:
- Manual QA testing
- Browser compatibility testing
Related Documentation¶
- API Documentation¶
Last Updated: 2025-12-29
Version: 2.0
Owner: Frontend Lead
Review Cycle: Monthly
"Fast, beautiful, and built with cutting-edge web technologies."