Skip to main content

04 - Code Structure and Organization

Organize code for maintainability: folder structure, naming conventions, separation of concerns and configuration management with Copilot.

What do you think about this article?

At a Glance

Organize code for maintainability: folder structure, naming conventions, separation of concerns and configuration management with Copilot.

Organizing Code with Copilot

A well-organized code structure is fundamental for long-term maintainability. In this article, we'll see how to use Copilot to define folder structure, naming conventions, configuration management, and patterns for a clean, professional codebase.

Code Organization Principles

  • Cohesion: Related files stay close together
  • Predictability: Easy to find where everything is
  • Scalability: Structure works even as project grows
  • Consistency: Same conventions applied everywhere
  • Discoverability: A new developer finds what they need quickly

Series Overview

# Module Status
1Foundation - Copilot as PartnerCompleted
2Ideation and RequirementsCompleted
3Backend and Frontend ArchitectureCompleted
4Code Structure and OrganizationYou are here
5Prompt Engineering and MCP AgentsNext
6Testing and Quality
7Documentation
8Deploy and DevOps
9Evolution and Maintenance

Complete Backend Folder Structure

Prompt - Backend Structure
Create a detailed folder structure for a Node.js + Express + TypeScript backend.

PROJECT: TaskFlow (time tracking + task management)
ARCHITECTURE: Layered (Controller - Service - Repository)

Requirements:
- Clean Architecture layers clearly separated
- Modular organization by feature/domain
- Clear separation of concerns
- Support for unit, integration, and e2e testing
- Environment-based configuration
- Database migrations and seeds
- Shared utilities and helpers
- API documentation structure

Show the complete tree with explanations for each folder/file.

Recommended Backend Structure

