All classes are now organised by domain (Availability, Booking, Auth). Each domain package contains its value object, repository, admin controller, REST endpoint, and any shortcode pages under a matching sub-namespace. Cross-cutting wiring (Plugin, AdminMenu, RestRegistrar, ShortcodeRegistrar, Schema) lives at src/ root. Tests mirror the domain structure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Commands
composer install # Install all dependencies
composer test # Run the full test suite (required after every change)
composer lint # PHPStan static analysis
composer cs # PHPCS coding standards check
composer cs:fix # Auto-fix coding standards
# Run a single test file
./vendor/bin/phpunit tests/Unit/Availability/AvailabilityRepositoryTest.php
# Run a single test by name
./vendor/bin/phpunit --filter testInsertCallsWpdbInsertAndReturnsId
Run composer test after every code change before considering a task complete.
Architecture
Plugin Bootstrap
unsupervised-schedular.php defines constants (USC_VERSION, USC_PLUGIN_DIR, USC_PLUGIN_URL), registers activation/deactivation hooks, then calls Plugin::boot() on plugins_loaded. No logic lives in the root file.
Directory Structure
src/ — All plugin PHP (PSR-4 namespace: Unsupervised\Schedular\)
Availability/ — Availability slots: value object, repository, controller, REST endpoint
Booking/ — Lessons/bookings: value object, repository, controller, REST endpoint, shortcode page
Auth/ — Roles, capabilities, login page
Plugin.php — Wires all components together on plugins_loaded
Installer.php — Creates DB tables and roles on activation
Schema.php — CREATE TABLE SQL for dbDelta
AdminMenu.php — Registers wp-admin menu pages
RestRegistrar.php — Registers all REST routes under us-scheduler/v1
ShortcodeRegistrar.php — Registers [us_booking] and [us_student_login] shortcodes
templates/ — PHP view files included by controllers/shortcodes
assets/ — CSS and JS (vanilla JS, no build step)
tests/Unit/ — PHPUnit unit tests (PSR-4: Unsupervised\Schedular\Tests\)
Availability/ — Tests for src/Availability/
Booking/ — Tests for src/Booking/
Auth/ — Tests for src/Auth/
docs/features/ — One markdown file per feature describing data model, API, and test locations
Code is organised package-by-domain (Availability, Booking, Auth). Each domain package contains everything related to that domain: value objects, repositories, controllers, REST endpoints, and shortcode pages. Cross-cutting wiring classes (Plugin, AdminMenu, RestRegistrar, ShortcodeRegistrar, Schema) live directly under src/.
Data Storage
Two custom database tables (created via dbDelta on activation):
{prefix}us_availability— instructor availability windows{prefix}us_lessons— booked lessons
All database access goes through repository classes within their domain package. No direct $wpdb calls outside repositories.
Key Classes
| Class | Responsibility |
|---|---|
Plugin |
Wires all components together on plugins_loaded |
Installer |
Creates DB tables and roles on activation |
Schema |
CREATE TABLE SQL strings for dbDelta |
AdminMenu |
Registers wp-admin menu pages |
RestRegistrar |
Registers all REST routes under us-scheduler/v1 |
ShortcodeRegistrar |
Registers [us_booking] and [us_student_login] shortcodes |
Auth\RoleManager |
Registers us_instructor and us_student roles with custom caps |
Auth\LoginPage |
Renders front-end student login form |
Availability\AvailabilitySlot |
Immutable value object for a slot row |
Availability\AvailabilityRepository |
CRUD for availability slots |
Availability\AvailabilityController |
Instructor availability management page |
Availability\AvailabilityEndpoint |
REST handlers for availability CRUD |
Booking\Lesson |
Immutable value object for a lesson row |
Booking\BookingRepository |
CRUD for lesson bookings |
Booking\BookingEndpoint |
REST handlers for booking and status updates |
Booking\BookingPage |
Renders student booking UI shell (JS takes over) |
Booking\LessonController |
Admin and instructor lesson list pages |
REST API Namespace
All endpoints live under /wp-json/us-scheduler/v1/. Permissions are enforced via permission_callback using capability checks (manage_availability, book_lesson), never role name checks.
Testing Approach
Tests use Brain\Monkey to stub WordPress functions without a full WP installation, and Mockery to mock $wpdb and other dependencies.
All test classes extend tests/Unit/TestCase.php, which handles Monkey\setUp() / Monkey\tearDown() and stubs all WP translation/escape functions automatically.
Brain\Monkey API notes:
Functions\when('fn')->alias(fn() => ...)— stub with a closure (NOTreturnUsing())Functions\when('fn')->justReturn($val)— stub returning a fixed valueFunctions\expect('fn')->once()->with(...)— assert call count and arguments- Use
Functions\when()(notFunctions\expect()) when you need argument-routing (e.g.get_rolereturning different values per argument) to avoid chaining ambiguity - Mockery matchers (e.g.
\Mockery::type()) inside plain PHP arrays do not work withwith()— use\Mockery::on(fn($arr) => ...)or\Mockery::any()instead - When mocking
$wpdb, set$mock->prefix = 'wp_'explicitly — it is a public property, not a method
Adding a Feature
- Write the feature doc in
docs/features/<feature-name>.md(data model, API, classes, test paths). - Create a domain package under
src/<Domain>/containing all classes for that feature. - Add template(s) under
templates/if needed. - Write unit tests under
tests/Unit/<Domain>/mirroring thesrc/<Domain>/structure. - Run
composer test— all tests must pass before the feature is complete.
CI
Gitea Actions (.gitea/workflows/ci.yml) runs on every push and pull request:
- lint — PHPCS WordPress coding standards
- static-analysis — PHPStan level 6
- test — PHPUnit on PHP 8.1, 8.2, 8.3
- no-debug — rejects commits with
var_dump,error_log, etc. insrc/