Skip to main content

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​

  1. Default to Server Components: Keep components in the server environment unless user interactivity (e.g. useState, useEffect, onClick, onChange) is strictly required.
  2. 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").
  3. 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 bcryptjs with 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.timingSafeEqual to 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/*.json and src/messages/es/*.json.
  • Navigation Primitives: Always import Link, useRouter, and usePathname from @/i18n/navigation to preserve active language prefixes automatically.