Zoosper CMSDocumentationGitHub

Developer guide

Repository layout

Development workflow

Run focused Pest tests first, then the full suite. Before committing, run module compilation, the strict gate and release checks.

Design rules

Controllers are thin HTTP adapters. Business rules belong in services. Persistence belongs in repositories. Templates own markup. Modules expose contracts through configuration, services, routes, permissions, assets and migrations.

A first-party package must declare the owning Composer package for every Marko namespace used by its runtime source. A root or sibling transitive dependency is not sufficient; direct imports and direct requirements must remain aligned.

Declare each route method and path only once across enabled modules. The Router rejects duplicate normalised method-and-path registrations; use a distinct method or path rather than relying on module order or silent replacement. Authenticated-only Admin routes and controller-authorised PAT API routes remain valid current patterns until a separate route-metadata decision changes them.

API Grid generator

Run php8.5 bin/zoosper make:api-grid Acme/RemoteRecords --key=acme.remote-records --route=/admin/remote-records to create a standalone package skeleton. The generated integration is deliberately disabled. Developers must implement endpoint-specific mapping, deployment-owned base URL and credentials, permissions, controller and feature presentation before enabling its route or menu.

The scaffold provides bounded first-party dependencies, request and response mapper starting points, valid and malformed response fixtures, a package test, export-ignore policy and complete package documentation headings. It never edits root Composer metadata automatically. Review the package, add its path repository and requirement explicitly, refresh the lock file, then run focused tests, Psalm, strict quality and the complete release gates.

Testing fixtures and maintained example

Use Zoosper\ApiGrid\Testing\FakeApiTransport to queue deterministic responses and inspect mapped requests without networking. Use ApiResponseFixture::success() and ApiResponseFixture::failure() to construct bounded transport results. The source-only integration under examples/api-grid-integration/ demonstrates deployment-owned scope, request mapping, strict response mapping and a neutral numbered Grid result.

API Grid compatibility and upgrade policy

API Grid public interfaces, failure categories, configuration keys, service identifiers, capability meanings and cursor semantics are compatibility boundaries. Compatible additions may add optional metadata, capabilities or helpers without changing existing defaults. A breaking signature, category, required configuration, pagination meaning or security default requires a new minor release line and an explicit migration note. First-party packages remain on the synchronised release train with bounded ^0.3.1@alpha dependencies. Deploy the committed root lock file, review generated packages before registration, and rerun focused tests, Psalm, strict quality, the full suite, module compilation and release checks after any upgrade.

Admin middleware requirements

At least one Admin middleware manifest must be discoverable in production application composition. Zoosper fails boot rather than registering Admin routes with an empty middleware pipeline. Public, authenticated-only, and permission-protected Admin routes remain intentional access classes evaluated by the discovered middleware.

API authorization parity

When adding an API route, classify it explicitly as reviewed anonymous, session-authenticated, or bearer-authenticated. Feature-owned bearer controllers must retain PersonalAccessTokenAuthenticator and enforce the required token scope and current user permission before reading or mutating protected resources. Update the central parity allow-list only for endpoints intentionally designed for anonymous access.

API object authorization

Classify each protected API resource as request-Site scoped or application-level. Request-Site resources must resolve collection and object lookups through the current SiteContext and return not found for cross-Site identifiers. Application-level resources must retain their narrow PAT scope and current-user management permission. Extend the central parity contract whenever a new protected resource class is introduced.

API response data

API collection endpoints must use server-owned pagination with a default page size of 20 and a maximum page size of 100. Preserve the resource collection key and return pagination with page, page_size, page_count, and total. Repository queries must apply Site scope before COUNT, LIMIT, and OFFSET.

Define an explicit response map for every API resource. Do not return domain objects, repository rows or upstream payloads directly. Include only fields required by the consumer, and exclude credentials, hashes, authorization values, protected secrets, recovery material and private filesystem or storage paths. Extend the central parity contract when adding a new protected API controller or external response mapper.