Skip to content

Frontend Architecture

Overview

The frontend is a modern React application built with TypeScript, Vite, and Tailwind CSS.

Technology Stack

  • Framework: React 18
  • Language: TypeScript
  • Build Tool: Vite
  • Styling: Tailwind CSS
  • UI Components: shadcn/ui (Radix UI primitives)
  • Routing: Wouter
  • State Management: TanStack Query
  • Icons: Lucide React

Project Structure

client/
├── src/
│   ├── components/       # Reusable UI components
│   │   ├── ui/          # shadcn/ui components
│   │   ├── hero-section.tsx
│   │   ├── navigation.tsx
│   │   └── ...
│   ├── pages/           # Page components
│   │   ├── home.tsx
│   │   ├── about.tsx
│   │   ├── projects.tsx
│   │   └── contact.tsx
│   ├── hooks/           # Custom React hooks
│   ├── lib/             # Utility functions
│   ├── assets/          # Images and static files
│   ├── App.tsx          # Main app component
│   └── main.tsx         # Entry point
├── public/              # Static assets
└── index.html           # HTML template

Key Features

Component Architecture

  • Atomic Design: Components organized by complexity
  • Composition: Reusable, composable components
  • Type Safety: Full TypeScript coverage

Routing

import { Route, Switch } from "wouter";

<Switch>
  <Route path="/" component={Home} />
  <Route path="/about" component={About} />
  <Route path="/projects" component={Projects} />
  <Route path="/projects/:id" component={ProjectDetail} />
  <Route path="/contact" component={Contact} />
  <Route component={NotFound} />
</Switch>

Navigation behaviour (navigation.tsx):

  • On the home page (/): nav items use anchor-scroll (<a href="#section">) so clicking a link smoothly scrolls to the section without a full route change.
  • On sub-pages (/about, /projects, etc.): nav items use wouter <Link> to navigate back to / (which renders the home sections). Using anchor-scroll on a sub-page would produce a broken #section fragment with no matching element.

API Request Routing

All API calls from the frontend use relative paths (e.g., /api/contact). There is no hardcoded backend host in the client code.

Environment How /api/* is resolved
Development Vite dev server proxies /api/http://localhost:8000 (configured in vite.config.ts)
Production nginx proxies /api/ → the backend container on the internal network (configured in nginx.default.conf.template)

This means the frontend container image is environment-agnostic — the same build artifact works in dev and prod without rebuilding.

State Management

  • TanStack Query: Server state management
  • React Context: Theme and global state
  • Local State: Component-specific state with hooks

Styling

  • Tailwind CSS: Utility-first CSS
  • CSS Variables: Theme customization
  • Dark Mode: Full dark/light theme support
  • OneDNA Branding: Pink accent colors

Build Process

Development

npm run dev
# Vite dev server on port 5173

Production

npm run build
# Outputs to dist/

Docker Build

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf

Performance Optimization

  • Code Splitting: Lazy loading for routes
  • Tree Shaking: Unused code elimination
  • Asset Optimization: Image compression
  • Bundle Analysis: Regular bundle size monitoring

See Also