Backend Folder Structure
backend/
|-- src/
|   |-- config/                     # Application configuration
|   |   |-- index.ts                # Main config export (loads from env)
|   |   |-- database.config.ts      # Database connection settings
|   |   |-- auth.config.ts          # JWT, OAuth settings
|   |   |-- cors.config.ts          # CORS policy
|   |   |-- rate-limit.config.ts    # Rate limiting rules
|   |
|   |-- modules/                    # Feature modules (domain-driven)
|   |   |-- users/
|   |   |   |-- users.controller.ts # HTTP handling
|   |   |   |-- users.service.ts    # Business logic
|   |   |   |-- users.repository.ts # Data access
|   |   |   |-- users.routes.ts     # Route definitions
|   |   |   |-- dto/                # Data Transfer Objects
|   |   |   |   |-- create-user.dto.ts
|   |   |   |   |-- update-user.dto.ts
|   |   |   |   |-- user-response.dto.ts
|   |   |   |-- entities/           # Domain entities
|   |   |   |   |-- user.entity.ts
|   |   |   |-- __tests__/          # Module-specific tests
|   |   |       |-- users.service.spec.ts
|   |   |       |-- users.controller.spec.ts
|   |   |
|   |   |-- auth/
|   |   |   |-- auth.controller.ts
|   |   |   |-- auth.service.ts
|   |   |   |-- strategies/         # Passport strategies
|   |   |   |   |-- jwt.strategy.ts
|   |   |   |   |-- local.strategy.ts
|   |   |   |-- dto/
|   |   |   |-- auth.routes.ts
|   |   |
|   |   |-- tasks/
|   |   |   |-- tasks.controller.ts
|   |   |   |-- tasks.service.ts
|   |   |   |-- tasks.repository.ts
|   |   |   |-- tasks.routes.ts
|   |   |   |-- dto/
|   |   |   |-- entities/
|   |   |   |-- __tests__/
|   |   |
|   |   |-- time-entries/
|   |       |-- ... (same structure)
|   |
|   |-- shared/                     # Shared across modules
|   |   |-- middleware/
|   |   |   |-- auth.middleware.ts
|   |   |   |-- validation.middleware.ts
|   |   |   |-- rate-limit.middleware.ts
|   |   |   |-- request-logger.middleware.ts
|   |   |-- guards/
|   |   |   |-- roles.guard.ts
|   |   |   |-- ownership.guard.ts
|   |   |-- decorators/
|   |   |   |-- current-user.decorator.ts
|   |   |   |-- roles.decorator.ts
|   |   |-- errors/
|   |   |   |-- app-error.ts
|   |   |   |-- validation.error.ts
|   |   |   |-- not-found.error.ts
|   |   |   |-- unauthorized.error.ts
|   |   |-- utils/
|   |   |   |-- hash.util.ts
|   |   |   |-- jwt.util.ts
|   |   |   |-- pagination.util.ts
|   |   |   |-- date.util.ts
|   |   |-- types/
|   |       |-- express.d.ts        # Express type extensions
|   |       |-- common.types.ts
|   |
|   |-- database/                   # Database setup
|   |   |-- connection.ts           # DB connection pool
|   |   |-- migrations/             # Schema migrations
|   |   |   |-- 001_create_users.ts
|   |   |   |-- 002_create_tasks.ts
|   |   |   |-- 003_create_time_entries.ts
|   |   |-- seeds/                  # Test/dev data
|   |   |   |-- users.seed.ts
|   |   |   |-- tasks.seed.ts
|   |   |-- queries/                # Complex SQL queries
|   |       |-- reports.queries.ts
|   |
|   |-- api/                        # API versioning
|   |   |-- v1/
|   |   |   |-- index.ts            # v1 router aggregator
|   |   |-- index.ts                # Main API router
|   |
|   |-- app.ts                      # Express app setup
|   |-- server.ts                   # Entry point (starts server)
|
|-- tests/                          # Test files (by type)
|   |-- unit/                       # Isolated unit tests
|   |-- integration/                # API integration tests
|   |   |-- users.integration.spec.ts
|   |-- e2e/                        # End-to-end tests
|   |-- fixtures/                   # Test data
|   |   |-- users.fixture.ts
|   |-- helpers/                    # Test utilities
|       |-- db.helper.ts            # Test DB setup/teardown
|       |-- auth.helper.ts          # Get test tokens
|
|-- scripts/                        # Utility scripts
|   |-- migrate.ts                  # Run migrations
|   |-- seed.ts                     # Seed database
|   |-- generate-types.ts           # Generate TS from DB
|
|-- docs/                           # Documentation
|   |-- api/                        # OpenAPI specs
|   |   |-- openapi.yaml
|   |-- adr/                        # Architecture Decision Records
|       |-- 001-database-choice.md
|
|-- .env.example                    # Environment template
|-- .env.test                       # Test environment
|-- tsconfig.json
|-- jest.config.js
|-- package.json
|-- README.md

Complete Frontend Folder Structure

