Skip to content

feat: heartbeat endpoint + docs + scaffolder UI + provider pipeline#49

Merged
Nejcc merged 1 commit into
masterfrom
dev
May 27, 2026
Merged

feat: heartbeat endpoint + docs + scaffolder UI + provider pipeline#49
Nejcc merged 1 commit into
masterfrom
dev

Conversation

@Nejcc

@Nejcc Nejcc commented May 27, 2026

Copy link
Copy Markdown
Collaborator

Major additions in one batch — work spans framework internals, dev tooling, and self-hosted docs.

framework / core

  • Wire the Service Provider pipeline that already lived in Kernel under the misleading loadServices name. loadProviders/finalizeProviders now read Env::get('providers') and call before()/after() around the middleware+controller run. before() pre-flight, after() post-flush.
  • Move PSR-4 autoload mapping out of config/Providers.php (where it was misnamed) into new config/Autoload.php. Providers.php is now an actual list of ServiceProvider classes. Bootstrap/Autoload.php reads the new autoload key with a legacy fallback to providers.
  • Container: add buildPlan cache to skip ReflectionClass on repeat resolves. ~3 µs faster per make() steady state, real win under persistent workers (RoadRunner / FrankenPHP) where plans live across requests.
  • Response::send(): two bugs. Stop clobbering Content-Type set by the controller with Accept-negotiated value (was emitting literal "/"). Stop double json_encode'ing string bodies in the application/json branch. Both needed for /heartbeat JSON to render correctly.
  • DebugTimer: timeline(includeOpen=true) reports in-progress spans so mid-request observers see middleware + controller frames that haven't end()'d. New record(label, cat, startNs, endNs) injects closed spans retroactively (used to backfill the pre-dt() autoload window).
  • RequestRecorder self-instruments via a "recorder snapshot" span so its own work is visible in the recording it writes.
  • Kernel: wrap finalizeProviders + add 'kernel construct' + 'request init' spans. Full lifecycle now accounts for ~93% of total_ms with every named phase visible.

/heartbeat (new)

  • Built-in self-check endpoint. 9 subsystem probes (php, config, container, routes, middlewares, providers, storage, database, assets) rolled up to ok / degraded / down. HTTP 200 / 503 for probes.
  • performance section: lifecycle timeline (closed + open spans), last completed request (read from recorder for 100% closed picture), 6 synthetic micro-benchmarks (median of 5 cold runs), memory + opcache stats.
  • HTML view at ?view=html (or browser Accept negotiation) — waterfall chart with light/dark theme, tinted cards for warn/fail checks, striped animation for in-progress spans, top-right corner ribbons, coverage % per timeline.

/new + / (scaffolder UI)

  • Move scaffolder from Welcome to /new (config-gated, default route overrideable). / now renders the same Scaffolder page.
  • Typed create/remove for 11 artifacts: page, controller, model, service, repository, middleware, provider, observer, dto, vo, plus resource composite (model + repository + service + page).
  • Slash commands: /create [type] , /remove [type] , /docs . Suggestions dropdown opens on focus, filters as you type, Tab/arrow/Enter navigation.
  • Default scaffold template upgraded — opts out of dark Layout, uses zinc/white palette, includes back-link CTA, theme switcher per page.

/docs/ (new — static page)

  • Self-hosted docs at public/docs/index.html. Vue 3 + Tailwind 4 + Prism, all from CDN. 45 topics across 8 categories: Introduction, Getting Started, Routing & HTTP, Wisp, Architecture, Data, Helpers & Internals, Tooling.
  • Three-column layout: left sidebar (categorized nav with scroll-spy), center content (anchored sections), right sidebar (on this page rail
    • quick links). Header sticky with search.
  • Every topic has a syntax-highlighted code example with Copy button.
  • Theme switcher synced with the rest of the app via localStorage.

other

  • app/Routes/Api.php: closure route → ApiController so the optimize route cache can include it.
  • Welcome.vue rewritten as a landing page (was the scaffolder).
  • About.vue (new) — example of the new default scaffold template.
  • app/Resources/css/app.css + app.ghost.tpl: minor.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Welcome, About, and Users pages
    • Added Scaffolder interface to generate controllers, models, pages, and other code artifacts
    • Added integrated documentation site with search and code examples
    • Added system health check endpoint
    • Added theme switcher (light/dark/auto) with persistent preferences
  • Improvements

    • Enhanced theme detection across the application with system preference support
    • Improved performance for dependency resolution

