Contribution Standards¶
Core coding standards for full-stack development.
SOLID Principles¶
Single Responsibility¶
Each module, class, or function has one purpose.
// ❌ Bad
class UserManager {
createUser(data) { }
sendEmail(to, body) { }
logActivity(action) { }
}
// ✅ Good
class UserService {
createUser(data: CreateUserDto): Promise<User> { }
}
class EmailService {
sendEmail(to: string, body: string): Promise<void> { }
}
class AuditLogger {
logActivity(action: string): Promise<void> { }
}
Open/Closed¶
Open for extension, closed for modification.
// ✅ Good: Use interfaces
interface PaymentProcessor {
processPayment(amount: number): Promise<PaymentResult>;
}
class StripeProcessor implements PaymentProcessor {
async processPayment(amount: number) { /* Stripe */ }
}
class PayPalProcessor implements PaymentProcessor {
async processPayment(amount: number) { /* PayPal */ }
}
// Adding new processor doesn't modify existing code
class SquareProcessor implements PaymentProcessor {
async processPayment(amount: number) { /* Square */ }
}
Dependency Inversion¶
Depend on abstractions, not concretions.
// ✅ Good: Inject dependencies
class CheckoutService {
constructor(private paymentProcessor: PaymentProcessor) {}
async checkout(order: Order) {
await this.paymentProcessor.processPayment(order.total);
}
}
TypeScript Best Practices¶
Strict Configuration¶
{
"compilerOptions": {
"strict": true,
"strictNullChecks": true,
"noImplicitAny": true,
"strictFunctionTypes": true
}
}
Explicit Types¶
// ✅ Good
interface User {
id: string;
email: string;
name: string | null;
}
async function getUser(id: string): Promise<User | null> {
return db.user.findUnique({ where: { id } });
}
// ❌ Bad
async function getUser(id) {
return db.user.findUnique({ where: { id } });
}
Null Handling¶
// ✅ Good: Handle null explicitly
function getUserName(user: User | null): string {
if (!user) return 'Guest';
return user.name ?? 'Unknown';
}
// ✅ Good: Optional chaining
const email = user?.profile?.email?.toLowerCase() ?? 'no-email';
// ❌ Bad: Unsafe access
const email = user.profile.email.toLowerCase();
Type Guards¶
// ✅ Good: Custom type guards
function isAdmin(user: User): user is AdminUser {
return user.role === 'admin';
}
if (isAdmin(user)) {
user.adminPrivileges; // TypeScript knows type
}
Utility Types¶
interface User {
id: string;
email: string;
password: string;
}
// Omit sensitive fields
type PublicUser = Omit<User, 'password'>;
// Make optional
type PartialUser = Partial<User>;
// Pick specific fields
type Credentials = Pick<User, 'email' | 'password'>;
API Design¶
RESTful Conventions¶
// Resources: plural nouns, kebab-case
GET /users
GET /users/:id
POST /users
PUT /users/:id
PATCH /users/:id
DELETE /users/:id
// Nested resources
GET /users/:id/posts
GET /workspaces/:id/members
Response Format¶
// Success
{
"success": true,
"data": { ... },
"meta": { "page": 1, "limit": 20, "total": 150 }
}
// Error
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input",
"details": { "email": "Invalid format" }
}
}
Status Codes¶
| Code | Usage |
|---|---|
| 200 | Successful GET, PUT, PATCH, DELETE |
| 201 | Successful POST (created) |
| 400 | Invalid input |
| 401 | Not authenticated |
| 403 | Not authorized |
| 404 | Not found |
| 422 | Validation errors |
| 500 | Server error |
Error Handling¶
Custom Error Classes¶
export class AppError extends Error {
constructor(
public message: string,
public statusCode: number,
public code: string,
public details?: Record<string, unknown>
) {
super(message);
}
}
export class ValidationError extends AppError {
constructor(message: string, details?: Record<string, unknown>) {
super(message, 422, 'VALIDATION_ERROR', details);
}
}
export class NotFoundError extends AppError {
constructor(resource: string, id: string) {
super(`${resource} with id ${id} not found`, 404, 'NOT_FOUND');
}
}
Usage¶
async function getUserById(id: string): Promise<User> {
const user = await db.user.findUnique({ where: { id } });
if (!user) {
throw new NotFoundError('User', id);
}
return user;
}
Database Guidelines¶
Query Optimization¶
// ✅ Good: Select only needed fields
const user = await db.user.findUnique({
where: { id },
select: { id: true, email: true, name: true }
});
// ✅ Good: Batch operations
await db.post.createMany({
data: users.map(user => ({ userId: user.id }))
});
// ❌ Bad: N+1 queries
for (const user of users) {
await db.post.create({ data: { userId: user.id } });
}
Multi-Tenancy¶
// ✅ CRITICAL: Always filter by organization
async function getProjects(orgId: string) {
return db.project.findMany({
where: { organizationId: orgId }
});
}
// ❌ DANGEROUS: Missing tenant filter
async function getAllProjects() {
return db.project.findMany(); // Exposes all tenants!
}
Code Quality¶
Commits¶
Use conventional commits:
feat: add user profile page
fix: resolve null pointer in auth
refactor: simplify payment logic
test: add integration tests
docs: update API documentation
Documentation¶
// ✅ Good: Explain "why"
// Cache permissions for 5 minutes to reduce DB load
// during high-traffic. Eventual consistency is acceptable.
const permissions = await cache.get(`user:${id}:perms`);
// ❌ Bad: States the obvious
// Get user permissions
const permissions = await getUserPermissions(id);
JSDoc for Public APIs¶
/**
* Creates a new user account.
*
* @param dto - User creation data
* @param workspaceId - Target workspace
* @returns Created user (without password)
* @throws {ValidationError} If input invalid
* @throws {ConflictError} If email exists
*/
export async function createUser(
dto: CreateUserDto,
workspaceId: string
): Promise<PublicUser> {
// ...
}