Frontend Folder Structure
frontend/
|-- src/
|   |-- app/
|   |   |-- core/                   # Singleton services (providedIn: 'root')
|   |   |   |-- services/
|   |   |   |   |-- api.service.ts           # HTTP client wrapper
|   |   |   |   |-- auth.service.ts          # Auth state management
|   |   |   |   |-- storage.service.ts       # LocalStorage/SessionStorage
|   |   |   |   |-- toast.service.ts         # Notification service
|   |   |   |   |-- theme.service.ts         # Dark/light mode
|   |   |   |-- guards/
|   |   |   |   |-- auth.guard.ts            # Protect routes
|   |   |   |   |-- guest.guard.ts           # Redirect if logged in
|   |   |   |   |-- unsaved-changes.guard.ts # Prevent accidental navigation
|   |   |   |-- interceptors/
|   |   |   |   |-- auth.interceptor.ts      # Add JWT to requests
|   |   |   |   |-- error.interceptor.ts     # Global error handling
|   |   |   |   |-- loading.interceptor.ts   # Show/hide loading
|   |   |   |   |-- retry.interceptor.ts     # Retry failed requests
|   |   |   |-- models/
|   |   |       |-- api-response.model.ts
|   |   |       |-- user.model.ts
|   |   |
|   |   |-- shared/                 # Reusable components (import in features)
|   |   |   |-- components/
|   |   |   |   |-- ui/                      # Design system primitives
|   |   |   |   |   |-- button/
|   |   |   |   |   |   |-- button.component.ts
|   |   |   |   |   |   |-- button.component.html
|   |   |   |   |   |   |-- button.component.scss
|   |   |   |   |   |   |-- button.component.spec.ts
|   |   |   |   |   |-- input/
|   |   |   |   |   |-- select/
|   |   |   |   |   |-- checkbox/
|   |   |   |   |   |-- modal/
|   |   |   |   |   |-- tooltip/
|   |   |   |   |   |-- dropdown/
|   |   |   |   |-- layout/                  # Layout components
|   |   |   |   |   |-- card/
|   |   |   |   |   |-- page-header/
|   |   |   |   |   |-- empty-state/
|   |   |   |   |-- feedback/                # Feedback components
|   |   |   |       |-- loading-spinner/
|   |   |   |       |-- skeleton/
|   |   |   |       |-- error-message/
|   |   |   |       |-- toast/
|   |   |   |-- directives/
|   |   |   |   |-- click-outside.directive.ts
|   |   |   |   |-- autofocus.directive.ts
|   |   |   |   |-- debounce-click.directive.ts
|   |   |   |   |-- tooltip.directive.ts
|   |   |   |-- pipes/
|   |   |   |   |-- time-ago.pipe.ts
|   |   |   |   |-- duration.pipe.ts
|   |   |   |   |-- truncate.pipe.ts
|   |   |   |   |-- highlight.pipe.ts
|   |   |   |-- index.ts                     # Barrel export
|   |   |
|   |   |-- features/               # Feature modules (lazy loaded)
|   |   |   |-- auth/
|   |   |   |   |-- components/
|   |   |   |   |   |-- login-form/
|   |   |   |   |   |-- register-form/
|   |   |   |   |   |-- forgot-password-form/
|   |   |   |   |-- pages/
|   |   |   |   |   |-- login.page.ts
|   |   |   |   |   |-- register.page.ts
|   |   |   |   |   |-- forgot-password.page.ts
|   |   |   |   |-- services/
|   |   |   |   |   |-- auth-api.service.ts
|   |   |   |   |-- models/
|   |   |   |   |   |-- auth.model.ts
|   |   |   |   |-- auth.routes.ts
|   |   |   |
|   |   |   |-- tasks/
|   |   |   |   |-- components/
|   |   |   |   |   |-- task-list/
|   |   |   |   |   |-- task-item/
|   |   |   |   |   |-- task-form/
|   |   |   |   |   |-- task-timer/
|   |   |   |   |   |-- task-filters/
|   |   |   |   |-- pages/
|   |   |   |   |   |-- tasks-list.page.ts
|   |   |   |   |   |-- task-detail.page.ts
|   |   |   |   |-- services/
|   |   |   |   |   |-- tasks-api.service.ts
|   |   |   |   |-- state/                   # Feature-specific state
|   |   |   |   |   |-- tasks.store.ts       # Signals-based store
|   |   |   |   |-- models/
|   |   |   |   |   |-- task.model.ts
|   |   |   |   |-- tasks.routes.ts
|   |   |   |
|   |   |   |-- dashboard/
|   |   |   |   |-- components/
|   |   |   |   |   |-- stats-card/
|   |   |   |   |   |-- recent-tasks/
|   |   |   |   |   |-- time-summary/
|   |   |   |   |   |-- quick-actions/
|   |   |   |   |-- pages/
|   |   |   |   |   |-- dashboard.page.ts
|   |   |   |   |-- dashboard.routes.ts
|   |   |   |
|   |   |   |-- settings/
|   |   |       |-- components/
|   |   |       |-- pages/
|   |   |       |-- settings.routes.ts
|   |   |
|   |   |-- layouts/                # Layout components
|   |   |   |-- main-layout/
|   |   |   |   |-- main-layout.component.ts
|   |   |   |   |-- components/
|   |   |   |       |-- header/
|   |   |   |       |-- sidebar/
|   |   |   |       |-- footer/
|   |   |   |-- auth-layout/
|   |   |       |-- auth-layout.component.ts
|   |   |
|   |   |-- app.component.ts
|   |   |-- app.routes.ts           # Root routes
|   |   |-- app.config.ts           # App providers
|   |
|   |-- assets/
|   |   |-- images/
|   |   |-- icons/
|   |   |   |-- svg/                # SVG icons
|   |   |-- fonts/
|   |
|   |-- styles/
|   |   |-- _variables.scss         # Design tokens
|   |   |-- _mixins.scss            # SCSS mixins
|   |   |-- _typography.scss        # Typography rules
|   |   |-- _utilities.scss         # Utility classes
|   |   |-- global.scss             # Global styles
|   |
|   |-- environments/
|       |-- environment.ts
|       |-- environment.prod.ts
|
|-- angular.json
|-- tsconfig.json
|-- package.json

