This document defines the coding standards and conventions for the Lychee project across PHP, Vue3/TypeScript, and documentation.
- License header: Every new PHP file must contain the license header at the top.
- Blank line: Include a single blank line after the opening
<?phptag.
<?php
/**
* License header goes here...
*/
namespace App\Example;-
Variables: Use
snake_casefor variable names.$user_name = 'John Doe'; $album_id = 42;
-
Classes: Follow PSR-4 autoloading standard.
namespace App\Http\Controllers; class PhotoController extends Controller
-
PSR-4: Apply the PSR-4 coding standard for autoloading.
-
Array checks: Use
in_array()withtrueas the third parameter for strict comparison.// ✅ Correct if (in_array($value, $array, true)) { // ... } // ❌ Incorrect if (in_array($value, $array)) { // ... }
-
Conditionals: Only use booleans in if statements, not integers or strings.
// ✅ Correct if ($user->isActive()) { // ... } // ❌ Incorrect if ($user->status) { // if status is integer or string // ... }
-
Strict comparison: Use strict comparison (
===) instead of loose comparison (==).// ✅ Correct if ($value === null) { // ... } // ❌ Incorrect if ($value == null) { // ... }
-
Code duplication: Avoid code duplication in both if and else statements. Extract common code.
// ✅ Correct $base_config = getBaseConfig(); if ($condition) { return array_merge($base_config, ['extra' => 'value']); } return $base_config; // ❌ Incorrect if ($condition) { $config = getBaseConfig(); $config['extra'] = 'value'; return $config; } else { $config = getBaseConfig(); return $config; }
-
Empty function: Do not use
empty(). Use explicit checks instead.// ✅ Correct if ($value === null || $value === '' || $value === []) { // ... } // ❌ Incorrect if (empty($value)) { // ... }
-
Request user handling:
$this->useris reserved for the user making the request.$this->user2is used when a user is provided by the query parameter.
-
Resource classes: Must extend from
Spatie\LaravelData\Datainstead ofJsonResource.use Spatie\LaravelData\Data; class PhotoData extends Data { // ... }
-
Views: Do not use Blade views. The application uses Vue3 for all frontend rendering.
When dealing with monetary values:
- Library: Use the
moneyphp/moneylibrary for all monetary operations. - Storage: Never use floats or doubles. Store values as integers representing the smallest currency unit (e.g., cents for USD).
// ✅ Correct $price_in_cents = 1099; // Represents $10.99 $money = new Money($price_in_cents, new Currency('USD')); // ❌ Incorrect $price = 10.99; // Float - prone to rounding errors
- Preferred: Use
DB::transaction(callable)for database transactions instead of manually callingDB::beginTransaction(),DB::commit(), andDB::rollback(). This ensures that transactions are handled more cleanly and reduces the risk of forgetting to commit or rollback.
// ✅ Correct
DB::transaction(function () {
// Perform database operations
});
// ❌ Incorrect
DB::beginTransaction();
try {
// Perform database operations
DB::commit();
} catch (Exception $e) {
DB::rollback();
throw $e;
}- Template order: Components must follow this structure:
<template>first<script lang="ts">second<style>last
<template>
<div>
<!-- Component template -->
</div>
</template>
<script lang="ts">
// Component logic
</script>
<style>
/* Component styles */
</style>-
Composition API: Use TypeScript with Composition API for Vue3.
-
Type generation: TypeScript types for PHP resources are automatically generated. After modifying PHP resource classes (e.g.,
PhotoResource,PhotoStatisticsResource), run:php artisan typescript:transform
This generates TypeScript definitions in
resources/js/lychee.d.tsfrom PHP DTOs, resources, and enums. The generated types are automatically available in theApp.*namespace (e.g.,App.Http.Resources.Models.PhotoResource). -
Function declarations: Use regular function declarations, not arrow functions.
// ✅ Correct function handleClick() { // ... } // ❌ Incorrect const handleClick = () => { // ... };
-
Async handling: Do not use
await/asyncin Vue3. Use.then()instead.// ✅ Correct fetchData().then((data) => { processData(data); }); // ❌ Incorrect const data = await fetchData(); processData(data);
- Component library: Use PrimeVue for UI components.
- Custom components: Build custom components on top of PrimeVue primitives.
- Services location: Place all axios requests in the
services/directory. - Base URL: Use
${Constants.getApiUrl()}to specify the base URL.import axios from 'axios'; import { Constants } from '@/constants'; export function fetchPhotos() { return axios.get(`${Constants.getApiUrl()}/photos`); }
-
Unit tests: Tests in
tests/Unit/directory must extend fromAbstractTestCase.namespace Tests\Unit; use Tests\AbstractTestCase; class ExampleTest extends AbstractTestCase { // ... }
-
Feature tests: Tests in
tests/Feature_v2/directory must extend fromBaseApiWithDataTest.namespace Tests\Feature_v2; use Tests\Feature_v2\BaseApiWithDataTest; class PhotoApiTest extends BaseApiWithDataTest { // ... }
- No mocking: Do not mock the database in tests.
- In-memory database: Use the in-memory SQLite database for test execution.
- Standard: Use Markdown format for all documentation.
- Footer: At the bottom of every documentation file, add:
--- *Last updated: [date of the update]*
- Follow the established structure in
docs/specs/:0-overview/- High-level project documentation1-concepts/- Conceptual documentation2-how-to/- How-to guides3-reference/- Reference documentation (this file)4-architecture/- Architecture decisions and designs5-operations/- Operational runbooks6-decisions/- Architectural Decision Records (ADRs)
Before committing PHP changes:
- PHP CS Fixer:
vendor/bin/php-cs-fixer fix— Apply code style fixes - Tests:
php artisan test— All tests must pass - PHPStan:
make phpstan— Level 6 minimum; fix all errors
Before committing frontend changes:
- Prettier:
npm run format— Apply code formatting - Tests:
npm run check— All frontend tests must pass
- Knowledge Map - Module and dependency relationships
- PSR-4 Specification - PHP autoloading standard
- Vue 3 Composition API - Official Vue3 documentation
- PrimeVue Documentation - UI component library
Last updated: December 27, 2025