Architecture & Coding Conventions
To ensure long-term maintainability, security, and developer velocity across the HiTech Insurance codebase, all engineering contributors must adhere to the standardized architecture patterns and conventions documented below.
1. Directory Structure & Layer Responsibilities
The codebase enforces strict separation of concerns across directory boundaries:
src/
├── app/ # Next.js App Router (Routes, Layouts, Metadata, API Handlers)
│ ├── [locale]/ # Localized route hierarchy (en / es)
│ └── api/ # RESTful API route handlers
├── components/ # Reusable React components
│ ├── common/ # Universal UI primitives (buttons, modals, inputs, loaders)
│ ├── feature/ # Domain-specific components (blog, admin, insurance, forms)
│ └── seo/ # JSON-LD structured data components
├── config/ # Static platform configurations (metadata, menus, constants)
├── hooks/ # Custom React client hooks (useDebounce, usePresence, etc.)
├── i18n/ # next-intl configuration, routing, and navigation helpers
├── lib/ # Shared utilities, database connections, schemas, and security
│ ├── db/ # Mongoose singleton and 40 model definitions
│ ├── email/ # Email templates and dispatchers
│ └── seo/ # Schema builders and metadata generators
├── messages/ # 34 bilingual JSON translation catalogs (en / es)
├── server/actions/ # Next.js Server Actions (mutations, pagination, admin logic)
├── services/ # Centralized business logic (MetaDataService, CrmService)
└── types/ # TypeScript interfaces, enums, and API payloads
2. Server Action Conventions
All Server Actions located in src/server/actions/ must follow consistent standards:
1. Mandatory Directives & Authentication Guards
Always place "use server"; at the top of the file. Privileged actions must invoke authentication guards immediately prior to executing any database operation:
"use server";
import { connectDB } from "@/lib/db/mongoose";
import { Blog, IBlog } from "@/lib/db/models/Blog";
import { requireAdmin } from "@/lib/auth-helpers";
import { revalidatePath } from "next/cache";
export async function createBlog(data: Partial<IBlog>) {
// 1. Enforce Role-Based Access Control
await requireAdmin();
// 2. Reuse Cached Database Connection
await connectDB();
try {
// 3. Perform Business Logic & Mongoose Mutation
const newBlog = await Blog.create(data);
// 4. Invalidate Stale Route Caches
revalidatePath("/blog");
revalidatePath("/admin");
// 5. Return Serialized Data
return {
success: true,
data: JSON.parse(JSON.stringify(newBlog))
};
} catch (error: any) {
console.error("Error creating blog:", error);
return { success: false, error: error.message };
}
}
2. Standardized Return Envelopes
Never allow unhandled exceptions to crash the client. Actions must return a standardized status envelope:
- Success:
{ success: true, data: T, message?: string } - Failure:
{ success: false, error: string, code?: string }
3. Serialization Safety
Mongoose documents contain internal circular references and prototype methods that cannot cross the React Server Component serialization boundary. Always sanitize documents using .lean() or JSON.parse(JSON.stringify(doc)).
3. Mongoose Defensive Model Pattern
Next.js App Router hot-reloads modules frequently during development. To prevent Mongoose from throwing OverwriteModelError: Cannot overwrite 'ModelName' model once compiled, all 40 models in src/lib/db/models/ must use the defensive compilation guard:
import { Schema, model, models, Model } from "mongoose";
export interface IExample {
title: string;
isActive: boolean;
}
const ExampleSchema = new Schema<IExample>(
{
title: { type: String, required: true },
isActive: { type: Boolean, default: true },
},
{ timestamps: true }
);
// Defensive Compilation Singleton
export const Example: Model<IExample> =
models.Example || model<IExample>("Example", ExampleSchema);
4. Client vs. Server Component Boundaries
- Default to Server Components: Keep components in the server environment unless user interactivity (e.g.
useState,useEffect,onClick,onChange) is strictly required. - Push Interactivity to the Leaves: Structure pages so that data fetching happens in parent Server Components, passing serialized data down to small, focused Client Components (
"use client"). - Never Import Database Models in Client Components: Importing Mongoose or server libraries in client files leaks database connection code and triggers compilation errors.
5. Input Validation & Security Standards
- Strict Zod Schemas: Every public API route and form submission must parse and validate request payloads against a Zod schema before processing.
- Password Hashing: User passwords must be hashed using
bcryptjswith a minimum salt factor of 10 rounds. Raw passwords must never be logged or stored. - Timing-Safe HMAC Verification: Partner API signatures must be verified using
crypto.timingSafeEqualto eliminate timing side-channel attacks. - No Hardcoded Copy: Never hardcode user-facing strings in JSX components. All text must be declared in
src/messages/en/*.jsonandsrc/messages/es/*.json. - Navigation Primitives: Always import
Link,useRouter, andusePathnamefrom@/i18n/navigationto preserve active language prefixes automatically.