Architecture Overview
Fullstack SSR architecture for Evensiva Technologies — Next.js 16 App Router, PostgreSQL, Prisma, NextAuth.js, MUI v6, @mui/material-nextjs v7.
Overview
Evensiva Technologies (evensiva.com) is a fullstack web application built with Next.js 16 App Router. The project was migrated from a Vite + React SPA to a server-rendered Next.js application for SEO, performance, and the ability to handle backend logic (database, authentication, API routes) within a single codebase.
Branding in the UI: The global header (Banner) and footer (Footer) show SiteLogo (/Logo.png) beside a two-line wordmark — Evensiva on the first line and TECHNOLOGIES in small caps on the second (same pattern in the mobile drawer). Together this reads Evensiva Technologies. The logo image uses alt="Evensiva Technologies". Root metadata and JSON-LD (JsonLd.tsx) use the same public name. The Banner applies a subtle border and shadow when the user scrolls (scroll listener on window).
The application serves as a company website and digital services portal offering IT training courses, web development services, digital marketing, and an internship program. It includes a public-facing marketing site, a blog with rich content rendering, and a full admin panel for content management.
Vite → Next.js Migration
The original application was a client-side React SPA bootstrapped with Vite, using React Router DOM for client routing and static data embedded in components. The migration involved:
- Framework swap: Vite → Next.js (App Router). Removed
vite.config.ts,index.html,src/main.tsx,src/App.tsx. - Routing: React Router DOM → Next.js file-system routing under
src/app/. - Navigation:
react-router-dom Link→next/linkthroughout all components. - Images: Native
<img>tags →next/imagewith optimized loading, public directory for static assets. - SSR integration: MUI + Emotion configured for server-side rendering via
AppRouterCacheProviderfrom@mui/material-nextjs/v16-appRouter. - TypeScript config: Merged
tsconfig.app.jsonandtsconfig.node.jsoninto a singletsconfig.jsonfor Next.js. - ESLint: Migrated from Vite ESLint config to
eslint-config-nextwith flat config (eslint.config.mjs).
vite.config.ts, index.html, src/main.tsx, src/App.tsx, src/App.css, src/vite-env.d.ts, tsconfig.app.json, tsconfig.node.json.Tech Stack
| Layer | Technology | Purpose |
|---|---|---|
| Framework | Next.js 16 (App Router) | SSR, SSG, file-system routing, API routes; default production compiler is Turbopack |
| Language | TypeScript 5 | Type safety across frontend and backend |
| UI Library | MUI v6 + Emotion + @mui/material-nextjs v7 | Component library with SSR-compatible styling; Next adapter supplies AppRouterCacheProvider |
| Database | PostgreSQL (Neon) | Serverless Postgres for posts, courses, contacts, users; project provisioned for Evensiva |
| ORM | Prisma 6 | Type-safe database access, migrations, seeding |
| Authentication | NextAuth.js v5 (Auth.js) | JWT sessions, Credentials + optional Google/GitHub OAuth, role-based access; auth.config.ts for Edge middleware, auth.ts for DB-backed providers |
| Forms | React Hook Form + Zod | Form state management and validation |
| Icons | MUI Icons + Lucide React | Icon sets for UI components |
| Rich Content | DOMPurify + PrismJS + html-react-parser | Sanitized HTML rendering with syntax highlighting |
| Deployment | Vercel | Edge hosting, serverless functions, CI/CD |
Project Structure
evensiva_frontend_app/
├── docs/ # Project documentation (this folder)
│ ├── features/ # Feature-specific docs (markdown)
│ ├── setup/ # Setup and deployment guides (HTML)
│ ├── archive/ # Historical migration docs
│ └── documentation-index.json # Manifest for all docs
├── prisma/
│ ├── schema.prisma # Database schema (User, Post, Course, Contact)
│ └── seed.ts # Database seed script
├── public/ # Static assets (case-sensitive URLs on Linux)
│ ├── Images/ # slider/, services/, courses/, docs/ (screenshots)
│ ├── PDFs/ # Downloadable PDFs
│ └── Logo.png # Brand + root metadata icon (`/Logo.png`)
├── src/
│ ├── app/ # Next.js App Router pages
│ │ ├── layout.tsx # Root layout: flex column body, main flex:1, ThemeRegistry, Banner, Footer, SEO
│ │ ├── page.tsx # Home route: metadata + HomePageContent
│ │ ├── HomePageContent.tsx # Home page UI (client; MUI + next/link CTAs)
│ │ ├── globals.css # Global styles
│ │ ├── about/ # About Us page
│ │ ├── contact/ # Contact form page
│ │ ├── courses/ # Courses listing
│ │ ├── documentation/ # Marketing documentation hub (/documentation)
│ │ ├── docs/ # Project docs index + file server for repo `docs/` tree
│ │ ├── help/ # Help center with FAQ
│ │ ├── internship/ # Internship program page
│ │ ├── posts/ # Blog listing + [slug] detail
│ │ ├── services/ # Services overview (RoutableTabs) + subpages
│ │ ├── admin/ # Admin panel (protected)
│ │ │ ├── layout.tsx # Admin layout with sidebar
│ │ │ ├── page.tsx # Dashboard with stats
│ │ │ ├── login/ # Admin login
│ │ │ ├── signup/ # Admin signup
│ │ │ ├── posts/ # Posts CRUD
│ │ │ ├── courses/ # Courses CRUD
│ │ │ └── contacts/ # Contact submissions
│ │ ├── api/ # API routes
│ │ │ ├── auth/[...nextauth] # NextAuth handler
│ │ │ ├── auth/register/ # Admin signup endpoint
│ │ │ ├── contact/ # Contact form API
│ │ │ ├── posts/ # Posts API (CRUD)
│ │ │ └── courses/ # Courses API (CRUD)
│ │ ├── sitemap.ts # Dynamic sitemap generation
│ │ └── robots.ts # robots.txt generation
│ ├── components/
│ │ ├── layouts/ # Banner (nav) and Footer — SiteLogo + Evensiva / TECHNOLOGIES wordmark
│ │ ├── features/ # Service feature components
│ │ ├── common/ # Shared components
│ │ │ ├── SiteLogo/ # Brand image from `public/Logo.png`
│ │ │ ├── RichContent/ # HTML renderer with Prism
│ │ │ ├── RoutableTabs/ # URL-synced tabs
│ │ │ ├── ArticleToc/ # Article TOC sidebar
│ │ │ ├── ImageSlider/ # Homepage carousel
│ │ │ ├── CourseCard/ # Course display card
│ │ │ ├── ServicesCards/ # Service display cards
│ │ │ ├── SocialMediaCard/ # Social links
│ │ │ └── GradientBox/ # Styled gradient container
│ │ ├── providers/ # ThemeRegistry, AuthProvider
│ │ ├── admin/ # Admin-specific components
│ │ ├── ContactForm/ # Contact form with API submission
│ │ └── JsonLd.tsx # JSON-LD structured data helpers
│ ├── lib/
│ │ ├── prisma.ts # Prisma client singleton
│ │ ├── auth.config.ts # Edge-safe NextAuth options (middleware; no Prisma)
│ │ ├── auth.ts # NextAuth + Credentials (Prisma/bcrypt) for API routes
│ │ └── utils.ts # Utility functions (slugify, formatDate)
│ └── types/
│ └── index.ts # Shared TypeScript types
├── middleware.ts # Edge auth for /admin/* (uses auth.config only)
├── next.config.ts # Next.js configuration
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
└── .env.local # Environment variables (not committed)
Rendering Strategy
The application uses Next.js App Router's default rendering strategy: Server Components by default, with "use client" directives only where client-side interactivity is required.
| Route | Rendering | Reason |
|---|---|---|
/, /about, /contact | Static (SSG) | Content doesn't change often; generated at build time |
/posts, /courses | Static with revalidation | Fetches from DB at build, revalidates on deploy |
/posts/[slug] | Dynamic (SSR) | Dynamic route; generates metadata per post |
/admin/* | Dynamic (SSR) | Auth-gated; always fresh data |
/api/* | Serverless functions | API endpoints for CRUD operations |
/sitemap.xml, /robots.txt | Dynamic | Generated from DB content |
Client vs Server Components
Components are Server Components by default. The "use client" directive is added only when a component uses:
- React hooks (
useState,useEffect,useRef, etc.) - Event handlers (
onClick,onChange, etc.) - Browser APIs (
window,document,localStorage) - MUI
styledoruseTheme(which use Emotion context) - Next.js client hooks (
useRouter,usePathname,useSearchParams) - MUI +
next/linkas component — Passingcomponent={NextLink}(or similar) from a Server Component to MUI violates serialization rules in Next.js 16; the affected UI lives in Client Components (e.g.HomePageContent, service feature sections).
Client components in this project
| Component | Reason for "use client" |
|---|---|
| Banner, Footer | Event handlers (drawer, menu), useMediaQuery, useState; Banner also useEffect scroll listener for elevated app bar; global brand lockup (SiteLogo + two-line wordmark) |
| ThemeRegistry | ThemeProvider, AppRouterCacheProvider (@mui/material-nextjs/v16-appRouter) |
| HomePageContent | MUI buttons with component={NextLink}; keeps page.tsx as a Server Component for metadata |
| Internship, ITTraining, DigitalMarketing, WebDevelopment | Same next/link + MUI pattern; marked "use client" |
| ImageSlider | useState + useEffect for carousel timer |
| ContactForm | Form state, API submission, useState |
| PostsClient | Category filtering with useState |
| AboutContent | MUI styled component |
| RichContent | DOMPurify, Prism, copy buttons, DOM manipulation |
| RoutableTabs | useSearchParams, useRouter for URL sync |
| ArticleTocSidebar | useTheme for dynamic styling |
| AdminSidebar | usePathname, useSession, sign-out action |
| PostForm, CourseForm | Full form state management |
| LoginForm, SignupForm | useSearchParams, form validation, NextAuth signIn, optional OAuth actions |
Routing
Next.js App Router uses file-system routing. Each page.tsx under src/app/ becomes a route.
Public routes (selected)
/ → Home page
/about → About Us
/contact → Contact form
/courses → Course listing
/documentation → Marketing documentation hub (links to services, /docs, help)
/docs → Project documentation index (technical HTML guides)
/docs/* → Served files from repo `docs/` (e.g. setup/*.html)
/help → Help center (FAQ)
/internship → Internship program
/posts → Blog listing
/posts/[slug] → Individual blog post (dynamic)
/services → Services overview (RoutableTabs)
/services/training → IT Training
/services/digital → Digital Marketing
/services/webdevelopment → Web Development
/admin → Admin dashboard
/admin/login → Admin login
/admin/signup → Admin signup
/admin/posts → Manage posts
/admin/posts/new → Create post
/admin/posts/[id]/edit → Edit post
/admin/courses → Manage courses
/admin/courses/new → Create course
/admin/courses/[id]/edit → Edit course
/admin/contacts → View contact submissions
/api/auth/[...nextauth] → NextAuth handler
/api/auth/register → Signup API (create user)
/api/contact → Contact API
/api/posts → Posts API
/api/posts/[id] → Single post API
/api/courses → Courses API
/api/courses/[id] → Single course API
/sitemap.xml → Dynamic sitemap
/robots.txt → Robots file
Data Flow
The application follows a clean data flow pattern:
- Server Components fetch data directly from Prisma (no API round-trip). Example:
src/app/posts/page.tsxcallsprisma.post.findMany()in the component body. - API Routes are used by the admin panel (client components) for CRUD operations via
fetch('/api/posts'). - Static fallback: Public pages (posts, courses) include hardcoded fallback data so the site renders even without a database connection.
- Validation: API routes use Zod schemas for input validation before database writes.
Browser → Server Component → Prisma → PostgreSQL (public pages)
Browser → Client Component → fetch() → API Route → Prisma → PostgreSQL (admin CRUD)
Browser → Server Component → Static fallback data (no DB available)
UI shell, layout, and spacing
Page shell: src/app/layout.tsx gives <body> an inline flex column with minHeight: 100vh and wraps route children in <Box component="main" sx={{ flex: 1 }}> (MUI Box) so the footer stays at the bottom when content is shorter than the viewport.
Spacing and UX: Marketing pages use consistent MUI sx spacing (section py, chip-to-heading gaps, card padding). Cards and buttons use shared motion patterns (e.g. cubic-bezier(0.4,0,0.2,1) transitions, hover lift). The services overview page (/services) uses top padding only on the outer container so vertical padding does not stack with the tab panels’ feature sections (each feature component already sets its own py). The contact route renders <ContactForm /> directly (no extra wrapper div).
Styling
The application uses MUI v6 with Emotion for component styling, integrated with Next.js SSR via @mui/material-nextjs v7 (import AppRouterCacheProvider from @mui/material-nextjs/v16-appRouter for Next.js 16).
- ThemeRegistry (
src/components/providers/ThemeRegistry.tsx): Wraps the app withAppRouterCacheProviderandThemeProviderto ensure Emotion styles are extracted during SSR and injected correctly. - Global CSS (
src/app/globals.css): Reset styles, font settings, and RichContent copy button styles. - Component styles: MUI
sxprop for most styling;styled()API for reusable styled components (GradientBox, AboutContent).
Build & Output
The project builds with next build (Next.js 16 uses Turbopack for production builds unless you pass --webpack). Output includes:
- Static pages (○): Pre-rendered at build time (home, about, contact, courses, posts listing, documentation, help, services).
- Dynamic pages (ƒ): Server-rendered on demand (post detail, admin pages, API routes).
- Shared JS: First-load shared bundle size varies by Next.js release; inspect build output after upgrades.
npm run build # Runs: next build (Turbopack by default in v16)
npm run dev # Runs: next dev (development server)
npm run start # Runs: next start (production server)
npm run lint # Runs: next lint
Note: On some Windows environments, next lint may fail with an invalid project directory; run ESLint from the project root (for example npx eslint .) or use your editor integration.