Review Change Stack

Major additions in one batch — work spans framework internals, dev tooling,
and self-hosted docs.

framework / core
  - Wire the Service Provider pipeline that already lived in Kernel under
    the misleading `loadServices` name. `loadProviders`/`finalizeProviders`
    now read `Env::get('providers')` and call before()/after() around the
    middleware+controller run. before() pre-flight, after() post-flush.
  - Move PSR-4 autoload mapping out of `config/Providers.php` (where it
    was misnamed) into new `config/Autoload.php`. Providers.php is now an
    actual list of ServiceProvider classes. Bootstrap/Autoload.php reads
    the new `autoload` key with a legacy fallback to `providers`.
  - Container: add buildPlan cache to skip ReflectionClass on repeat
    resolves. ~3 µs faster per make() steady state, real win under
    persistent workers (RoadRunner / FrankenPHP) where plans live across
    requests.
  - Response::send(): two bugs. Stop clobbering Content-Type set by the
    controller with Accept-negotiated value (was emitting literal "*/*").
    Stop double json_encode'ing string bodies in the application/json
    branch. Both needed for /heartbeat JSON to render correctly.
  - DebugTimer: timeline(includeOpen=true) reports in-progress spans so
    mid-request observers see middleware + controller frames that haven't
    end()'d. New record(label, cat, startNs, endNs) injects closed spans
    retroactively (used to backfill the pre-dt() autoload window).
  - RequestRecorder self-instruments via a "recorder snapshot" span so
    its own work is visible in the recording it writes.
  - Kernel: wrap finalizeProviders + add 'kernel construct' + 'request
    init' spans. Full lifecycle now accounts for ~93% of total_ms with
    every named phase visible.

/heartbeat (new)
  - Built-in self-check endpoint. 9 subsystem probes (php, config,
    container, routes, middlewares, providers, storage, database, assets)
    rolled up to ok / degraded / down. HTTP 200 / 503 for probes.
  - performance section: lifecycle timeline (closed + open spans), last
    completed request (read from recorder for 100% closed picture), 6
    synthetic micro-benchmarks (median of 5 cold runs), memory + opcache
    stats.
  - HTML view at ?view=html (or browser Accept negotiation) — waterfall
    chart with light/dark theme, tinted cards for warn/fail checks,
    striped animation for in-progress spans, top-right corner ribbons,
    coverage % per timeline.

/new + / (scaffolder UI)
  - Move scaffolder from Welcome to /new (config-gated, default route
    overrideable). / now renders the same Scaffolder page.
  - Typed create/remove for 11 artifacts: page, controller, model,
    service, repository, middleware, provider, observer, dto, vo, plus
    `resource` composite (model + repository + service + page).
  - Slash commands: /create [type] <name>, /remove [type] <name>, /docs
    <keywords>. Suggestions dropdown opens on focus, filters as you type,
    Tab/arrow/Enter navigation.
  - Default scaffold template upgraded — opts out of dark Layout, uses
    zinc/white palette, includes back-link CTA, theme switcher per page.

/docs/ (new — static page)
  - Self-hosted docs at public/docs/index.html. Vue 3 + Tailwind 4 +
    Prism, all from CDN. 45 topics across 8 categories: Introduction,
    Getting Started, Routing & HTTP, Wisp, Architecture, Data, Helpers
    & Internals, Tooling.
  - Three-column layout: left sidebar (categorized nav with scroll-spy),
    center content (anchored sections), right sidebar (on this page rail
    + quick links). Header sticky with search.
  - Every topic has a syntax-highlighted code example with Copy button.
  - Theme switcher synced with the rest of the app via localStorage.

other
  - app/Routes/Api.php: closure route → ApiController so the optimize
    route cache can include it.
  - Welcome.vue rewritten as a landing page (was the scaffolder).
  - About.vue (new) — example of the new default scaffold template.
  - app/Resources/css/app.css + app.ghost.tpl: minor.
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2786f4ca-cbe6-4e59-9cd1-7c717f3039ba

📥 Commits

Reviewing files that changed from the base of the PR and between 8fe9c8f and 623cd70.