Naming Conventions

Consistent naming helps Copilot generate coherent code and makes the codebase more readable for all team members (including yourself in 6 months).

Naming Conventions

Type Convention Example
File (general) kebab-case user-profile.component.ts
Class PascalCase UserProfileComponent
Variable/Function camelCase getUserProfile()
Constant SCREAMING_SNAKE_CASE MAX_RETRY_COUNT
Interface PascalCase (no I prefix) UserProfile
Type PascalCase TaskStatus
Enum PascalCase UserRole
Enum member SCREAMING_SNAKE_CASE UserRole.ADMIN
Boolean variable is/has/can prefix isLoading, hasError
Event handler on/handle prefix onSubmit, handleClick
Observable $ suffix users$, isLoading$
Signal no suffix (Angular 18+) users, isLoading

Recommended File Suffixes

Backend

Naming Patterns - Backend
// Controllers
user.controller.ts     -> UserController

// Services
user.service.ts        -> UserService

// Repositories
user.repository.ts     -> UserRepository

// Entities
user.entity.ts         -> User

// DTOs
create-user.dto.ts     -> CreateUserDto
update-user.dto.ts     -> UpdateUserDto

// Middleware
auth.middleware.ts     -> authMiddleware

// Guards
roles.guard.ts         -> RolesGuard

// Routes
user.routes.ts         -> userRoutes

Frontend (Angular)

Naming Patterns - Frontend
// Components
user-list.component.ts -> UserListComponent

// Pages (Smart Components)
users-list.page.ts     -> UsersListPage

// Services
user.service.ts        -> UserService
user-api.service.ts    -> UserApiService

// Models
user.model.ts          -> User (interface)

// Guards
auth.guard.ts          -> authGuard (function)

// Interceptors
auth.interceptor.ts    -> authInterceptor

// Pipes
time-ago.pipe.ts       -> TimeAgoPipe

// Directives
tooltip.directive.ts   -> TooltipDirective

Separation of Concerns

Each file/class should have a single, clear responsibility. This makes code more testable, reusable, and maintainable.

Wrong: God Controller

// user.controller.ts - EVERYTHING together
class UserController {{ '{' }}
  async create(req, res) {{ '{' }}
    // 1. Validation (should be in middleware)
    if (!req.body.email) {{ '{' }}
      return res.status(400).json(...);
    {{ '}' }}
    if (!/^[^\s@]+@[^\s@]+$/.test(req.body.email)) {{ '{' }}
      return res.status(400).json(...);
    {{ '}' }}

    // 2. Business logic (should be in service)
    const exists = await db.query('SELECT...');
    if (exists) throw new Error('...');

    const hashedPassword = await bcrypt.hash(...);

    // 3. Database (should be in repository)
    await db.query('INSERT INTO users...');

    // 4. Send email (should be in service)
    await sendgrid.send({{ '{' }}
      to: req.body.email,
      subject: 'Welcome!',
      ...
    {{ '}' }});

    res.json({{ '{' }} success: true {{ '}' }});
  {{ '}' }}
{{ '}' }}

Correct: Separate Responsibilities

// Controller: ONLY HTTP handling
async create(req, res, next) {{ '{' }}
  try {{ '{' }}
    const user = await this.userService
      .createUser(req.body);
    res.status(201).json({{ '{' }} data: user {{ '}' }});
  {{ '}' }} catch (err) {{ '{' }}
    next(err);
  {{ '}' }}
{{ '}' }}

// Service: ONLY business logic
async createUser(dto: CreateUserDto) {{ '{' }}
  await this.validateUniqueEmail(dto.email);
  const user = new User(dto);
  const saved = await this.userRepo.save(user);
  await this.emailService.sendWelcome(saved);
  return saved;
{{ '}' }}

// Repository: ONLY data access
async save(user: User): Promise<User> {{ '{' }}
  return this.db.users.create(user);
{{ '}' }}

// EmailService: ONLY email
async sendWelcome(user: User) {{ '{' }}
  await this.mailer.send({{ '{' }}...{{ '}' }});
{{ '}' }}

Configuration Management

Centralize configurations by environment with validation and type safety.

TypeScript - Config Management
// config/index.ts
import dotenv from 'dotenv';
import {{ '{' }} z {{ '}' }} from 'zod';

// Load .env file
dotenv.config();

// Define schema with validation
const configSchema = z.object({{ '{' }}
  // Environment
  NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
  PORT: z.string().transform(Number).default('3000'),

  // Database
  DATABASE_URL: z.string().url(),
  DATABASE_POOL_MIN: z.string().transform(Number).default('2'),
  DATABASE_POOL_MAX: z.string().transform(Number).default('10'),

  // Authentication
  JWT_SECRET: z.string().min(32),
  JWT_EXPIRES_IN: z.string().default('7d'),
  BCRYPT_ROUNDS: z.string().transform(Number).default('12'),

  // CORS
  CORS_ORIGIN: z.string().default('http://localhost:4200'),

  // External Services (optional in dev)
  SENDGRID_API_KEY: z.string().optional(),
  SENTRY_DSN: z.string().optional(),
{{ '}' }});

// Parse and validate
const parsed = configSchema.safeParse(process.env);

if (!parsed.success) {{ '{' }}
  console.error('Invalid environment variables:');
  console.error(parsed.error.format());
  process.exit(1);
{{ '}' }}

// Export typed config
export const config = {{ '{' }}
  env: parsed.data.NODE_ENV,
  port: parsed.data.PORT,
  isProduction: parsed.data.NODE_ENV === 'production',
  isDevelopment: parsed.data.NODE_ENV === 'development',

  database: {{ '{' }}
    url: parsed.data.DATABASE_URL,
    pool: {{ '{' }}
      min: parsed.data.DATABASE_POOL_MIN,
      max: parsed.data.DATABASE_POOL_MAX,
    {{ '}' }},
  {{ '}' }},

  jwt: {{ '{' }}
    secret: parsed.data.JWT_SECRET,
    expiresIn: parsed.data.JWT_EXPIRES_IN,
  {{ '}' }},

  bcrypt: {{ '{' }}
    rounds: parsed.data.BCRYPT_ROUNDS,
  {{ '}' }},

  cors: {{ '{' }}
    origin: parsed.data.CORS_ORIGIN.split(','),
  {{ '}' }},

  sendgrid: {{ '{' }}
    apiKey: parsed.data.SENDGRID_API_KEY,
  {{ '}' }},

  sentry: {{ '{' }}
    dsn: parsed.data.SENTRY_DSN,
  {{ '}' }},
{{ '}' }} as const;

