Coding Standards — Quick Reference
Full rationale and decisions in the ADRs section. This page is the daily cheat sheet.
PHP
| Item | Convention | Example |
|---|---|---|
| Standard | PSR-12 | - |
| Strict types | declare(strict_types=1) — always, first line after <?php | - |
| Namespace | FacturaScripts\Plugins\<Plugin>\<Layer> | FacturaScripts\Plugins\ObelioScheduling\Model\Appointment |
| Classes | PascalCase, English | AppointmentRoom, SurgerySession |
| Methods | camelCase, English | getNextAppointment(), loadCompany() |
| Constants | SCREAMING_SNAKE_CASE | STATUS_IN_WAITING_ROOM |
| Variables | camelCase | $patientName, $appointmentDate |
| Comments | English, mandatory | PHPDoc on every class + method; inline // for non-obvious WHY |
PHPDoc example
<?php
declare(strict_types=1);
namespace FacturaScripts\Plugins\ObelioScheduling\Model;
/**
* Represents a bookable appointment slot in the scheduling system.
*
* Each appointment belongs to one company (idEmpresa) and one clinic center (codalmacen).
* Status transitions: pending -> confirmed -> in_progress -> completed | cancelled | no_show.
*/
class Appointment extends ModelClass
{
/**
* Returns all pending appointments for the given clinic center on the given date.
*
* @param string $codalmacen FS warehouse code used as clinic center identifier
* @param string $date ISO 8601 date string (YYYY-MM-DD)
* @return self[]
*/
public function getPendingByCenter(string $codalmacen, string $date): array
{
// ...
}
}
Database
| Item | Convention | Example |
|---|---|---|
| Table names | obelio_<plugin>_<entity> — snake_case, English, singular | obelio_scheduling_appointment |
| Column names | snake_case, English | appointment_date, created_at |
| PK constraint | pk_<table> | pk_obelio_scheduling_appointment |
| FK constraint | fk_<table>_<col> | fk_obelio_scheduling_appointment_id_patient |
| Unique constraint | uq_<table>_<col> | uq_obelio_scheduling_appointment_code |
| Index | idx_<table>_<col> | idx_obelio_scheduling_appointment_date |
| FS core joins | Accept FS naming as-is | JOIN clientes ON clientes.codcliente = obelio_core_patient.id_cliente |
Multi-tenant columns are mandatory on every obeliOmed table:
-- Every table must include these two columns
`idempresa` INT NOT NULL, -- FS company id (tenant separator)
`codalmacen` VARCHAR(4) NOT NULL -- FS warehouse = clinic center
Versioning (CalVer, ADR-028)
Format: AAMMDD.NN — year-month-day, dot, sequence within day.
260620.01 -> 2026-06-20, first build of the day
260620.02 -> 2026-06-20, second build
260621.01 -> 2026-06-21, first build
Git branches
develop -> integration branch (Javi merges here; do not push directly)
main -> production releases (Javi only)
NNN-description -> your feature branch; branch from develop
Examples: 016-surgery-room-model, 017-patient-guardian-fields
Merge authority
Only Javi closes PRs and merges to develop and main. Open your PR, write REVIEW.md, and stop. Never ask "can I merge this?" — Javi decides on merge days.
CSS / JS (ObelioTheme)
| Item | Convention | Example |
|---|---|---|
| Classes | obelio-<entity>-<modifier> (kebab-case, prefix) | .obelio-appt-card, .obelio-clock |
| CSS variables | Use design tokens from ObelioTheme | var(--obelio-color-primary) |
| JS modules | ES modules, no globals | import { formatDate } from '../utils/date.js' |
Translations
All user-facing text goes through FacturaScripts translation keys:
// In templates
{{ i18n.trans('Appointment date') }}
// In PHP
$this->i18n->trans('Appointment date')
Translation files live in Translation/es_ES.json and Translation/en_US.json.
Code is always English; translations handle language.