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#sectionfragment 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¶
Production¶
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