From dd9e2937d2803f59d755337206e39ab0c7dfab47 Mon Sep 17 00:00:00 2001 From: Snider Date: Fri, 13 Mar 2026 13:38:03 +0000 Subject: [PATCH] docs: add CLAUDE.md project instructions Co-Authored-By: Virgil --- CLAUDE.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..82789ea --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,61 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is `lthn/service`, a Composer package for the Core PHP Framework (Laravel-based). It provides SaaS service discovery, dependency resolution, versioning, health checks, and generic landing pages for services. It is a library package — not a standalone application. + +**License:** EUPL-1.2 +**PHP:** ^8.2 +**Dependency:** `lthn/php` (the Core PHP Framework) + +## Commands + +There is no standalone build, lint, or test runner in this repo. This package is consumed by a host Laravel application. To run tests: + +```bash +# From the host application that requires this package: +./vendor/bin/phpunit vendor/lthn/service/src/Core/Service/Tests/ +# Single test file: +./vendor/bin/phpunit vendor/lthn/service/src/Core/Service/Tests/Unit/ServiceVersionTest.php +``` + +Tests use PHPUnit with `#[Test]` attributes (not `@test` annotations or `test_` prefixes). + +## Architecture + +The package has two distinct layers with separate PSR-4 namespaces: + +### Core Layer (`Core\Service\` → `src/Core/Service/`) + +Framework-level service infrastructure: + +- **ServiceDiscovery** — Scans module paths for `ServiceDefinition` implementations, validates dependencies, resolves initialization order via topological sort, caches results for 1 hour (configurable via `core.services.cache_discovery`) +- **Contracts/** — `ServiceDefinition` (extends `AdminMenuProvider` from `Core\Front\Admin`), `ServiceDependency` (required/optional with semver constraints), `HealthCheckable` +- **ServiceVersion** — Immutable readonly value object following semver with deprecation/sunset lifecycle +- **HealthCheckResult** — Immutable readonly result with factory methods (`healthy()`, `degraded()`, `unhealthy()`, `fromException()`) +- **Enums/ServiceStatus** — Backed enum: healthy, degraded, unhealthy, unknown +- **Concerns/HasServiceVersion** — Trait providing default `version()` (1.0.0) and `dependencies()` (empty) for ServiceDefinition implementations +- **ServiceDependencyException** — Named constructors: `circular()`, `missing()`, `versionMismatch()` + +### Website Layer (`Core\Website\Service\` → `src/Website/Service/`) + +Public marketing/landing pages served as Livewire components: + +- **Boot** — Laravel ServiceProvider that registers Blade views (`service::` namespace) and web routes +- **View/Landing** — Livewire component for service landing page, resolves workspace via subdomain (e.g., `social.host.test` → `social`) +- **View/Features** — Livewire component with per-service feature lists (matched by workspace slug) +- **Routes/web.php** — Two routes: `/` (Landing) and `/features` (Features) +- **View/Blade/** — Blade templates using `service::` namespace with layout and components + +## Key Patterns + +- All PHP files use `declare(strict_types=1)` +- Value objects are `final readonly class` +- Factory methods preferred over constructor calls for result types +- Service definitions use static methods (`definition()`, `version()`, `dependencies()`) +- `ServiceDefinition::definition()` must return array with required keys: `code`, `module`, `name` +- Service codes must match pattern: `/^[a-z][a-z0-9_-]*$/i` +- Subdomain routing: `{slug}.host.{tld}` pattern for workspace resolution +- Config keys prefixed with `core.` (e.g., `core.services.cache_discovery`, `core.module_paths`, `core.app.name`)