📒 Files selected for processing (31)
  • app/Controllers/AboutController.php
  • app/Controllers/ApiController.php
  • app/Controllers/UsersController.php
  • app/Controllers/WelcomeController.php
  • app/Resources/css/app.css
  • app/Resources/js/Pages/About.vue
  • app/Resources/js/Pages/Scaffolder.vue
  • app/Resources/js/Pages/Users.vue
  • app/Resources/js/Pages/Welcome.vue
  • app/Resources/views/app.ghost.tpl
  • app/Routes/Api.php
  • app/Routes/Web.php
  • packages/silverengine/core/src/App/Controllers/HeartbeatController.php
  • packages/silverengine/core/src/App/Controllers/NewController.php
  • packages/silverengine/core/src/App/Controllers/ScaffoldController.php
  • packages/silverengine/core/src/App/Routes.php
  • packages/silverengine/core/src/App/Views/heartbeat.php
  • packages/silverengine/core/src/Config/Autoload.php
  • packages/silverengine/core/src/Config/Providers.php
  • packages/silverengine/core/src/Config/Scaffolder.php
  • packages/silverengine/core/src/Config/Services.php
  • packages/silverengine/core/src/Core/Bootstrap/Autoload.php
  • packages/silverengine/core/src/Core/Container.php
  • packages/silverengine/core/src/Core/Kernel.php
  • packages/silverengine/core/src/Http/Response.php
  • packages/silverengine/core/src/Support/DebugTimer.php
  • packages/silverengine/core/src/Support/Heartbeat.php
  • packages/silverengine/core/src/Support/RequestRecorder.php
  • packages/silverengine/core/src/Support/Scaffolder.php
  • public/docs/index.html
  • public/index.php

📝 Walkthrough

Walkthrough

This PR introduces a complete code-scaffolding system with UI, framework health-check diagnostics, dark-mode support across application pages, configuration reorganization, and a comprehensive documentation SPA. Core framework changes include provider lifecycle transition, Container build-plan caching, Response content-type preservation, and enhanced debug timing.

Changes

Dark Mode and Application Pages

Layer / File(s) Summary
Dark mode CSS and template infrastructure
app/Resources/css/app.css, app/Resources/views/app.ghost.tpl
Tailwind custom dark variant enables class-based dark mode; pre-paint script in Wisp template reads localStorage theme and applies dark class to avoid flicker.
Welcome page refactoring with scaffolder context
app/Controllers/WelcomeController.php, app/Resources/js/Pages/Welcome.vue
WelcomeController now returns wisp('Scaffolder', ...) with phpVersion, branch, routes, and canScaffold props. Welcome.vue rewritten with theme toggle and conditional scaffolder link (gated by local + debug env).
About and Users pages with theme support
app/Controllers/AboutController.php, app/Resources/js/Pages/About.vue, app/Controllers/UsersController.php, app/Resources/js/Pages/Users.vue
New AboutController and UsersController render Wisp views; About.vue and Users.vue SFCs provide themed pages with theme persistence (localStorage + matchMedia).
API controller and route registration
app/Controllers/ApiController.php, app/Routes/Api.php, app/Routes/Web.php
ApiController returns JSON welcome message; Api.php routes to controller instead of inline closure; Web.php registers /about and /users routes.

Code Scaffolder Feature

Layer / File(s) Summary
Scaffolder feature configuration
packages/silverengine/core/src/Config/Scaffolder.php
New config with enabled (default true) and route (default /new) settings; documents environment gating (local + debug required).
Scaffolder.vue interactive UI component
app/Resources/js/Pages/Scaffolder.vue
Large Vue component: parses command input into action/type/name, validates names, computes file/route plans, generates PHP/Vue/route stubs, theme toggle, clipboard copy helpers, POST submission to /__silver/scaffold, error/success handling, and docs-search mode.
Scaffolder backend: NewController, ScaffoldController, Scaffolder class
packages/silverengine/core/src/App/Controllers/NewController.php, packages/silverengine/core/src/App/Controllers/ScaffoldController.php, packages/silverengine/core/src/Support/Scaffolder.php
NewController gates Scaffolder.vue UI (dev-only). ScaffoldController handles POST with action/type/name/url branching and legacy URL-based paths. Scaffolder class adds create(type, name) / remove(type, name) public methods for type-driven scaffolding and enhanced unscaffold(url) with route/import/file cleanup.
Scaffolder route registration
packages/silverengine/core/src/App/Routes.php
Routes.php registers conditional GET route (path from config, default /new) for NewController.

Health Check and Diagnostics System

