Skip to main content

Code Style

UniPulse follows consistent coding conventions across the entire monorepo. TypeScript strict mode is enabled everywhere.


General Principles​

PrincipleDetails
TypeScript everywhereStrict mode enabled in all packages
Functional patternsPrefer functions and objects over classes
Named exportsPrefer named exports over default exports
Absolute importsUse path aliases (@/, @unipulse/shared)
No anyAvoid any type -- use unknown if type is truly unknown
Explicit return typesAdd return types to service functions

Naming Conventions​

ItemConventionExample
Files (services)kebab-case.service.tspost.service.ts, ai-advisor.service.ts
Files (routes)kebab-case.routes.tspost.routes.ts, ab-test.routes.ts
Files (types)kebab-case.types.tspost.types.ts, brand-voice.types.ts
Files (validators)kebab-case.validators.tspost.validators.ts
Files (queues)kebab-case.queue.tspublish.queue.ts
ComponentsPascalCase.tsxPostCard.tsx, DataTable.tsx
Storeskebab-case.store.tsauth.store.ts, ui.store.ts
Hooksuse-kebab-case.tsuse-posts.ts, use-workspace.ts
FunctionscamelCasegetPostById, generateCaption
ConstantsUPPER_SNAKE_CASEMAX_RETRY_COUNT, PROMPT_CONFIGS
Types/InterfacesPascalCaseCreatePostInput, WorkflowNode
EnumsPascalCase (type), UPPER_SNAKE_CASE (values)Role.ADMIN, Platform.FACEBOOK
Database fieldscamelCasecreatedAt, workspaceId
Environment variablesUPPER_SNAKE_CASEDATABASE_URL, JWT_SECRET
Queue nameskebab-caseanalytics-sync, ice-process

File Organization​

RuleDetails
One service per filepost.service.ts contains all post-related business logic
One component per filePostCard.tsx exports a single component
Group by feature domainpages/analytics/, services/analytics.service.ts
Index files for re-exportscomponents/ui/index.ts for barrel exports
Co-locate testsservices/__tests__/post.service.test.ts

Backend Patterns​

Service Pattern​

// apps/api/src/services/example.service.ts
import { prisma } from '../lib/prisma';
import type { CreateExampleInput } from '@unipulse/shared';

export const exampleService = {
async getAll(workspaceId: string): Promise<Example[]> {
return prisma.example.findMany({
where: { workspaceId },
orderBy: { createdAt: 'desc' },
});
},

async create(workspaceId: string, data: CreateExampleInput): Promise<Example> {
return prisma.example.create({
data: { ...data, workspaceId },
});
},
};

Route Pattern​

// apps/api/src/routes/example.routes.ts
import { Router } from 'express';
import { authenticate } from '../middleware/auth';
import { requireWorkspace } from '../middleware/requireWorkspace';
import { validate } from '../middleware/validate';
import { createExampleSchema } from '@unipulse/shared';
import { exampleService } from '../services/example.service';

const router = Router();

router.get('/', authenticate, requireWorkspace('VIEWER'), async (req, res, next) => {
try {
const items = await exampleService.getAll(req.workspace.id);
res.json(items);
} catch (error) {
next(error);
}
});

router.post('/', authenticate, requireWorkspace('EDITOR'), validate(createExampleSchema), async (req, res, next) => {
try {
const item = await exampleService.create(req.workspace.id, req.body);
res.status(201).json(item);
} catch (error) {
next(error);
}
});

export default router;

Frontend Patterns​

Component Pattern​

// apps/web/src/pages/examples/ExampleList.tsx
import { useQuery } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import { DataTable } from '@/components/data-table';
import type { Example } from '@unipulse/shared';

export function ExampleList() {
const { t } = useTranslation('examples');
const { data, isLoading } = useQuery<Example[]>({
queryKey: ['examples'],
queryFn: () => api.examples.getAll(),
});

if (isLoading) return <Skeleton />;

return (
<div>
<h1>{t('title')}</h1>
<DataTable data={data ?? []} columns={columns} />
</div>
);
}

Store Pattern​

// apps/web/src/stores/example.store.ts
import { create } from 'zustand';

interface ExampleState {
selectedId: string | null;
setSelected: (id: string | null) => void;
}

export const useExampleStore = create<ExampleState>((set) => ({
selectedId: null,
setSelected: (id) => set({ selectedId: id }),
}));

Code Quality Rules​

RuleToolEnforcement
Zod for all validation@unipulse/shared validatorsMiddleware + zodResolver
Prisma for all DB access@prisma/clientNo raw SQL unless necessary
TanStack Query for API calls@tanstack/react-queryNo manual fetch in components
Workspace scopingworkspaceId in every queryService layer convention
Error handling at boundariesAppError + global handlerDon't catch silently
Translation for all user-facing textreact-i18nextt() function, never hardcoded strings
Logical CSS propertiesTailwind v4 ms-, me-, ps-, pe-RTL support

Import Order​

// 1. Node.js built-ins
import path from 'path';

// 2. External packages
import { Router } from 'express';
import { z } from 'zod';

// 3. Internal packages
import type { Post } from '@unipulse/shared';

// 4. Local imports
import { prisma } from '../lib/prisma';
import { postService } from '../services/post.service';

Cross-Reference