8.4 KiB
Coding Conventions
Analysis Date: 2026-02-15
Naming Patterns
Files:
- Frontend pages: PascalCase with
.jsxextension (e.g.,Dashboard.jsx,LoginPage.jsx,WorkoutPage.jsx) - Frontend components: PascalCase with
.jsxextension (e.g.,Icons.jsx) - Backend routes:
index.jsfor main server file - CSS files: kebab-case or match component name (e.g.,
index.css,App.css) - Context files: Named with
Contextsuffix (e.g.,AuthContext.jsx)
Functions:
- Async functions: verb + noun pattern (e.g.,
fetchProgram,fetchLogs,handleSubmit) - Event handlers:
handleprefix (e.g.,handleSubmit,handleSave,handleChange) - Helper/utility functions: descriptive names without prefixes (e.g.,
getCoachGreeting,getMuscleGroups,getWeekStart) - Hook usage: Standard React hooks (e.g.,
useState,useEffect,useContext) - Middleware functions: descriptive names (e.g.,
authMiddleware)
Variables:
- State variables: camelCase (e.g.,
user,loading,program,selectedDay) - Constants (config): UPPER_SNAKE_CASE or camelCase (e.g.,
API_URL,JWT_SECRET,PORT) - Local variables: camelCase (e.g.,
dayOfWeek,todayWorkout,lastWeight) - Boolean variables: descriptive (e.g.,
loading,editing,warmupDone,completedWarmups) - IDs: numeric or snake_case from database (e.g.,
user_id,program_exercise_id,program_day_id)
Types:
- Objects/interfaces: use descriptive structure without explicit types (e.g.,
{ id, email, onboarding_complete }) - Database records: snake_case field names from schema (e.g.,
password_hash,body_fat_pct,measured_at)
Code Style
Formatting:
- No explicit linter/formatter detected in config
- Indentation: 2 spaces (observed in code)
- Line length: typically under 100 characters
- Quotes: single quotes in most files, double quotes in some (inconsistent but not enforced)
- Semicolons: inconsistently used (some files omit, some include)
Linting:
- No ESLint, Prettier, or Biome config files detected
- No type checking (no TypeScript or JSDoc type annotations)
Spacing:
- Components separated by blank lines
- Function logic blocks separated by comments
- Import statements grouped: React/library imports first, then local imports
Import Organization
Order:
- React and core library imports (e.g.,
import React from 'react') - External libraries (e.g.,
react-router-dom, Express packages) - Local imports (context, pages, components)
- CSS/asset imports (e.g.,
import './index.css')
Path Aliases:
- No path aliases configured (
@/style paths not used) - Relative imports used throughout (e.g.,
'./context/AuthContext','../components/Icons') - Relative paths:
../for parent directory navigation in page imports
Examples:
// Frontend (AuthContext.jsx)
import { createContext, useContext, useState, useEffect } from 'react';
import { useAuth } from '../context/AuthContext';
import { Icon } from '../components/Icons';
import './App.css';
// Backend (index.js)
const express = require('express');
const { Pool } = require('pg');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
Error Handling
Patterns:
-
Frontend (React): Try-catch blocks in async functions, error state managed with
useStatetry { const res = await fetch(`${API_URL}/auth/login`, { ... }); const data = await res.json(); if (!res.ok) throw new Error(data.error); // Handle success } catch (err) { setError(err.message); } -
Backend (Express): Try-catch blocks in route handlers with status code responses
try { // Database query or logic res.json(result); } catch (err) { if (err.code === '23505') return res.status(400).json({ error: 'Email already exists' }); console.error('Operation error:', err); res.status(500).json({ error: 'Server error' }); } -
Error Response Format: JSON with
errorkey:{ error: 'Human-readable message' } -
Status Codes: 400 (validation/conflict), 401 (auth), 404 (not found), 500 (server error)
-
Empty error catches: Some empty catch blocks without logging (e.g.,
catch { logout(); }in AuthContext)
Logging
Framework: Native console.error() only
Patterns:
- Error logging:
console.error('Context + error:', err) - Backend operations logged:
console.error('Register error:', err),console.error('Profile error:', err) - Frontend operations: minimal logging (mostly silent failures)
- No structured logging or log levels (DEBUG, INFO, WARN)
- Log format: descriptive label + colon + error object
Examples from code:
console.error('Failed to fetch program:', err);
console.error('Login error:', err);
console.error('Update profile error:', err);
Comments
When to Comment:
- Section headers for major logical blocks (e.g.,
// Coach section,// Today's action,// Quick stats) - Data structure explanations (e.g.,
// Uppvärmningsövningar baserat på muskelgrupp) - Complex calculations or business logic
- Not applied to simple conditionals or obvious code
JSDoc/TSDoc:
- Not used - no type annotations or formal documentation
- Inline comments rare and minimal
Examples:
// Mappa övningar till muskelgrupper
function getMuscleGroups(exercises) { ... }
// Beräkna progress
const completedExercises = exercises.filter(ex => { ... });
// Check if log exists for this set
const existing = await pool.query(...);
Function Design
Size:
- Page/component functions: 40-250 lines (includes JSX)
- Helper functions: 5-30 lines
- Backend route handlers: 10-50 lines
Parameters:
- Named parameters for component props:
{ children, requireOnboarding = true } - Function parameters: individual arguments or destructured objects
- Query parameters: destructured from request (e.g.,
const { user_id, date } = req.query)
Return Values:
- React components return JSX directly
- Async functions return Promise<JSON | null>
- Helper functions return computed values or arrays
- Route handlers return via
res.json()orres.status().json()
Async/Await:
- Preferred over
.then()chains - Used consistently in all async operations
- Combined with try-catch for error handling
Examples:
const fetchProgram = async () => {
if (program) return; // Early return
try {
const res = await fetch(`${API_URL}/programs/1`);
const data = await res.json();
setProgram(data);
} catch (err) {
console.error('Failed to fetch program:', err);
}
};
// Helper function
function isSameDay(d1, d2) {
return d1.getDate() === d2.getDate() &&
d1.getMonth() === d2.getMonth() &&
d1.getFullYear() === d2.getFullYear();
}
Module Design
Exports:
- Frontend: Default exports for pages/contexts:
export default Dashboard - Frontend: Named exports for utilities:
export const useAuth = () => useContext(AuthContext) - Backend: Direct route handlers with
app.get(),app.post()etc. (not module exports) - Contexts:
export function AuthProvider+export const useAuth
Barrel Files:
- Icons component (
Icons.jsx) exports multiple icon definitions and helper functions - Most modules single-responsibility (one component/context per file)
Examples:
// Context export pattern
export function AuthProvider({ children }) { ... }
export const useAuth = () => useContext(AuthContext);
// Component export pattern
export default function LoginPage() { ... }
// Backend (no module export pattern, direct app routing)
app.post('/api/auth/login', async (req, res) => { ... });
State Management
Frontend:
- React
useStatehooks for local component state - React Context API for global auth state (
AuthContext.jsx) - Parent component state passed down as props (e.g.,
App.jsxmanages view, program, logs) - No Redux, Zustand, or Jotai
Backend:
- In-memory database connections via
Pool(pg package) - No state persistence between requests
- Request-scoped data via middleware (e.g.,
req.userfrom JWT)
CSS/Styling
Approach: Plain CSS with CSS variables
- CSS variables defined in
:root:--bg-primary,--text-primary,--accent, etc. - Dark theme with fitness-oriented color palette
- Classes: descriptive kebab-case (e.g.,
dashboard-header,calendar-day,page-main) - Utility/modifier classes:
.active,.today,.has-workout,.loading - No CSS-in-JS or utility framework (no Tailwind, Styled Components)
Convention analysis: 2026-02-15