Layer / File(s) Summary
Heartbeat health-check orchestrator
packages/silverengine/core/src/Support/Heartbeat.php
Runs subsystem probes (PHP/opcache, config, container, routes, middleware/providers, storage, database, assets), computes ok/degraded/down status, synthesizes performance metrics (micro-benchmarks, lifecycle timings, last-request summary, memory/opcache stats).
HeartbeatController and /heartbeat route
packages/silverengine/core/src/App/Controllers/HeartbeatController.php, packages/silverengine/core/src/App/Routes.php
HeartbeatController invokes Heartbeat, maps status to HTTP code (503 only for down), sets no-cache headers, negotiates HTML/JSON output based on ?view param and Accept header. Routes.php registers GET /heartbeat.
Heartbeat HTML diagnostic dashboard
packages/silverengine/core/src/App/Views/heartbeat.php
Full HTML dashboard with inline CSS: verdict hero, KPI cards, subsystem check grid, request lifecycle timeline (including in-progress spans), previous-request timeline, cold-path benchmarks, memory/opcache gauges, and raw JSON details.

Framework Core Infrastructure: Config, Providers, Container, Response, Debug

Layer / File(s) Summary
Configuration files: Autoload, Providers, Services
packages/silverengine/core/src/Config/Autoload.php, packages/silverengine/core/src/Config/Providers.php, packages/silverengine/core/src/Config/Services.php
New Autoload.php returns PSR-4 prefix→directory mappings. Providers.php repurposed from autoload namespaces to provider class configuration. Services.php emptied.
Bootstrap autoload with config lookup
packages/silverengine/core/src/Core/Bootstrap/Autoload.php
Updated to read $mapping from Env::get('autoload') with fallback to legacy providers key.
Kernel provider lifecycle (replacing services)
packages/silverengine/core/src/Core/Kernel.php
Adds $providers property; replaces loadServices()/finalizeServices() with loadProviders()/finalizeProviders(); instantiates providers, calls before() immediately in order, defers after() to request end. Updates instrumentation to 'providers' and 'finalize providers' phases.
Container build plan caching for constructor resolution
packages/silverengine/core/src/Core/Container.php
Adds $buildPlans cache to store precomputed per-class constructor metadata. build() refactored to use cached plans; new planFor() computes and caches parameter kinds (class autowire/optional/required).
Response content-type preservation and JSON handling
packages/silverengine/core/src/Http/Response.php
send() preserves explicit Content-Type headers, maps */* to text/html, normalizes by stripping parameters. JSON body handling refactored with match(true) over $body: passes strings through, encodes RenderInterface via data(), encodes other values with json_encode().
Debug timing infrastructure: DebugTimer and RequestRecorder
packages/silverengine/core/src/Support/DebugTimer.php, packages/silverengine/core/src/Support/RequestRecorder.php
DebugTimer adds record() to inject retroactive closed spans; timeline() accepts $includeOpen flag and emits duration_ms / in_progress fields. RequestRecorder captures self-timing overhead in persisted timeline.
Bootstrap timing instrumentation
public/index.php
Adds dt()->record('autoload + bootstrap', ...) to backfill pre-boot window; wraps new Kernel() with dt()->begin/end('kernel construct').

Documentation

Layer / File(s) Summary
Comprehensive docs SPA with categories and examples
public/docs/index.html
Standalone CDN-based SPA: loads Tailwind/Vue3/Prism, embeds CATEGORIES documentation model, implements search/filtering (?q= sync), theme persistence (light/auto/dark) with system sync, copy-to-clipboard for code blocks, sidebar highlighting, hash-based scrolling, responsive layout.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • SilverEngine/Framework#48: Both PRs modify the same routing/controller surface—app/Controllers/WelcomeController.php's invokable __invoke() endpoint and related app/Routes/Web.php wiring are refactored/updated—so the changes are directly connected at the code level.

Poem

🐰 A scaffolder's song:
With dark mode and health checks in tow,
We build the framework's UI glow—
Controllers, pages, docs to show,
While timers tick and providers flow.
From config to the heartbeat's cheer,
The rabbit coded far and near! 🐇✨

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Comment @coderabbitai help to get the list of available commands and usage tips.

@Nejcc Nejcc merged commit 37a54cd into master May 27, 2026
1 check was pending
@coderabbitai coderabbitai Bot mentioned this pull request May 27, 2026
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant