Skip to main content
Back to ScopeForged

ScopeForged Documentation

Technical documentation, guides, and feature references for the ScopeForged client portal.

Core Standards/Naming Conventions

Naming Conventions Guide

Last Updated: 2026-01-22 Status: Active Audience: Developers

This guide documents the naming conventions used throughout the Client Portal codebase to ensure consistency and maintainability.


Table of Contents

  1. PHP Classes
  2. Methods and Functions
  3. Variables
  4. Database
  5. Files and Directories
  6. Routes
  7. Configuration
  8. Views
  9. Tests

PHP Classes

Controllers

PatternConventionExample
Resource controllersPascalCase + ControllerClientController, InvoiceController
Nested resourcesParent + ChildClientProjectController
Admin controllersAdmin prefix in namespaceAdmin\ClientController
// Good
namespace App\Http\Controllers;
class ClientController extends Controller {}

namespace App\Http\Controllers\Admin;
class DashboardController extends Controller {}

// Bad
class clientController {}  // Wrong case
class ClientsController {} // Don't pluralize

Models

PatternConventionExample
Model namesPascalCase singularClient, Invoice, ProjectFile
Pivot modelsBoth names combinedClientUser
// Good
class Client extends Model {}
class ProjectFile extends Model {}
class InvoiceItem extends Model {}

// Bad
class Clients extends Model {}     // Don't pluralize
class project_file extends Model {} // Wrong case

Services

PatternConventionExample
Service classesPascalCase + ServiceInvoiceService, FileUploadService
Action classesPascalCase + Action verbCreateInvoiceAction, SendNotificationAction
// Good
class InvoiceService {}
class CreateInvoiceAction {}

// Bad
class InvoiceServiceClass {} // Redundant suffix
class invoiceService {}      // Wrong case

Service Naming Standards (Detailed)

This section provides detailed naming standards for the Services directory.

Service Classes

All service classes should use the *Service.php suffix:

TypeConventionExample
Domain services{Domain}{Purpose}Service.phpClientAnalyticsService.php
Analysis services{Domain}AnalysisService.phpTrendAnalysisService.php
Processing services{Domain}ProcessingService.phpDataProcessingService.php
// Good
class TrendAnalysisService {}     // Analysis functionality
class FileUploadService {}        // Upload handling
class NotificationDeliveryService {} // Delivery logic

// Bad
class TrendAnalyzer {}    // Missing Service suffix
class FileUploader {}     // Missing Service suffix

Builder Services (with Dependencies)

Builders that have dependencies (use DI) should have *BuilderService.php suffix:

// Good - has DI dependencies
class ChartBuilderService {
    public function __construct(private ChartFactory $factory) {}
}

class ReportQueryBuilderService {
    public function __construct(private DataSourceRegistry $registry) {}
}

Pure Builders (No Dependencies)

Pure utility builders without dependencies can use *Builder.php without the Service suffix:

// Good - pure utility, no DI
class CacheKeyBuilder {
    public static function build(string ...$parts): string {}
}

Registry Classes

Registry classes use *Registry.php suffix (no Service):

// Good
class ReportRegistry {}
class WidgetRegistry {}
class ExportFormatRegistry {}

DTOs (Data Transfer Objects)

DTOs should be placed in App\DataTransferObjects\ namespace:

PatternLocationExample
DTOsApp\DataTransferObjects\ParsedQuery.php, ExportResultDto.php
Suffixes*Data.php or *Dto.phpSearchResultData.php
// Good - in App\DataTransferObjects
namespace App\DataTransferObjects;

readonly class ParsedQuery {
    public function __construct(
        public string $textSearch,
        public array $filters = [],
    ) {}
}

Value Objects

Value objects with logic should be placed in App\Support\{Domain}\:

PatternLocationExample
Value objectsApp\Support\{Domain}\App\Support\Search\SearchContext.php
// Good - in App\Support\Search
namespace App\Support\Search;

final class SearchContext {
    public function __construct(
        public readonly ?User $user = null,
        public readonly int $limit = 10,
    ) {}
}

Directory Structure for Services

app/Services/
├── Analytics/
│   ├── TrendAnalysisService.php      # Analysis service
│   ├── KpiService.php                 # Domain service
│   └── DrillDown/
│       └── DrillDownQueryBuilder.php  # Pure builder
├── Reports/
│   ├── ReportService.php              # Domain service
│   ├── ChartBuilderService.php        # Builder with DI
│   ├── ReportRegistry.php             # Registry
│   └── Builder/
│       └── CustomReportBuilder.php    # Implementation
└── Cache/
    └── CacheKeyBuilder.php            # Pure utility

app/DataTransferObjects/
├── ParsedQuery.php                    # Search DTO
├── SearchResults.php                  # Results DTO
└── LeadScore.php                      # Scoring DTO

app/Support/
└── Search/
    └── SearchContext.php              # Value object

Other Classes

TypeConventionExample
Form RequestsPascalCase + RequestStoreClientRequest, UpdateInvoiceRequest
ResourcesPascalCase + ResourceClientResource, InvoiceResource
PoliciesPascalCase + PolicyClientPolicy, ProjectPolicy
EventsPascalCase (past tense)InvoiceCreated, FileUploaded
ListenersPascalCase (action)SendInvoiceNotification
JobsPascalCase (action)ProcessPayment, GeneratePdfInvoice
MailPascalCase + Mail/NotificationInvoiceMail, WelcomeNotification
MiddlewarePascalCaseEnsureUserIsAdmin, CheckClientAccess
ExceptionsPascalCase + ExceptionInvoiceNotFoundException, InvalidStatusException

Methods and Functions

General Methods

TypeConventionExample
Regular methodscamelCasegetActiveProjects(), calculateTotal()
Boolean methodsis/has/can/should prefixisActive(), hasPermission(), canEdit()
Accessor methodsget + AttributegetFullNameAttribute()
Mutator methodsset + AttributesetPasswordAttribute()
// Good
public function getActiveClients() {}
public function isOverdue(): bool {}
public function hasUnpaidInvoices(): bool {}
public function canAccessProject(Project $project): bool {}

// Bad
public function GetActiveClients() {}  // Wrong case
public function active(): bool {}      // Missing 'is' prefix for boolean

Controller Methods

Follow Laravel resource conventions:

MethodPurposeExample
index()List resourcesDisplay all clients
create()Show create formDisplay new client form
store()Save new resourceSave new client
show()Display single resourceDisplay client details
edit()Show edit formDisplay edit client form
update()Update resourceUpdate client
destroy()Delete resourceDelete client

Variables

Local Variables

TypeConventionExample
Regular variablescamelCase$clientName, $totalAmount
Boolean variablesis/has/should prefix$isActive, $hasErrors
CollectionsPlural camelCase$clients, $invoiceItems
Single itemsSingular camelCase$client, $invoice
// Good
$activeClients = Client::where('is_active', true)->get();
$isOverdue = $invoice->due_date < now();
$totalAmount = $items->sum('amount');

// Bad
$active_clients = [];  // Use camelCase
$overdue = true;       // Add 'is' prefix for booleans
$client_list = [];     // Use plural without 'list'

Constants

TypeConventionExample
Class constantsSCREAMING_SNAKE_CASEMAX_FILE_SIZE, DEFAULT_ROLE
Enum casesPascalCaseDraft, Active, Completed
// Good
class Invoice
{
    public const MAX_LINE_ITEMS = 100;
    public const DEFAULT_DUE_DAYS = 30;
}

enum InvoiceStatus: string
{
    case Draft = 'draft';
    case Sent = 'sent';
    case Paid = 'paid';
}

// Bad
class Invoice
{
    public const maxLineItems = 100;  // Wrong case
    public const Max_Items = 100;     // Wrong case
}

Database

Tables

PatternConventionExample
Table namessnake_case pluralclients, project_files
Pivot tablesSingular alphabeticalclient_user, project_tag
Polymorphic*able suffixcommentable, taggable
// Good - Migration
Schema::create('project_files', function (Blueprint $table) {});
Schema::create('client_user', function (Blueprint $table) {});  // Pivot

// Bad
Schema::create('ProjectFiles', function (Blueprint $table) {});  // Wrong case
Schema::create('project_file', function (Blueprint $table) {});  // Should be plural

Columns

PatternConventionExample
Regular columnssnake_casecompany_name, due_date
Foreign keyssingular_table_idclient_id, project_id
Boolean columnsis/has prefixis_active, has_paid
Timestampssnake_casecreated_at, paid_at
Polymorphic*able_type, *able_idtaggable_type, taggable_id
// Good
$table->string('company_name');
$table->foreignId('client_id')->constrained();
$table->boolean('is_active')->default(true);
$table->timestamp('paid_at')->nullable();

// Bad
$table->string('companyName');    // Use snake_case
$table->foreignId('clientID');    // Use snake_case
$table->boolean('active');        // Add 'is_' prefix

Indexes

PatternConventionExample
Index namestable_columns_indexinvoices_client_id_index
Unique indexestable_columns_uniqueusers_email_unique

Files and Directories

PHP Files

TypeConventionExample
ClassesPascalCase.phpClientController.php, Invoice.php
TraitsPascalCase.phpHasFiles.php, Notifiable.php
InterfacesPascalCase.phpInvoiceable.php, Exportable.php

Directory Structure

app/
├── Actions/              # Single-purpose action classes
├── Enums/                # PHP enums
├── Events/               # Event classes
├── Exceptions/           # Custom exceptions
├── Http/
│   ├── Controllers/
│   │   ├── Admin/        # Admin controllers
│   │   └── Portal/       # Client portal controllers
│   ├── Middleware/
│   └── Requests/         # Form request classes
├── Listeners/            # Event listeners
├── Mail/                 # Mailable classes
├── Models/               # Eloquent models
├── Notifications/        # Notification classes
├── Policies/             # Authorization policies
├── Providers/            # Service providers
└── Services/             # Service classes

Migrations

PatternExample
Create table2024_01_01_000001_create_clients_table.php
Add column2024_01_02_000001_add_status_to_invoices_table.php
Modify column2024_01_03_000001_modify_amount_in_invoices_table.php

Routes

Route Names

PatternConventionExample
Resource routesplural.actionclients.index, clients.show
Nested resourcesparent.child.actionclients.projects.index
Admin routesadmin.resource.actionadmin.clients.index
Portal routesportal.resource.actionportal.dashboard
// Good
Route::resource('clients', ClientController::class);
// Generates: clients.index, clients.create, clients.store, etc.

Route::prefix('admin')->name('admin.')->group(function () {
    Route::resource('clients', Admin\ClientController::class);
});
// Generates: admin.clients.index, admin.clients.show, etc.

// Bad
Route::get('/clients', [ClientController::class, 'index'])->name('getClients');
Route::get('/clients', [ClientController::class, 'index'])->name('client-list');

Route URIs

PatternConventionExample
Resourceskebab-case plural/clients, /project-files
ParameterscamelCase/clients/{client}, /invoices/{invoice}
Actionskebab-case/invoices/{invoice}/send-reminder
// Good
Route::get('/project-files', [ProjectFileController::class, 'index']);
Route::post('/invoices/{invoice}/mark-paid', [InvoiceController::class, 'markPaid']);

// Bad
Route::get('/projectFiles', ...);  // Use kebab-case
Route::get('/project_files', ...); // Use kebab-case

Configuration

Config Keys

PatternConventionExample
Config filessnake_case.phpclient_portal.php
Config keyssnake_casemax_file_size, default_role
Nested keysdot notationclient_portal.files.max_size
// config/client_portal.php
return [
    'max_file_size' => 10 * 1024 * 1024,  // 10MB
    'default_role' => 'client',
    'invoices' => [
        'due_days' => 30,
        'reminder_days' => [7, 3, 1],
    ],
];

// Usage
config('client_portal.max_file_size');
config('client_portal.invoices.due_days');

Environment Variables

PatternConventionExample
Variable namesSCREAMING_SNAKE_CASEAPP_NAME, DB_CONNECTION
Custom variablesPREFIX_NAMECLIENT_PORTAL_MAX_FILE_SIZE
# Good
APP_NAME="Client Portal"
CLIENT_PORTAL_MAX_FILE_SIZE=10485760
MAIL_FROM_ADDRESS="noreply@example.com"

# Bad
appName="Client Portal"     # Wrong case
maxFileSize=10485760        # Wrong case, needs prefix

Views

Blade Files

PatternConventionExample
View fileskebab-case.blade.phpclient-dashboard.blade.php
Directorieskebab-caseadmin/, portal/, components/
Componentskebab-case.blade.phpinvoice-card.blade.php
Layoutskebab-case.blade.phpapp.blade.php, guest.blade.php
resources/views/
├── admin/
│   ├── dashboard.blade.php
│   └── clients/
│       ├── index.blade.php
│       └── show.blade.php
├── portal/
│   └── dashboard.blade.php
├── components/
│   ├── invoice-card.blade.php
│   └── file-upload.blade.php
└── layouts/
    ├── app.blade.php
    └── guest.blade.php

Component Classes

// Good - Component class
namespace App\View\Components;
class InvoiceCard extends Component {}

// Usage in Blade
<x-invoice-card :invoice="$invoice" />

Tests

Test Files

TypeConventionExample
Feature testsPascalCaseTest.phpClientManagementTest.php
Unit testsPascalCaseTest.phpInvoiceServiceTest.php
Test methodstest_snake_casetest_user_can_create_client()
// Good
class ClientManagementTest extends TestCase
{
    public function test_admin_can_create_client(): void
    {
        // ...
    }

    public function test_client_cannot_access_admin_dashboard(): void
    {
        // ...
    }
}

// Alternative with attributes (Pest-style in PHPUnit)
#[Test]
public function admin_can_create_client(): void
{
    // ...
}

Test Directory Structure

tests/
├── Feature/
│   ├── Admin/
│   │   └── ClientManagementTest.php
│   ├── Auth/
│   │   ├── LoginTest.php
│   │   └── RegistrationTest.php
│   └── Portal/
│       └── DashboardTest.php
└── Unit/
    ├── Models/
    │   └── InvoiceTest.php
    └── Services/
        └── InvoiceServiceTest.php

Quick Reference

Do's

  • Use PascalCase for classes, traits, interfaces, enums
  • Use camelCase for methods, variables, parameters
  • Use snake_case for database tables, columns, config keys
  • Use kebab-case for URLs, view files, CSS classes
  • Use SCREAMING_SNAKE_CASE for constants and env variables
  • Be consistent within a file and across the codebase

Don'ts

  • Avoid abbreviations that aren't universally understood
  • Avoid mixing naming conventions within the same category
  • Avoid single-letter variable names (except in loops)
  • Avoid Hungarian notation ($strName, $intCount)