TypeScript Standards
Deltalytix is built with TypeScript in strict mode. All code must be properly typed.
TypeScript Configuration
The project uses these TypeScript settings:
{
"compilerOptions" : {
"target" : "ES2017" ,
"lib" : [ "dom" , "dom.iterable" , "esnext" ],
"strict" : true ,
"skipLibCheck" : true ,
"esModuleInterop" : true ,
"module" : "esnext" ,
"moduleResolution" : "bundler" ,
"jsx" : "react-jsx" ,
"paths" : {
"@/*" : [ "./*" ]
}
}
}
Type Safety
Always Use Explicit Types
// Good
function calculatePnL ( trades : Trade []) : number {
return trades . reduce (( sum , trade ) => sum + trade . pnl , 0 )
}
// Bad
function calculatePnL ( trades ) {
return trades . reduce (( sum , trade ) => sum + trade . pnl , 0 )
}
// Good
interface TradeData {
instrument : string
pnl : number
quantity : number
}
function processData ( data : TradeData ) : void { }
// Bad
function processData ( data : any ) : void { }
// Good
type TradeSide = 'long' | 'short'
type TradeStatus = 'open' | 'closed' | 'pending'
interface Trade {
side : TradeSide
status : TradeStatus
}
// Good - type is inferred
const trades = await prisma . trade . findMany ()
const total = trades . length
// Unnecessary - already inferred
const trades : Trade [] = await prisma . trade . findMany ()
const total : number = trades . length
React Best Practices
Component Structure
'use client' // Only if client component
import { useState } from 'react'
import { useI18n } from '@/locales/client'
interface TradeCardProps {
trade : Trade
onUpdate ?: ( trade : Trade ) => void
}
export function TradeCard ({ trade , onUpdate } : TradeCardProps ) {
const t = useI18n ()
const [ isEditing , setIsEditing ] = useState ( false )
return (
< div className = "rounded-lg border p-4" >
< h3 >{ t ( 'trade-table.instrument' )} </ h3 >
{ /* Component content */ }
</ div >
)
}
Component Guidelines
Use Functional Components
Always use functional components with hooks, not class components.
Server vs Client Components
Default to Server Components. Only use 'use client' when needed for:
Event handlers
Browser APIs
State management
React hooks
Props Interface
Define explicit interfaces for component props.
Destructure Props
Destructure props in the function signature for clarity.
Hooks Usage
// Good - hooks at top level
function TradeAnalysis () {
const t = useI18n ()
const [ trades , setTrades ] = useState < Trade []>([])
const filteredTrades = useMemo (
() => trades . filter ( t => t . pnl > 0 ),
[ trades ]
)
return < div >{ /* content */ } </ div >
}
// Bad - conditional hooks
function TradeAnalysis () {
if ( condition ) {
const t = useI18n () // ❌ Never
}
return < div >{ /* content */ } </ div >
}
File Organization
Project Structure
deltalytix/
├── app/ # Next.js App Router
│ ├── [locale]/ # Internationalized routes
│ │ ├── dashboard/ # Dashboard pages
│ │ └── (landing)/ # Marketing pages
│ └── api/ # API routes
├── components/ # React components
│ ├── ui/ # Base UI components
│ └── [feature]/ # Feature-specific components
├── lib/ # Utility functions
├── hooks/ # Custom React hooks
├── store/ # Zustand stores
├── server/ # Server-side logic
├── locales/ # Translations (EN/FR)
└── prisma/ # Database schema
File Naming Conventions
Components TradeCard.tsx
TradeTable.tsx
PnLChart.tsx
PascalCase for components
Utilities formatCurrency.ts
calculatePnL.ts
parseTradeData.ts
camelCase for utilities
Hooks useTradeFilters.ts
useTrades.ts
useEquityChart.ts
use + PascalCase prefix
Types types.ts
trade.types.ts
api.types.ts
.types.ts suffix
Naming Conventions
Variables and Functions
// Variables - camelCase
const tradeData = []
const totalPnl = 0
const isLoading = false
// Functions - camelCase, descriptive verbs
function calculateTotalPnl ( trades : Trade []) : number { }
function formatTradeDate ( date : Date ) : string { }
function filterProfitableTrades ( trades : Trade []) : Trade [] { }
// Boolean variables - is/has/can prefix
const isAuthenticated = true
const hasPermission = false
const canEdit = true
// Constants - UPPER_SNAKE_CASE
const MAX_TRADES_PER_PAGE = 50
const API_BASE_URL = 'https://api.example.com'
const DEFAULT_COMMISSION_RATE = 2.5
Interfaces and Types
// Interfaces - PascalCase, descriptive nouns
interface Trade {
id : string
instrument : string
pnl : number
side : 'long' | 'short'
}
interface TradeFilters {
dateRange ?: DateRange
instruments ?: string []
minPnl ?: number
}
// Type aliases - PascalCase
type TradeSide = 'long' | 'short'
type DateRange = { from : Date ; to : Date }
// Generic types - single capital letter
type ApiResponse < T > = {
data : T
error ?: string
}
ESLint Configuration
The project uses ESLint with Next.js configuration:
import { defineConfig , globalIgnores } from "eslint/config"
import nextVitals from "eslint-config-next/core-web-vitals"
import nextTs from "eslint-config-next/typescript"
const eslintConfig = defineConfig ([
... nextVitals ,
... nextTs ,
globalIgnores ([ ".next/**" , "out/**" , "build/**" ])
])
export default eslintConfig
Indentation
Semicolons
Quotes
Line Length
Use 2 spaces for indentation
No tabs
Consistent across all files
Not required (JavaScript/TypeScript default)
Be consistent within a file
Use single quotes for strings
Use double quotes for JSX attributes
const name = 'Deltalytix'
return < div className = "container" />
Aim for 80-100 characters per line
Break long lines for readability
Import Organization
// 1. External dependencies
import { useState , useEffect } from 'react'
import { toast } from 'sonner'
// 2. Internal dependencies with @ alias
import { Button } from '@/components/ui/button'
import { useI18n } from '@/locales/client'
import { formatCurrency } from '@/lib/utils'
// 3. Relative imports
import { TradeCard } from './TradeCard'
import type { Trade } from './types'
// 4. Type-only imports at the end
import type { ReactNode } from 'react'
Best Practices
Error Handling
// Good - Proper error handling
try {
const trades = await fetchTrades ()
return trades
} catch ( error ) {
console . error ( 'Failed to fetch trades:' , error )
toast . error ( t ( 'error' ), {
description: t ( 'dashboard.loadingError' )
})
return []
}
// Bad - Silent failures
try {
const trades = await fetchTrades ()
return trades
} catch ( error ) {
// Silent failure
}
Self-Documenting Code
// Good - Clear and self-explanatory
function calculateAverageWinRate ( trades : Trade []) : number {
const winningTrades = trades . filter ( trade => trade . pnl > 0 )
return ( winningTrades . length / trades . length ) * 100
}
// Bad - Unclear variable names
function calc ( t : any []) : number {
const w = t . filter ( x => x . p > 0 )
return ( w . length / t . length ) * 100
}
When to Comment
Complex business logic
Non-obvious solutions
Workarounds and hacks
Important decisions
TODOs with context
When NOT to Comment
Obvious code
Redundant descriptions
Commented-out code
Version history (use git)
// Good - Explains WHY
// Rithmic API returns times in UTC but without timezone indicator
// We need to manually convert to user's timezone
const localTime = convertRithmicTimeToLocal ( trade . timestamp )
// Bad - Explains WHAT (obvious)
// Loop through trades
for ( const trade of trades ) {
// Calculate PnL
const pnl = calculatePnL ( trade )
}
State Management
// Client-side state - Zustand stores
import { create } from 'zustand'
interface TradeStore {
trades : Trade []
setTrades : ( trades : Trade []) => void
addTrade : ( trade : Trade ) => void
}
export const useTradeStore = create < TradeStore >(( set ) => ({
trades: [],
setTrades : ( trades ) => set ({ trades }),
addTrade : ( trade ) => set (( state ) => ({
trades: [ ... state . trades , trade ]
}))
}))
// Server-side - Server Actions
export async function updateTrade ( tradeId : string , data : TradeUpdate ) {
'use server'
const user = await getUser ()
if ( ! user ) throw new Error ( 'Unauthorized' )
return prisma . trade . update ({
where: { id: tradeId },
data
})
}
API Design
Server Actions
API Routes
Real-time
Use for mutations and authenticated operations: 'use server'
export async function deleteTrade ( tradeId : string ) {
const user = await getUser ()
if ( ! user ) throw new Error ( 'Unauthorized' )
return prisma . trade . delete ({
where: { id: tradeId , userId: user . id }
})
}
Use for public data and webhooks: // app/api/trades/route.ts
export async function GET ( request : Request ) {
const trades = await prisma . trade . findMany ()
return Response . json ({ trades })
}
Use Supabase subscriptions: const channel = supabase
. channel ( 'trades' )
. on ( 'INSERT' , ( payload ) => {
// Handle new trade
})
. subscribe ()
Memoization
import { useMemo , useCallback } from 'react'
function TradeAnalysis ({ trades } : { trades : Trade [] }) {
// Memoize expensive calculations
const statistics = useMemo (() => {
return calculateComplexStatistics ( trades )
}, [ trades ])
// Memoize callbacks passed to children
const handleTradeUpdate = useCallback (( trade : Trade ) => {
updateTrade ( trade )
}, [])
return < div >{ /* content */ } </ div >
}
Lazy Loading
import dynamic from 'next/dynamic'
// Lazy load heavy components
const AdvancedChart = dynamic (
() => import ( '@/components/charts/AdvancedChart' ),
{ loading : () => < ChartSkeleton /> }
)
Testing Guidelines
While Deltalytix doesn’t have a comprehensive test suite yet, follow these guidelines:
Manual Testing Checklist
Future Testing
We plan to add:
Unit tests with Jest
Component tests with React Testing Library
E2E tests with Playwright
Contributions that add tests are highly appreciated!
Resources