Coding standards, conventions, and rules for the Swyft codebase. Pre-commit hooks enforce most of these automatically.
This project uses strict TypeScript. These are non-negotiable:
any types. Fix the type properly.@ts-ignore or @ts-expect-error. Fix the type properly.noUncheckedIndexedAccess is enabled). Always handle undefined from indexed access.exactOptionalPropertyTypes is enabled). Use prop?: string | undefined when assigning string | undefined to an optional property.// WRONG
function getTotal(items: any[]) {
return items.reduce((sum, i) => sum + i.price, 0);
}
// CORRECT
function getTotal(items: Array<{ price: number }>): number {
return items.reduce((sum, i) => sum + i.price, 0);
}
| Type | Convention | Example |
|---|---|---|
| Components | PascalCase | WarehouseCard.tsx |
| Hooks | camelCase with use prefix |
useWarehouses.ts |
| Utilities | camelCase | formatCurrency.ts |
| Type definitions | camelCase with .types.ts |
routing.types.ts |
| Tests | Same name with .test.ts |
engine.test.ts |
| Server-only | .server.ts suffix |
order-router.server.ts |
| Generated | .generated.ts suffix |
trackstar.generated.ts |
Imports must follow this order (enforced by ESLint import/order):
react, zod, etc.)@swyft/*)./, ../)import { useState } from 'react';
import { z } from 'zod';
import { logger } from '@swyft/shared';
import { getStore } from '@swyft/database';
import { OrderCard } from './OrderCard';
import type { Order } from '../types/order.types';
Keep components focused and small:
| Type | Max Lines |
|---|---|
| Page component | 200 |
| Domain component | 150 |
| UI component | 100 |
| Hook | 150 |
| Utility function | 50 |
If a component exceeds these limits, extract sub-components or hooks.
Use the shared logger, never console.log:
// WRONG
console.log('debug:', data);
// CORRECT
import { logger } from '@swyft/shared';
logger.info('Order processed', { orderId: order.id, status: order.status });
All secrets, API keys, and passwords must come from environment variables. Never commit .env files.
// WRONG
const apiKey = 'sk_live_abc123';
// CORRECT
const apiKey = process.env.TRACKSTAR_API_KEY;
if (!apiKey) throw new ConfigError('TRACKSTAR_API_KEY required');
Validate all external input (webhooks, API requests) using Zod schemas:
import { z } from 'zod';
const OrderSchema = z.object({
orderId: z.string().uuid(),
items: z.array(
z.object({
sku: z.string().min(1),
quantity: z.number().positive(),
})
),
});
const parsed = OrderSchema.safeParse(payload);
if (!parsed.success) {
throw new ValidationError('Invalid order payload');
}
Always verify Shopify webhooks using the built-in HMAC authentication:
const { topic, shop, payload } = await authenticate.webhook(request);
service_role key server-side only. Never expose it to the browser.dangerouslySetInnerHTML with user-provided content.Always use the UUID store ID, never the domain string:
// WRONG
const orders = await supabase.from('orders').eq('shop_id', session.shop);
// CORRECT
const store = await getOrCreateStore(session.shop);
const orders = await supabase.from('orders').eq('shop_id', store.id);
Use Conventional Commits:
feat: add warehouse coverage visualization
fix: correct inventory sync timing
refactor: extract routing logic to package
test: add e2e tests for order flow
docs: update onboarding guide
chore: upgrade dependencies
Commit messages are validated by commitlint via pre-commit hooks.
Before submitting a PR, ensure all checks pass:
pnpm typecheck # TypeScript type checking
pnpm lint # ESLint
pnpm test # Vitest unit tests
pnpm build # Full build (when needed)
Pre-commit hooks run formatting, TypeScript validation, linting, and affected tests automatically. Do not bypass them with --no-verify.
These will be caught by hooks or code review:
| Pattern | Why |
|---|---|
any type |
Defeats type safety |
@ts-ignore / @ts-expect-error |
Hides real type errors |
console.log |
Use @swyft/shared logger |
| Hardcoded secrets | Security risk |
| Direct WMS API calls | Use Trackstar unified API |
shopify app dev (bare) |
Overwrites production URLs |
--no-verify on git |
Bypasses quality hooks |
| Force push to main | Destroys shared history |
dangerouslySetInnerHTML |
XSS risk with user content |
Editing .env files |
Hooks block this; use .env.staging.example as template |
# Run all unit tests
pnpm test
# Run tests with coverage
pnpm test:coverage
# Run E2E tests (requires running dev server)
pnpm test:e2e
# Run tests for a specific package
pnpm --filter @swyft/routing-engine test
The project uses Vitest for unit tests and Playwright for E2E tests. Test files use the .test.ts suffix and live alongside the code they test.