// Type for config
export type Config = typeof config;

.env.example File

.env.example
# =============================================================
# TaskFlow Backend Configuration
# Copy this file to .env and fill in your values
# =============================================================

# -------------------------------------------------------------
# Environment
# -------------------------------------------------------------
NODE_ENV=development
PORT=3000

# -------------------------------------------------------------
# Database (PostgreSQL)
# -------------------------------------------------------------
DATABASE_URL=postgresql://user:password@localhost:5432/taskflow
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=10

# -------------------------------------------------------------
# Authentication
# -------------------------------------------------------------
# Generate with: openssl rand -base64 32
JWT_SECRET=your-super-secret-key-at-least-32-chars
JWT_EXPIRES_IN=7d
BCRYPT_ROUNDS=12

# -------------------------------------------------------------
# CORS
# -------------------------------------------------------------
CORS_ORIGIN=http://localhost:4200

# -------------------------------------------------------------
# External Services (optional for development)
# -------------------------------------------------------------
# SENDGRID_API_KEY=SG.xxxxx
# SENTRY_DSN=https://xxxxx@sentry.io/xxxxx

Index Files and Barrel Exports

Use index.ts files for clean exports and simplified imports.

TypeScript - Barrel Exports
// =============================================================
// shared/components/index.ts - Barrel Export
// =============================================================
// UI Components
export {{ '{' }} ButtonComponent {{ '}' }} from './ui/button/button.component';
export {{ '{' }} InputComponent {{ '}' }} from './ui/input/input.component';
export {{ '{' }} SelectComponent {{ '}' }} from './ui/select/select.component';
export {{ '{' }} ModalComponent {{ '}' }} from './ui/modal/modal.component';

// Layout Components
export {{ '{' }} CardComponent {{ '}' }} from './layout/card/card.component';
export {{ '{' }} PageHeaderComponent {{ '}' }} from './layout/page-header/page-header.component';
export {{ '{' }} EmptyStateComponent {{ '}' }} from './layout/empty-state/empty-state.component';

// Feedback Components
export {{ '{' }} LoadingSpinnerComponent {{ '}' }} from './feedback/loading-spinner/loading-spinner.component';
export {{ '{' }} SkeletonComponent {{ '}' }} from './feedback/skeleton/skeleton.component';
export {{ '{' }} ToastComponent {{ '}' }} from './feedback/toast/toast.component';

// =============================================================
// Usage in feature module
// =============================================================
// BEFORE (without barrel)
import {{ '{' }} ButtonComponent {{ '}' }} from '../../../shared/components/ui/button/button.component';
import {{ '{' }} InputComponent {{ '}' }} from '../../../shared/components/ui/input/input.component';
import {{ '{' }} CardComponent {{ '}' }} from '../../../shared/components/layout/card/card.component';

// AFTER (with barrel)
import {{ '{' }}
  ButtonComponent,
  InputComponent,
  CardComponent
{{ '}' }} from '@shared/components';

// =============================================================
// tsconfig.json - Path aliases
// =============================================================
{{ '{' }}
  "compilerOptions": {{ '{' }}
    "baseUrl": "./src",
    "paths": {{ '{' }}
      "@shared/*": ["app/shared/*"],
      "@core/*": ["app/core/*"],
      "@features/*": ["app/features/*"],
      "@environments/*": ["environments/*"]
    {{ '}' }}
  {{ '}' }}
{{ '}' }}

Import Organization

TypeScript - Import Order
// =============================================================
// Recommended import order
// =============================================================

