Coding Guidelines - AvengerDisassemble/KU-connect GitHub Wiki
/project-root
│
├── /src # Application source code
│ ├── /config # Configuration files (e.g., DB, environment)
│ ├── /controllers # Controllers to handle API requests & responses
│ ├── /routes # Route definitions and endpoint organization
│ ├── /models # Database models / schemas
│ ├── /services # Business logic and service layer
│ ├── /middlewares # Express middlewares (auth, validation, error handling)
│ ├── /utils # Utility functions and helpers
│ ├── /validators # Input validation schemas
│ └── app.js # App initialization (Express app setup)
│
├── /tests # Automated tests (unit, integration)
├── .env # Environment variables
├── server.js # Server startup and HTTP server (entry point)
├── package.json
└── README.md
- Use camelCase for variables and functions (getUserData).
- Use PascalCase for classes and constructors (UserModel)
- Use UPPERCASE for constants (API_URL).
- Use kebab-case for file and folder names (user-controler.js).
The coding style shall follow the JavaScript Standard Style.
The documenting standard will follow the JSDoc Standard.
/**
* Represents a book.
* @param {string} title - The title of the book.
* @param {string} author - The author of the book.
*/
function Book(title, author) {
}Note: There is a "@constructor" included in the example. However, since we are writing a simple class, it won't be necessary.
/** Class representing a point. */
class Point {
/**
* Create a point.
* @param {number} x - The x value.
* @param {number} y - The y value.
*/
constructor(x, y) {
// ...
}
/**
* Get the x value.
* @return {number} The x value.
*/
getX() {
// ...
}
/**
* Get the y value.
* @return {number} The y value.
*/
getY() {
// ...
}
/**
* Convert a string containing two comma-separated numbers into a point.
* @param {string} str - The string containing two comma-separated numbers.
* @return {Point} A Point object.
*/
static fromString(str) {
// ...
}
}/** @module color/mixer */
/** The name of the module. */
export const name = 'mixer';
/** The most recent blended color. */
export var lastColor = null;
/**
* Blend two colors together.
* @param {string} color1 - The first color, in hexadecimal format.
* @param {string} color2 - The second color, in hexadecimal format.
* @return {string} The blended color.
*/
export function blend(color1, color2) {}
// convert color to array of RGB values (0-255)
function rgbify(color) {}
export {
/**
* Get the red, green, and blue values of a color.
* @function
* @param {string} color - A color, in hexadecimal format.
* @returns {Array.<number>} An array of the red, green, and blue values,
* each ranging from 0 to 255.
*/
rgbify as toRgb
}(Not yet finalized)
src/
├─ assets/ # Static assets (e.g., logos, SVGs)
├─ components/ # Reusable UI components
│ ├─ ui/ # Footer, Header, Guard, etc.
│ └─ hooks/ # Custom hooks (e.g., useAuth)
├─ lib/ # Helper functions (e.g., utils.ts)
├─ pages/ # Page components, grouped by role
│ ├─ admin/ # Admin dashboard
│ ├─ employer/ # Employer dashboard
│ ├─ professor/ # Professor dashboard
│ ├─ student/ # Student dashboard
│ └─ public/ # Landing, Login, NotFound
├─ services/ # API client logic (e.g., api.ts)
├─ styles/ # Global styles (CSS, Tailwind)
├─ utils/ # Shared utilities
├─ App.tsx # Root component with router
└─ main.tsx # Entry point
-
Components: Use PascalCase and the
.tsxfile extension (e.g.,Header.tsx,NoteCard.tsx). -
Files & Helpers: Use camelCase for all other files (e.g.,
formatDate.ts,api.ts). -
Types/Interfaces: Use PascalCase (e.g.,
User,ApiResponse). -
Constants: Use UPPER_CASE with underscores (e.g.,
API_BASE_URL). -
Variables, Functions: Use descriptive camelCase (e.g.,
userName,formatDate). -
Booleans: Prefix with is, has, or can (e.g.,
isUserLoggedIn).
- Use functional components (not class).
- Keep components small and focused.
- Order: imports → hooks/state → handlers → JSX return.
- Use TypeScript interfaces/types for props.
- Mark optional props with
?and set default values using default parameters.
import React from "react";
interface NoteCardProps {
title: string;
content: string;
onDelete: () => void;
age?: number; // optional
}
const NoteCard: React.FC<NoteCardProps> = ({ title, content, onDelete, age = 18 }) => {
const handleClick = () => onDelete();
return (
<div className="note">
<h1>{title}</h1>
<p>{content} - {age}</p>
<button onClick={handleClick}>Delete</button>
</div>
);
};
export default NoteCard;- Use Tailwind CSS.
- Class names should be readable and grouped logically.
- Use conditional classes with template strings.
<button className={isActive ? "bg-blue-500" : "bg-gray-300"}>
Click
</button>- Use React hooks such as
useState,useEffect, and others. - Always define types explicitly when they cannot be inferred.
- Use union types or generic parameters for complex states.
- Extract repeated logic into custom hooks with proper typing.
const [count, setCount] = useState<number>(0);
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
console.log("User changed:", user);
}, [user]);
// Example of a custom hook
function useToggle(initialValue: boolean = false): [boolean, () => void] {
const [value, setValue] = useState<boolean>(initialValue);
const toggle = () => setValue((prev) => !prev);
return [value, toggle];
}- Group imports in the following order:
- React.
- External libraries.
- Local Files: Components, hooks, or utils from within the project.
- Use absolute imports (configured in tsconfig.json) instead of long relative paths.
- Avoid unused imports; enforce cleanup with ESLint.
-
Naming: Use descriptive names prefixed with a verb (e.g.,
handleClick,handleSubmit). -
Placement: Define
handlerfunctions above the return statement. - Typing: Always specify event types for clarity and safety.
// Input change event
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value);
};
// Form submit event
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// submit logic
};
// Button click event
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
console.log("Button clicked");
};