Skip to content

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:

  1. Model Compression

  2. GLTF/GLB format (efficient binary)

  3. Draco compression for geometry
  4. Texture atlasing

  5. Lazy Loading

// Load 3D model only when in viewport
const Avatar3D = lazy(() => import('@/components/Avatar3D'))

<Suspense fallback={<AvatarSkeleton />}>
  <Avatar3D avatarId={id} />
</Suspense>
  1. Level of Detail (LOD)

  2. Multiple model versions (high/medium/low poly)

  3. Switch based on camera distance

  4. Frame Rate Optimization

    useFrame((state, delta) => {
      // Limit updates to 30fps for complex scenes
      if (delta > 1 / 30) {
        mixer.update(delta);
      }
    });
    


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 variants
  • Input.tsx - Text, password, email inputs
  • Card.tsx - Container component
  • Modal.tsx - Overlay dialogs
  • Dropdown.tsx - Select menus
  • Toast.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 sidebar
  • Navbar.tsx - Top navigation
  • StatCard.tsx - Metrics display
  • ChatbotCard.tsx - Chatbot preview
  • AnalyticsChart.tsx - Data visualization

3. Chat Interface Components (components/ChatInterface/)

  • ChatWindow.tsx - Main chat container
  • MessageBubble.tsx - Chat message display
  • InputBar.tsx - Message input
  • TypingIndicator.tsx - "Bot is typing..."
  • VoiceControls.tsx - Voice chat UI

4. Form Components (components/Forms/)

  • ChatbotForm.tsx - Create/edit chatbot
  • LoginForm.tsx - Authentication
  • ProfileForm.tsx - User profile
  • BillingForm.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 deployment
  • service.yaml - Load balancer service
  • ingress.yaml - External traffic routing
  • configmap.yaml - Environment variables
  • secrets.yaml - Sensitive data

CI/CD Pipeline

GitHub Actions (.github/workflows/)

Build & Deploy Flow:

  1. Run tests (npm test)
  2. Lint code (npm run lint)
  3. Build Docker image
  4. Push to container registry
  5. 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

- 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."