// 1. Angular/Framework imports
import {{ '{' }} Component, OnInit, inject {{ '}' }} from '@angular/core';
import {{ '{' }} CommonModule {{ '}' }} from '@angular/common';
import {{ '{' }} RouterModule {{ '}' }} from '@angular/router';
import {{ '{' }} FormBuilder, ReactiveFormsModule {{ '}' }} from '@angular/forms';

// 2. Third-party library imports
import {{ '{' }} Observable {{ '}' }} from 'rxjs';
import {{ '{' }} map, catchError {{ '}' }} from 'rxjs/operators';

// 3. Core/Shared imports (using path aliases)
import {{ '{' }} AuthService {{ '}' }} from '@core/services/auth.service';
import {{ '{' }} ButtonComponent, CardComponent {{ '}' }} from '@shared/components';
import {{ '{' }} TimeAgoPipe {{ '}' }} from '@shared/pipes';

// 4. Feature-specific imports (relative paths)
import {{ '{' }} TasksApiService {{ '}' }} from './services/tasks-api.service';
import {{ '{' }} TaskItemComponent {{ '}' }} from './components/task-item/task-item.component';
import {{ '{' }} Task {{ '}' }} from './models/task.model';

// 5. Constants and types
import {{ '{' }} TASK_STATUS {{ '}' }} from './constants/task.constants';
import type {{ '{' }} TaskFilters {{ '}' }} from './types/task.types';

File Templates for Copilot

Create templates that Copilot can use as reference to generate consistent code.

Template - Angular Component
// =============================================================
// Template: Angular Standalone Component
// =============================================================
import {{ '{' }} Component, Input, Output, EventEmitter, ChangeDetectionStrategy {{ '}' }} from '@angular/core';
import {{ '{' }} CommonModule {{ '}' }} from '@angular/common';

/**
 * [ComponentName] - [Brief description]
 *
 * @example
 * <app-[component-name]
 *   [inputProp]="value"
 *   (outputEvent)="handler($event)"
 * />
 */
@Component({{ '{' }}
  selector: 'app-[component-name]',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './[component-name].component.html',
  styleUrl: './[component-name].component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
{{ '}' }})
export class [ComponentName]Component {{ '{' }}
  // -------------------------------------------------------------
  // Inputs
  // -------------------------------------------------------------
  @Input() inputProp: string = '';

  // -------------------------------------------------------------
  // Outputs
  // -------------------------------------------------------------
  @Output() outputEvent = new EventEmitter<void>();

  // -------------------------------------------------------------
  // Public methods
  // -------------------------------------------------------------
  onAction(): void {{ '{' }}
    this.outputEvent.emit();
  {{ '}' }}
{{ '}' }}

Code Organization Checklist

Checklist

Item Status
Folder structure defined and documented
Naming conventions documented
Path aliases configured in tsconfig
Barrel exports for shared modules
Config management centralized with validation
.env.example with all variables
ESLint/Prettier configured
Husky + lint-staged for pre-commit hooks

Conclusion

A well-organized code structure pays dividends throughout the project's lifetime. Investing time in defining clear conventions makes development faster, code more maintainable, and onboarding new contributors (or yourself in 6 months) much easier.

Key Takeaways

  • Feature-Based Structure: Organize by feature, not by file type
  • Naming Conventions: kebab-case for files, PascalCase for classes
  • Separation of Concerns: Controller -> Service -> Repository
  • Config Management: Centralize with schema validation (Zod)
  • Barrel Exports: Index.ts for clean imports
  • Path Aliases: @shared, @core, @features to avoid ../../../

Next Article

In the next article "Prompt Engineering and MCP Agents" we'll see advanced techniques for writing effective prompts and how to configure MCP agents for persistent context in your project.

Try These Tools

Free developer tools related to this topic.

Commenti

Caricamento commenti...

Sign in to comment

Discuss this article in the community

Join the Telegram group to discuss with other developers, ask questions and share your experiences.

Did you like this article?

Explore other content on the blog or discover my projects