{"section":"cli","slug":"orm-console","featureTitle":"ORM Console Toolkit","summary":"The ORM ships with a practical CLI surface: status, diff, sync, and seed commands with dry-run safety and SQL plan export.","entryLine":"Framework credibility also lives in operations. The ORM CLI should tell you what will change before it changes anything.","highlights":["orm:status","orm:diff","orm:sync","orm:seed","--output"],"learnMoreLabel":"See the command surface →","deepDiveLabel":"What each command is for →","documentBodyHtml":"<article class=\"sx-docs-fragment\" data-doc-id=\"cli/orm-console\" data-doc-locale=\"en\">\n<h1>ORM Console Toolkit</h1>\n<p>Framework credibility also lives in operations. The ORM CLI should tell you what will change before it changes anything.</p>\n<h2>How it works</h2>\n<p><code>orm:status</code> shows database capabilities and whether the schema is in sync. <code>orm:diff</code> lists code-versus-database differences without applying them. <code>orm:sync --dry-run</code> builds the execution plan as reviewable output, and <code>--output</code> exports it to a SQL file for audit trails. <code>orm:seed</code> runs <code>defaults()</code> upserts for seedable resources to make local and demo environments reproducible.</p>\n<h2>Why this matters</h2>\n<p>Teams that skip review tooling end up applying schema changes they did not fully understand. Treating <code>orm:sync --dry-run</code> as the normal review path — rather than an exotic flag — shortens incident recovery and makes schema changes safe to delegate.</p>\n</article>","sectionLabel":"CLI","navSections":[{"key":"get-started","label":"Start Here","sidebarLabel":"Get Started","summary":"The shortest path from fresh scaffold to a trustworthy local Semitexa runtime: install, boot, understand the module map, bind a real host, and reach the first tenant boundary.","icon":"GO","eyebrow":"Onboarding","starter":true,"prerequisites":[],"featureCount":7,"href":"/demo/get-started","features":[{"section":"get-started","slug":"module-structure","label":"Start Here","title":"Module Structure","summary":"The minimal Semitexa module is a typed HTTP spine of payload, handler, resource, and template.","opensInNewTab":false,"href":"/demo/get-started/module-structure"},{"section":"get-started","slug":"installation","label":"Start Here","title":"Installation","summary":"Create the project, review the baseline env contract, and bring up the Semitexa runtime the supported way.","opensInNewTab":false,"href":"/demo/get-started/installation"},{"section":"get-started","slug":"local-domain","label":"Start Here","title":"Local Domain","summary":"Register .test domains through the built-in local-domain helper instead of relying on ad hoc host setup.","opensInNewTab":false,"href":"/demo/get-started/local-domain"},{"section":"get-started","slug":"base-tenant","label":"Start Here","title":"Base Tenant","summary":"Establish one default tenant context early so tenant-aware behavior is visible before the rest of the application grows.","opensInNewTab":false,"href":"/demo/get-started/base-tenant"},{"section":"get-started","slug":"locale-setup","label":"Start Here","title":"Locale Setup","summary":"Configure the minimal Locale contract so translations and locale-aware rendering become explicit early.","opensInNewTab":false,"href":"/demo/get-started/locale-setup"},{"section":"get-started","slug":"ai-console","label":"Start Here","title":"AI Console","summary":"Use the Semitexa AI console as a command translation surface over real operator commands.","opensInNewTab":false,"href":"/demo/get-started/ai-console"},{"section":"get-started","slug":"beyond-controllers","label":"Start Here","title":"Beyond Controllers","summary":"Understand why Semitexa keeps transport, use case, and rendering as separate explicit responsibilities.","opensInNewTab":false,"href":"/demo/get-started/beyond-controllers"}],"groups":[{"key":"structure","label":"Module Structure","featureCount":1,"features":[{"section":"get-started","slug":"module-structure","label":"Start Here","title":"Module Structure","summary":"The minimal Semitexa module is a typed HTTP spine of payload, handler, resource, and template.","opensInNewTab":false,"href":"/demo/get-started/module-structure"}]},{"key":"onboarding","label":"Onboarding","featureCount":6,"features":[{"section":"get-started","slug":"installation","label":"Start Here","title":"Installation","summary":"Create the project, review the baseline env contract, and bring up the Semitexa runtime the supported way.","opensInNewTab":false,"href":"/demo/get-started/installation"},{"section":"get-started","slug":"local-domain","label":"Start Here","title":"Local Domain","summary":"Register .test domains through the built-in local-domain helper instead of relying on ad hoc host setup.","opensInNewTab":false,"href":"/demo/get-started/local-domain"},{"section":"get-started","slug":"base-tenant","label":"Start Here","title":"Base Tenant","summary":"Establish one default tenant context early so tenant-aware behavior is visible before the rest of the application grows.","opensInNewTab":false,"href":"/demo/get-started/base-tenant"},{"section":"get-started","slug":"locale-setup","label":"Start Here","title":"Locale Setup","summary":"Configure the minimal Locale contract so translations and locale-aware rendering become explicit early.","opensInNewTab":false,"href":"/demo/get-started/locale-setup"},{"section":"get-started","slug":"ai-console","label":"Start Here","title":"AI Console","summary":"Use the Semitexa AI console as a command translation surface over real operator commands.","opensInNewTab":false,"href":"/demo/get-started/ai-console"},{"section":"get-started","slug":"beyond-controllers","label":"Start Here","title":"Beyond Controllers","summary":"Understand why Semitexa keeps transport, use case, and rendering as separate explicit responsibilities.","opensInNewTab":false,"href":"/demo/get-started/beyond-controllers"}]}]},{"key":"routing","label":"Routing & Handlers","summary":"Attribute-driven routes, typed handlers, and content negotiation in one coherent request pipeline.","icon":"RT","eyebrow":"HTTP Layer","starter":true,"prerequisites":[],"featureCount":7,"href":"/demo/routing","features":[{"section":"routing","slug":"basic","label":"Routing & Handlers","title":"Basic Route","summary":"Define a route with one access attribute on the payload — no XML, no YAML, no config files.","opensInNewTab":false,"href":"/demo/routing/basic"},{"section":"routing","slug":"parameterized","label":"Routing & Handlers","title":"Parameterized Route","summary":"Path parameters with regex constraints and typed injection.","opensInNewTab":false,"href":"/demo/routing/parameterized/headphones"},{"section":"routing","slug":"env-route-override","label":"Routing & Handlers","title":"Env Route Override","summary":"Keep the payload as the route source of truth while allowing operations to remap the public URL through .env.","opensInNewTab":false,"href":"/demo/routing/env-route-override"},{"section":"routing","slug":"payload-shield","label":"Routing & Handlers","title":"Payload As A Shield","summary":"Hydration happens before the handler, and each setter owns the normalization and guard logic for its own field.","opensInNewTab":false,"href":"/demo/routing/payload-shield"},{"section":"routing","slug":"payload-parts","label":"Routing & Handlers","title":"Payload Parts","summary":"One module owns the route, another module can extend the same payload contract without forking or reopening the base class.","opensInNewTab":false,"href":"/demo/routing/payload-parts"},{"section":"routing","slug":"content-negotiation","label":"Routing & Handlers","title":"Content Negotiation","summary":"One endpoint, multiple response formats — automatically.","opensInNewTab":false,"href":"/demo/routing/content-negotiation"},{"section":"routing","slug":"public-endpoint","label":"Routing & Handlers","title":"Public Payload","summary":"Anonymous endpoints opt in explicitly with the public access attribute. Every other payload requires authentication.","opensInNewTab":false,"href":"/demo/routing/public-endpoint"}],"groups":[{"key":"foundations","label":"Foundations","featureCount":3,"features":[{"section":"routing","slug":"basic","label":"Routing & Handlers","title":"Basic Route","summary":"Define a route with one access attribute on the payload — no XML, no YAML, no config files.","opensInNewTab":false,"href":"/demo/routing/basic"},{"section":"routing","slug":"parameterized","label":"Routing & Handlers","title":"Parameterized Route","summary":"Path parameters with regex constraints and typed injection.","opensInNewTab":false,"href":"/demo/routing/parameterized/headphones"},{"section":"routing","slug":"env-route-override","label":"Routing & Handlers","title":"Env Route Override","summary":"Keep the payload as the route source of truth while allowing operations to remap the public URL through .env.","opensInNewTab":false,"href":"/demo/routing/env-route-override"}]},{"key":"request-model","label":"Request Model","featureCount":2,"features":[{"section":"routing","slug":"payload-shield","label":"Routing & Handlers","title":"Payload As A Shield","summary":"Hydration happens before the handler, and each setter owns the normalization and guard logic for its own field.","opensInNewTab":false,"href":"/demo/routing/payload-shield"},{"section":"routing","slug":"payload-parts","label":"Routing & Handlers","title":"Payload Parts","summary":"One module owns the route, another module can extend the same payload contract without forking or reopening the base class.","opensInNewTab":false,"href":"/demo/routing/payload-parts"}]},{"key":"delivery","label":"Delivery","featureCount":2,"features":[{"section":"routing","slug":"content-negotiation","label":"Routing & Handlers","title":"Content Negotiation","summary":"One endpoint, multiple response formats — automatically.","opensInNewTab":false,"href":"/demo/routing/content-negotiation"},{"section":"routing","slug":"public-endpoint","label":"Routing & Handlers","title":"Public Payload","summary":"Anonymous endpoints opt in explicitly with the public access attribute. Every other payload requires authentication.","opensInNewTab":false,"href":"/demo/routing/public-endpoint"}]}]},{"key":"di","label":"Dependency Injection","summary":"Single-path DI with explicit lifecycles, deterministic contracts, and stable boot behavior for long-running workers.","icon":"DI","eyebrow":"Container","starter":true,"prerequisites":[],"featureCount":5,"href":"/demo/di","features":[{"section":"di","slug":"overview","label":"Dependency Injection","title":"DI Canon","summary":"One canonical DI path for container-managed classes: explicit properties, explicit lifecycles, deterministic boot.","opensInNewTab":false,"href":"/demo/di/overview"},{"section":"di","slug":"readonly","label":"Dependency Injection","title":"Readonly Injection","summary":"One explicit DI path, one shared worker instance — fast at runtime and stable under reload.","opensInNewTab":false,"href":"/demo/di/readonly"},{"section":"di","slug":"mutable","label":"Dependency Injection","title":"Mutable Injection","summary":"Execution-scoped services get a fresh clone every run — safe state without contaminating the worker.","opensInNewTab":false,"href":"/demo/di/mutable"},{"section":"di","slug":"factory","label":"Dependency Injection","title":"Factory Injection","summary":"On-demand creation stays explicit — lazy instances without falling back to service locator habits.","opensInNewTab":false,"href":"/demo/di/factory"},{"section":"di","slug":"contracts","label":"Dependency Injection","title":"Service Contracts","summary":"Depend on contracts, but keep ownership explicit — deterministic substitution instead of runtime magic.","opensInNewTab":false,"href":"/demo/di/contracts"}],"groups":[{"key":"container-basics","label":"Container Basics","featureCount":5,"features":[{"section":"di","slug":"overview","label":"Dependency Injection","title":"DI Canon","summary":"One canonical DI path for container-managed classes: explicit properties, explicit lifecycles, deterministic boot.","opensInNewTab":false,"href":"/demo/di/overview"},{"section":"di","slug":"readonly","label":"Dependency Injection","title":"Readonly Injection","summary":"One explicit DI path, one shared worker instance — fast at runtime and stable under reload.","opensInNewTab":false,"href":"/demo/di/readonly"},{"section":"di","slug":"mutable","label":"Dependency Injection","title":"Mutable Injection","summary":"Execution-scoped services get a fresh clone every run — safe state without contaminating the worker.","opensInNewTab":false,"href":"/demo/di/mutable"},{"section":"di","slug":"factory","label":"Dependency Injection","title":"Factory Injection","summary":"On-demand creation stays explicit — lazy instances without falling back to service locator habits.","opensInNewTab":false,"href":"/demo/di/factory"},{"section":"di","slug":"contracts","label":"Dependency Injection","title":"Service Contracts","summary":"Depend on contracts, but keep ownership explicit — deterministic substitution instead of runtime magic.","opensInNewTab":false,"href":"/demo/di/contracts"}]}]},{"key":"data","label":"Persistence","summary":"Attribute-mapped resources, repositories, filtering, pagination, and relations with real demo data.","icon":"DB","eyebrow":"Persistence","starter":true,"prerequisites":[],"featureCount":9,"href":"/demo/data","features":[{"section":"data","slug":"domain-models","label":"Persistence","title":"Domain-Level Models","summary":"Semitexa separates persistence resources from business models. Resources map tables; domain models carry behavior and invariants.","opensInNewTab":false,"href":"/demo/data/domain-models"},{"section":"data","slug":"repository-workflow","label":"Persistence","title":"Repository Workflow","summary":"The canonical Semitexa path: handlers depend on repository contracts, repositories return domain models, and persistence resources stay behind the boundary.","opensInNewTab":false,"href":"/demo/data/repository-workflow"},{"section":"data","slug":"schema-sync","label":"Persistence","title":"Schema Sync, Not Migration Churn","summary":"Semitexa creates SQL only when the real schema changed, blocks destructive drops by default, and logs the exact DDL plan as SQL and JSON.","opensInNewTab":false,"href":"/demo/data/schema-sync"},{"section":"data","slug":"query","label":"Persistence","title":"Query Builder","summary":"Compose type-safe queries with a fluent API — no raw SQL, no magic strings.","opensInNewTab":false,"href":"/demo/data/query"},{"section":"data","slug":"filtering","label":"Persistence","title":"Filtering","summary":"Mark a property #[Filterable] and the ORM handles the rest — no manual WHERE clauses.","opensInNewTab":false,"href":"/demo/data/filtering"},{"section":"data","slug":"pagination","label":"Persistence","title":"Pagination","summary":"Offset and cursor pagination out of the box — switch modes with a single query parameter.","opensInNewTab":false,"href":"/demo/data/pagination"},{"section":"data","slug":"relations","label":"Persistence","title":"Relations","summary":"Declare parent and child links on the resource itself, then read typed relations from the handler.","opensInNewTab":false,"href":"/demo/data/relations"},{"section":"data","slug":"table-extension","label":"Persistence","title":"Shared Table Extension","summary":"Two modules can extend one table independently, and the ORM merges the schema without forcing either side to edit the other.","opensInNewTab":false,"href":"/demo/data/table-extension"},{"section":"data","slug":"n-plus-one","label":"Persistence","title":"N+1 Without Magic","summary":"Semitexa avoids N+1 by using resource slices for the exact columns and relations each screen needs, instead of hiding database traffic behind implicit relation loading.","opensInNewTab":false,"href":"/demo/data/n-plus-one"}],"groups":[{"key":"modeling","label":"Modeling & Workflow","featureCount":3,"features":[{"section":"data","slug":"domain-models","label":"Persistence","title":"Domain-Level Models","summary":"Semitexa separates persistence resources from business models. Resources map tables; domain models carry behavior and invariants.","opensInNewTab":false,"href":"/demo/data/domain-models"},{"section":"data","slug":"repository-workflow","label":"Persistence","title":"Repository Workflow","summary":"The canonical Semitexa path: handlers depend on repository contracts, repositories return domain models, and persistence resources stay behind the boundary.","opensInNewTab":false,"href":"/demo/data/repository-workflow"},{"section":"data","slug":"schema-sync","label":"Persistence","title":"Schema Sync, Not Migration Churn","summary":"Semitexa creates SQL only when the real schema changed, blocks destructive drops by default, and logs the exact DDL plan as SQL and JSON.","opensInNewTab":false,"href":"/demo/data/schema-sync"}]},{"key":"querying","label":"Querying","featureCount":6,"features":[{"section":"data","slug":"query","label":"Persistence","title":"Query Builder","summary":"Compose type-safe queries with a fluent API — no raw SQL, no magic strings.","opensInNewTab":false,"href":"/demo/data/query"},{"section":"data","slug":"filtering","label":"Persistence","title":"Filtering","summary":"Mark a property #[Filterable] and the ORM handles the rest — no manual WHERE clauses.","opensInNewTab":false,"href":"/demo/data/filtering"},{"section":"data","slug":"pagination","label":"Persistence","title":"Pagination","summary":"Offset and cursor pagination out of the box — switch modes with a single query parameter.","opensInNewTab":false,"href":"/demo/data/pagination"},{"section":"data","slug":"relations","label":"Persistence","title":"Relations","summary":"Declare parent and child links on the resource itself, then read typed relations from the handler.","opensInNewTab":false,"href":"/demo/data/relations"},{"section":"data","slug":"table-extension","label":"Persistence","title":"Shared Table Extension","summary":"Two modules can extend one table independently, and the ORM merges the schema without forcing either side to edit the other.","opensInNewTab":false,"href":"/demo/data/table-extension"},{"section":"data","slug":"n-plus-one","label":"Persistence","title":"N+1 Without Magic","summary":"Semitexa avoids N+1 by using resource slices for the exact columns and relations each screen needs, instead of hiding database traffic behind implicit relation loading.","opensInNewTab":false,"href":"/demo/data/n-plus-one"}]}]},{"key":"auth","label":"Security","summary":"Typed session payloads, machine credentials, RBAC, and route protection without string-key auth chaos.","icon":"AU","eyebrow":"Security","starter":false,"prerequisites":[],"featureCount":7,"href":"/demo/auth","features":[{"section":"auth","slug":"session","label":"Security","title":"Session Auth","summary":"Google signs the user in, then the session stores the selected demo role and re-hydrates it on every request.","opensInNewTab":false,"href":"/demo/auth/session"},{"section":"auth","slug":"session-payloads","label":"Security","title":"Session Payloads","summary":"Semitexa forbids string-key session chaos: session state lives in typed Session Payloads or it does not exist.","opensInNewTab":false,"href":"/demo/auth/session-payloads"},{"section":"auth","slug":"google","label":"Security","title":"Google Authorization","summary":"Authorization is required for demo SSE blocks that keep a long-lived backend connection open.","opensInNewTab":false,"href":"/demo/auth/google"},{"section":"auth","slug":"machine","label":"Security","title":"Machine Auth","summary":"Service-to-service authentication via Bearer tokens — scoped, revocable, and audited.","opensInNewTab":false,"href":"/demo/auth/machine"},{"section":"auth","slug":"protected","label":"Security","title":"Protected Route","summary":"Add one access attribute and one optional permission attribute and the framework enforces access — 401 for unauthenticated requests, 403 for unauthorized ones.","opensInNewTab":false,"href":"/demo/auth/protected"},{"section":"auth","slug":"requires-permission","label":"Security","title":"Requires Permission","summary":"Declare one permission slug on the payload and let the framework enforce it before your handler runs.","opensInNewTab":false,"href":"/demo/auth/requires-permission"},{"section":"auth","slug":"rbac","label":"Security","title":"RBAC","summary":"Hybrid RBAC with coarse-grained capabilities, exact permission slugs, and module-owned permission catalogs.","opensInNewTab":false,"href":"/demo/auth/rbac"}],"groups":[{"key":"identity","label":"Identity","featureCount":4,"features":[{"section":"auth","slug":"session","label":"Security","title":"Session Auth","summary":"Google signs the user in, then the session stores the selected demo role and re-hydrates it on every request.","opensInNewTab":false,"href":"/demo/auth/session"},{"section":"auth","slug":"session-payloads","label":"Security","title":"Session Payloads","summary":"Semitexa forbids string-key session chaos: session state lives in typed Session Payloads or it does not exist.","opensInNewTab":false,"href":"/demo/auth/session-payloads"},{"section":"auth","slug":"google","label":"Security","title":"Google Authorization","summary":"Authorization is required for demo SSE blocks that keep a long-lived backend connection open.","opensInNewTab":false,"href":"/demo/auth/google"},{"section":"auth","slug":"machine","label":"Security","title":"Machine Auth","summary":"Service-to-service authentication via Bearer tokens — scoped, revocable, and audited.","opensInNewTab":false,"href":"/demo/auth/machine"}]},{"key":"access-control","label":"Access Control","featureCount":3,"features":[{"section":"auth","slug":"protected","label":"Security","title":"Protected Route","summary":"Add one access attribute and one optional permission attribute and the framework enforces access — 401 for unauthenticated requests, 403 for unauthorized ones.","opensInNewTab":false,"href":"/demo/auth/protected"},{"section":"auth","slug":"requires-permission","label":"Security","title":"Requires Permission","summary":"Declare one permission slug on the payload and let the framework enforce it before your handler runs.","opensInNewTab":false,"href":"/demo/auth/requires-permission"},{"section":"auth","slug":"rbac","label":"Security","title":"RBAC","summary":"Hybrid RBAC with coarse-grained capabilities, exact permission slugs, and module-owned permission catalogs.","opensInNewTab":false,"href":"/demo/auth/rbac"}]}]},{"key":"events","label":"Async","summary":"Synchronous and deferred event flows, queues, and SSE-style interactions.","icon":"EV","eyebrow":"Async","starter":false,"prerequisites":[],"featureCount":5,"href":"/demo/events","features":[{"section":"events","slug":"arena","label":"Async","title":"Execution Arena","summary":"Launch the same backend intent in sync, Swoole async, and queued modes, then watch the proof arrive over SSE.","opensInNewTab":false,"href":"/demo/events/arena"},{"section":"events","slug":"sync","label":"Async","title":"Sync Events","summary":"Dispatch an event and all sync listeners run before the response is sent.","opensInNewTab":false,"href":"/demo/events/sync"},{"section":"events","slug":"deferred","label":"Async","title":"Deferred Handler","summary":"Heavy work runs after the response is sent — the user gets instant feedback.","opensInNewTab":false,"href":"/demo/events/deferred"},{"section":"events","slug":"queued","label":"Async","title":"Queued Handler","summary":"Events survive restarts and scale across workers — backed by a durable message queue.","opensInNewTab":false,"href":"/demo/events/queued"},{"section":"events","slug":"sse","label":"Async","title":"SSE Stream","summary":"Real-time server push without WebSockets — connect once and receive real backend events over plain HTTP.","opensInNewTab":false,"href":"/demo/events/sse"}],"groups":[{"key":"event-flow","label":"Event Flow","featureCount":5,"features":[{"section":"events","slug":"arena","label":"Async","title":"Execution Arena","summary":"Launch the same backend intent in sync, Swoole async, and queued modes, then watch the proof arrive over SSE.","opensInNewTab":false,"href":"/demo/events/arena"},{"section":"events","slug":"sync","label":"Async","title":"Sync Events","summary":"Dispatch an event and all sync listeners run before the response is sent.","opensInNewTab":false,"href":"/demo/events/sync"},{"section":"events","slug":"deferred","label":"Async","title":"Deferred Handler","summary":"Heavy work runs after the response is sent — the user gets instant feedback.","opensInNewTab":false,"href":"/demo/events/deferred"},{"section":"events","slug":"queued","label":"Async","title":"Queued Handler","summary":"Events survive restarts and scale across workers — backed by a durable message queue.","opensInNewTab":false,"href":"/demo/events/queued"},{"section":"events","slug":"sse","label":"Async","title":"SSE Stream","summary":"Real-time server push without WebSockets — connect once and receive real backend events over plain HTTP.","opensInNewTab":false,"href":"/demo/events/sse"}]}]},{"key":"rendering","label":"UI Rendering & SSR","summary":"One rendering story from handler to HTML: page data, page regions, and live updates stay in the same server-driven model instead of splitting into frontend and backend template logic.","icon":"UI","eyebrow":"Frontend","starter":false,"prerequisites":[],"featureCount":15,"href":"/demo/rendering","features":[{"section":"rendering","slug":"philosophy","label":"UI Rendering & SSR","title":"SSR Philosophy","summary":"Semitexa SSR is one continuous rendering architecture: page, slots, deferred regions, live refresh, and interactive components stay inside one server-owned story.","opensInNewTab":false,"href":"/demo/rendering/philosophy"},{"section":"rendering","slug":"resource-dtos","label":"UI Rendering & SSR","title":"Resource DTOs","summary":"A Resource DTO is the one typed source of presentation data: handlers shape it once, templates consume it everywhere, and no view has to dissect random arrays.","opensInNewTab":false,"href":"/demo/rendering/resource-dtos"},{"section":"rendering","slug":"slots","label":"UI Rendering & SSR","title":"Slot Resources","summary":"Each page region is its own resource pipeline with the same template system as the main page — no scattered partial glue, no mystery wiring.","opensInNewTab":false,"href":"/demo/rendering/slots"},{"section":"rendering","slug":"components","label":"UI Rendering & SSR","title":"Components","summary":"Reusable, attribute-registered UI components — discovered automatically from the classmap.","opensInNewTab":false,"href":"/demo/rendering/components"},{"section":"rendering","slug":"seo","label":"UI Rendering & SSR","title":"SEO","summary":"Set title, description, and Open Graph tags from your handler — no template hacks needed.","opensInNewTab":false,"href":"/demo/rendering/seo"},{"section":"rendering","slug":"assets","label":"UI Rendering & SSR","title":"Asset Pipeline","summary":"Declare assets with glob patterns in assets.json — served, versioned, and injected automatically.","opensInNewTab":false,"href":"/demo/rendering/assets"},{"section":"rendering","slug":"component-scripts","label":"UI Rendering & SSR","title":"Component Script Assets","summary":"A Semitexa SSR component can own its optional enhancement asset, so behavior travels with the component instead of leaking into page-level glue.","opensInNewTab":false,"href":"/demo/rendering/component-scripts"},{"section":"rendering","slug":"deferred-scripts","label":"UI Rendering & SSR","title":"Script Injection","summary":"Deferred blocks carry their own JS — injected once when the block arrives, never duplicated.","opensInNewTab":false,"href":"/demo/rendering/deferred-scripts"},{"section":"rendering","slug":"deferred","label":"UI Rendering & SSR","title":"Deferred Blocks","summary":"SSR renders the shell first, then expensive regions stream in as real HTML over SSE — no SPA handoff and no client-side page rebuild.","opensInNewTab":true,"href":"/demo/rendering/deferred"},{"section":"rendering","slug":"deferred-encapsulation","label":"UI Rendering & SSR","title":"Block Isolation","summary":"Two identical blocks on the same page run independently — scoped DOM, scoped JS, no conflicts.","opensInNewTab":false,"href":"/demo/rendering/deferred-encapsulation"},{"section":"rendering","slug":"deferred-live","label":"UI Rendering & SSR","title":"Live Widgets","summary":"A live slot can refresh itself on a timer while the page stays SSR-first — no SPA runtime and no handwritten polling layer.","opensInNewTab":false,"href":"/demo/rendering/deferred-live"},{"section":"rendering","slug":"reactive-report","label":"UI Rendering & SSR","title":"Reactive Report","summary":"Background work updates an SSR-first slot in place, so the UI feels live without falling back to SPA state orchestration.","opensInNewTab":false,"href":"/demo/rendering/reactive-report"},{"section":"rendering","slug":"reactive-import","label":"UI Rendering & SSR","title":"Reactive Import","summary":"Background batches keep moving, and the page reflects server progress as live HTML instead of a client-managed progress app.","opensInNewTab":false,"href":"/demo/rendering/reactive-import"},{"section":"rendering","slug":"reactive-analytics","label":"UI Rendering & SSR","title":"Reactive Analytics","summary":"Independent analytics jobs can light up one dashboard progressively, while the page stays server-rendered from the first byte.","opensInNewTab":false,"href":"/demo/rendering/reactive-analytics"},{"section":"rendering","slug":"reactive-ai","label":"UI Rendering & SSR","title":"Reactive AI Task","summary":"Submit a task and watch the AI pipeline stages reveal one by one as the cron job processes it.","opensInNewTab":false,"href":"/demo/rendering/reactive-ai"}],"groups":[{"key":"rendering-model","label":"SSR Foundation","featureCount":8,"features":[{"section":"rendering","slug":"philosophy","label":"UI Rendering & SSR","title":"SSR Philosophy","summary":"Semitexa SSR is one continuous rendering architecture: page, slots, deferred regions, live refresh, and interactive components stay inside one server-owned story.","opensInNewTab":false,"href":"/demo/rendering/philosophy"},{"section":"rendering","slug":"resource-dtos","label":"UI Rendering & SSR","title":"Resource DTOs","summary":"A Resource DTO is the one typed source of presentation data: handlers shape it once, templates consume it everywhere, and no view has to dissect random arrays.","opensInNewTab":false,"href":"/demo/rendering/resource-dtos"},{"section":"rendering","slug":"slots","label":"UI Rendering & SSR","title":"Slot Resources","summary":"Each page region is its own resource pipeline with the same template system as the main page — no scattered partial glue, no mystery wiring.","opensInNewTab":false,"href":"/demo/rendering/slots"},{"section":"rendering","slug":"components","label":"UI Rendering & SSR","title":"Components","summary":"Reusable, attribute-registered UI components — discovered automatically from the classmap.","opensInNewTab":false,"href":"/demo/rendering/components"},{"section":"rendering","slug":"seo","label":"UI Rendering & SSR","title":"SEO","summary":"Set title, description, and Open Graph tags from your handler — no template hacks needed.","opensInNewTab":false,"href":"/demo/rendering/seo"},{"section":"rendering","slug":"assets","label":"UI Rendering & SSR","title":"Asset Pipeline","summary":"Declare assets with glob patterns in assets.json — served, versioned, and injected automatically.","opensInNewTab":false,"href":"/demo/rendering/assets"},{"section":"rendering","slug":"component-scripts","label":"UI Rendering & SSR","title":"Component Script Assets","summary":"A Semitexa SSR component can own its optional enhancement asset, so behavior travels with the component instead of leaking into page-level glue.","opensInNewTab":false,"href":"/demo/rendering/component-scripts"},{"section":"rendering","slug":"deferred-scripts","label":"UI Rendering & SSR","title":"Script Injection","summary":"Deferred blocks carry their own JS — injected once when the block arrives, never duplicated.","opensInNewTab":false,"href":"/demo/rendering/deferred-scripts"}]},{"key":"deferred","label":"Deferred Delivery","featureCount":2,"features":[{"section":"rendering","slug":"deferred","label":"UI Rendering & SSR","title":"Deferred Blocks","summary":"SSR renders the shell first, then expensive regions stream in as real HTML over SSE — no SPA handoff and no client-side page rebuild.","opensInNewTab":true,"href":"/demo/rendering/deferred"},{"section":"rendering","slug":"deferred-encapsulation","label":"UI Rendering & SSR","title":"Block Isolation","summary":"Two identical blocks on the same page run independently — scoped DOM, scoped JS, no conflicts.","opensInNewTab":false,"href":"/demo/rendering/deferred-encapsulation"}]},{"key":"live","label":"Reactive UI","featureCount":5,"features":[{"section":"rendering","slug":"deferred-live","label":"UI Rendering & SSR","title":"Live Widgets","summary":"A live slot can refresh itself on a timer while the page stays SSR-first — no SPA runtime and no handwritten polling layer.","opensInNewTab":false,"href":"/demo/rendering/deferred-live"},{"section":"rendering","slug":"reactive-report","label":"UI Rendering & SSR","title":"Reactive Report","summary":"Background work updates an SSR-first slot in place, so the UI feels live without falling back to SPA state orchestration.","opensInNewTab":false,"href":"/demo/rendering/reactive-report"},{"section":"rendering","slug":"reactive-import","label":"UI Rendering & SSR","title":"Reactive Import","summary":"Background batches keep moving, and the page reflects server progress as live HTML instead of a client-managed progress app.","opensInNewTab":false,"href":"/demo/rendering/reactive-import"},{"section":"rendering","slug":"reactive-analytics","label":"UI Rendering & SSR","title":"Reactive Analytics","summary":"Independent analytics jobs can light up one dashboard progressively, while the page stays server-rendered from the first byte.","opensInNewTab":false,"href":"/demo/rendering/reactive-analytics"},{"section":"rendering","slug":"reactive-ai","label":"UI Rendering & SSR","title":"Reactive AI Task","summary":"Submit a task and watch the AI pipeline stages reveal one by one as the cron job processes it.","opensInNewTab":false,"href":"/demo/rendering/reactive-ai"}]}]},{"key":"platform","label":"Tenancy","summary":"Multi-tenant resolution, tenant-aware configuration, and strict isolation of data and background work.","icon":"TN","eyebrow":"Multi-Tenant","starter":false,"prerequisites":["data","rendering"],"featureCount":5,"href":"/demo/platform","features":[{"section":"platform","slug":"tenancy-resolution","label":"Tenancy","title":"Tenant Context Resolution","summary":"See how Semitexa resolves the active tenant from subdomain, header, path, or query input before the rest of the platform runs.","opensInNewTab":false,"href":"/demo/platform/tenancy-resolution"},{"section":"platform","slug":"tenancy-config","label":"Tenancy","title":"Per-Tenant Configuration","summary":"Three demo tenants with distinct branding -- switch tenant, everything changes without if/else.","opensInNewTab":false,"href":"/demo/platform/tenancy-config"},{"section":"platform","slug":"tenancy-layers","label":"Tenancy","title":"Multi-Layer Tenancy","summary":"Organization, Locale, Theme, Environment -- four independent layers compose into one TenantContext.","opensInNewTab":false,"href":"/demo/platform/tenancy-layers"},{"section":"platform","slug":"tenancy-isolation","label":"Tenancy","title":"Data Isolation","summary":"Product listing scoped by tenant -- switch tenant, list changes. Zero manual WHERE clauses.","opensInNewTab":false,"href":"/demo/platform/tenancy-isolation"},{"section":"platform","slug":"tenancy-queue","label":"Tenancy","title":"Queue Tenant Propagation","summary":"Tenant context travels with queued jobs -- _tenant key injected automatically, restored by worker.","opensInNewTab":false,"href":"/demo/platform/tenancy-queue"}],"groups":[{"key":"resolution","label":"Tenant Resolution","featureCount":1,"features":[{"section":"platform","slug":"tenancy-resolution","label":"Tenancy","title":"Tenant Context Resolution","summary":"See how Semitexa resolves the active tenant from subdomain, header, path, or query input before the rest of the platform runs.","opensInNewTab":false,"href":"/demo/platform/tenancy-resolution"}]},{"key":"configuration","label":"Tenant Configuration","featureCount":2,"features":[{"section":"platform","slug":"tenancy-config","label":"Tenancy","title":"Per-Tenant Configuration","summary":"Three demo tenants with distinct branding -- switch tenant, everything changes without if/else.","opensInNewTab":false,"href":"/demo/platform/tenancy-config"},{"section":"platform","slug":"tenancy-layers","label":"Tenancy","title":"Multi-Layer Tenancy","summary":"Organization, Locale, Theme, Environment -- four independent layers compose into one TenantContext.","opensInNewTab":false,"href":"/demo/platform/tenancy-layers"}]},{"key":"isolation","label":"Isolation & Work","featureCount":2,"features":[{"section":"platform","slug":"tenancy-isolation","label":"Tenancy","title":"Data Isolation","summary":"Product listing scoped by tenant -- switch tenant, list changes. Zero manual WHERE clauses.","opensInNewTab":false,"href":"/demo/platform/tenancy-isolation"},{"section":"platform","slug":"tenancy-queue","label":"Tenancy","title":"Queue Tenant Propagation","summary":"Tenant context travels with queued jobs -- _tenant key injected automatically, restored by worker.","opensInNewTab":false,"href":"/demo/platform/tenancy-queue"}]}]},{"key":"api","label":"API","summary":"External API endpoints, machine auth, versioning, and consumer-facing schema behavior.","icon":"API","eyebrow":"Machine","starter":false,"prerequisites":["routing","auth"],"featureCount":7,"href":"/demo/api","features":[{"section":"api","slug":"rest-api","label":"API","title":"REST API","summary":"Classic Semitexa REST endpoints with typed payloads, versioning, and consumer-friendly response shaping.","opensInNewTab":false,"href":"/demo/api/rest-api"},{"section":"api","slug":"structured-errors","label":"API","title":"Structured Errors","summary":"Throw domain exceptions and let semitexa-api map them into stable machine-readable error envelopes.","opensInNewTab":false,"href":"/demo/api/structured-errors"},{"section":"api","slug":"active-version","label":"API","title":"Active Version","summary":"The current collection endpoint with a clean X-Api-Version header and no deprecation noise.","opensInNewTab":false,"href":"/demo/api/active-version"},{"section":"api","slug":"sunset-version","label":"API","title":"Sunset Version","summary":"A deprecated product endpoint that emits both Deprecation and Sunset headers.","opensInNewTab":false,"href":"/demo/api/sunset-version"},{"section":"api","slug":"schema-discovery","label":"API","title":"Schema Discovery","summary":"A mini Swagger-style explorer for the live product API contract, schema endpoint, and response shapes.","opensInNewTab":false,"href":"/demo/api/schema-discovery"},{"section":"api","slug":"graphql","label":"API","title":"GraphQL API","summary":"GraphQL-first Semitexa contracts built with typed payloads and typed output DTOs instead of resolver sprawl.","opensInNewTab":false,"href":"/demo/api/graphql"},{"section":"api","slug":"rest-graphql","label":"API","title":"REST + GraphQL","summary":"One Semitexa use case can serve both REST and GraphQL without duplicating handler logic into separate resolver classes.","opensInNewTab":false,"href":"/demo/api/rest-graphql"}],"groups":[{"key":"public-api","label":"REST Surface","featureCount":4,"features":[{"section":"api","slug":"rest-api","label":"API","title":"REST API","summary":"Classic Semitexa REST endpoints with typed payloads, versioning, and consumer-friendly response shaping.","opensInNewTab":false,"href":"/demo/api/rest-api"},{"section":"api","slug":"structured-errors","label":"API","title":"Structured Errors","summary":"Throw domain exceptions and let semitexa-api map them into stable machine-readable error envelopes.","opensInNewTab":false,"href":"/demo/api/structured-errors"},{"section":"api","slug":"active-version","label":"API","title":"Active Version","summary":"The current collection endpoint with a clean X-Api-Version header and no deprecation noise.","opensInNewTab":false,"href":"/demo/api/active-version"},{"section":"api","slug":"sunset-version","label":"API","title":"Sunset Version","summary":"A deprecated product endpoint that emits both Deprecation and Sunset headers.","opensInNewTab":false,"href":"/demo/api/sunset-version"}]},{"key":"schema","label":"Schema Discovery","featureCount":3,"features":[{"section":"api","slug":"schema-discovery","label":"API","title":"Schema Discovery","summary":"A mini Swagger-style explorer for the live product API contract, schema endpoint, and response shapes.","opensInNewTab":false,"href":"/demo/api/schema-discovery"},{"section":"api","slug":"graphql","label":"API","title":"GraphQL API","summary":"GraphQL-first Semitexa contracts built with typed payloads and typed output DTOs instead of resolver sprawl.","opensInNewTab":false,"href":"/demo/api/graphql"},{"section":"api","slug":"rest-graphql","label":"API","title":"REST + GraphQL","summary":"One Semitexa use case can serve both REST and GraphQL without duplicating handler logic into separate resolver classes.","opensInNewTab":false,"href":"/demo/api/rest-graphql"}]}]},{"key":"cli","label":"CLI","summary":"Operational, introspection, and AI-oriented command surfaces that explain and drive the framework from the terminal.","icon":"CLI","eyebrow":"Operations","starter":false,"prerequisites":["routing"],"featureCount":6,"href":"/demo/cli","features":[{"section":"cli","slug":"describe-commands","label":"CLI","title":"Project Graph Introspection","summary":"Routes, modules, contracts, and handlers can be introspected directly from the CLI instead of reverse-engineering the framework graph by hand.","opensInNewTab":false,"href":"/demo/cli/describe-commands"},{"section":"cli","slug":"runtime-maintenance","label":"CLI","title":"Runtime Maintenance","summary":"Reload workers, clear stale cache, sync registries, lint architecture rules, and probe handler wiring without reaching for ad-hoc shell scripts.","opensInNewTab":false,"href":"/demo/cli/runtime-maintenance"},{"section":"cli","slug":"scaffolding-generators","label":"CLI","title":"Scaffolding Generators","summary":"Scaffold modules, pages, payloads, services, and contracts through commands that already understand Semitexa structure and AI-friendly output modes.","opensInNewTab":false,"href":"/demo/cli/scaffolding-generators"},{"section":"cli","slug":"workers-scheduling","label":"CLI","title":"Workers & Scheduling","summary":"Run queues, scheduler pools, mail delivery, webhooks, and tenant-scoped commands from a coherent operator surface instead of bespoke daemons.","opensInNewTab":false,"href":"/demo/cli/workers-scheduling"},{"section":"cli","slug":"ai-tooling","label":"CLI","title":"AI Tooling Surface","summary":"Semitexa exposes AI-facing commands as explicit CLI contracts: capabilities, skills, log access, and a local assistant entrypoint.","opensInNewTab":false,"href":"/demo/cli/ai-tooling"},{"section":"cli","slug":"orm-console","label":"CLI","title":"ORM Console Toolkit","summary":"The ORM ships with a practical CLI surface: status, diff, sync, and seed commands with dry-run safety and SQL plan export.","opensInNewTab":false,"href":"/demo/cli/orm-console"}],"groups":[{"key":"inspection","label":"Describe & Inspect","featureCount":2,"features":[{"section":"cli","slug":"describe-commands","label":"CLI","title":"Project Graph Introspection","summary":"Routes, modules, contracts, and handlers can be introspected directly from the CLI instead of reverse-engineering the framework graph by hand.","opensInNewTab":false,"href":"/demo/cli/describe-commands"},{"section":"cli","slug":"runtime-maintenance","label":"CLI","title":"Runtime Maintenance","summary":"Reload workers, clear stale cache, sync registries, lint architecture rules, and probe handler wiring without reaching for ad-hoc shell scripts.","opensInNewTab":false,"href":"/demo/cli/runtime-maintenance"}]},{"key":"automation","label":"Automation","featureCount":4,"features":[{"section":"cli","slug":"scaffolding-generators","label":"CLI","title":"Scaffolding Generators","summary":"Scaffold modules, pages, payloads, services, and contracts through commands that already understand Semitexa structure and AI-friendly output modes.","opensInNewTab":false,"href":"/demo/cli/scaffolding-generators"},{"section":"cli","slug":"workers-scheduling","label":"CLI","title":"Workers & Scheduling","summary":"Run queues, scheduler pools, mail delivery, webhooks, and tenant-scoped commands from a coherent operator surface instead of bespoke daemons.","opensInNewTab":false,"href":"/demo/cli/workers-scheduling"},{"section":"cli","slug":"ai-tooling","label":"CLI","title":"AI Tooling Surface","summary":"Semitexa exposes AI-facing commands as explicit CLI contracts: capabilities, skills, log access, and a local assistant entrypoint.","opensInNewTab":false,"href":"/demo/cli/ai-tooling"},{"section":"cli","slug":"orm-console","label":"CLI","title":"ORM Console Toolkit","summary":"The ORM ships with a practical CLI surface: status, diff, sync, and seed commands with dry-run safety and SQL plan export.","opensInNewTab":false,"href":"/demo/cli/orm-console"}]}]},{"key":"llm","label":"LLM Module","sidebarLabel":"LLM","summary":"The dedicated `semitexa/llm` module: AI assistant entrypoint, skill discovery, planner, executor, provider backends, and skill authoring rules.","icon":"AI","eyebrow":"semitexa/llm","starter":false,"prerequisites":["cli"],"featureCount":4,"href":"/demo/llm","features":[{"section":"llm","slug":"overview","label":"LLM Module","title":"LLM Module Overview","summary":"What `semitexa/llm` adds to the framework and how your project can expose its own CLI skills to the assistant.","opensInNewTab":false,"href":"/demo/llm/overview"},{"section":"llm","slug":"providers","label":"LLM Module","title":"Providers & Backends","summary":"Provider contracts, backend resolution, local vs remote Ollama, and the environment knobs that shape LLM runtime behavior.","opensInNewTab":false,"href":"/demo/llm/providers"},{"section":"llm","slug":"skills","label":"LLM Module","title":"Adding Skills","summary":"How a console command becomes AI-executable through `#[AsAiSkill]`, metadata policy, and registry discovery.","opensInNewTab":false,"href":"/demo/llm/skills"},{"section":"llm","slug":"execution-flow","label":"LLM Module","title":"Execution Flow","summary":"How a user request becomes a planner decision, a reviewed skill proposal, and finally a real console execution.","opensInNewTab":false,"href":"/demo/llm/execution-flow"}],"groups":[{"key":"assistant-basics","label":"Assistant Surface","featureCount":2,"features":[{"section":"llm","slug":"overview","label":"LLM Module","title":"LLM Module Overview","summary":"What `semitexa/llm` adds to the framework and how your project can expose its own CLI skills to the assistant.","opensInNewTab":false,"href":"/demo/llm/overview"},{"section":"llm","slug":"providers","label":"LLM Module","title":"Providers & Backends","summary":"Provider contracts, backend resolution, local vs remote Ollama, and the environment knobs that shape LLM runtime behavior.","opensInNewTab":false,"href":"/demo/llm/providers"}]},{"key":"skill-system","label":"Skill System","featureCount":2,"features":[{"section":"llm","slug":"skills","label":"LLM Module","title":"Adding Skills","summary":"How a console command becomes AI-executable through `#[AsAiSkill]`, metadata policy, and registry discovery.","opensInNewTab":false,"href":"/demo/llm/skills"},{"section":"llm","slug":"execution-flow","label":"LLM Module","title":"Execution Flow","summary":"How a user request becomes a planner decision, a reviewed skill proposal, and finally a real console execution.","opensInNewTab":false,"href":"/demo/llm/execution-flow"}]}]},{"key":"project-graph","label":"Project Graph","summary":"The `semitexa-project-graph` package: stored structural graph, intelligence layer, impact analysis, and task-scoped context for serious repository work.","icon":"PG","eyebrow":"AI Accelerator","starter":true,"prerequisites":["cli"],"featureCount":3,"href":"/demo/project-graph","features":[{"section":"project-graph","slug":"overview","label":"Project Graph","title":"Project Graph Overview","summary":"Understand what `semitexa-project-graph` adds: a stored structural map, an intelligence layer, and task-scoped context for large-codebase work.","opensInNewTab":false,"href":"/demo/project-graph/overview"},{"section":"project-graph","slug":"inspection","label":"Project Graph","title":"Inspecting the Graph","summary":"Use Project Graph queries and intelligence views to inspect modules, dependencies, flows, events, and hotspots without reconstructing the repository manually.","opensInNewTab":false,"href":"/demo/project-graph/inspection"},{"section":"project-graph","slug":"impact","label":"Project Graph","title":"Impact, Context, and Watch Mode","summary":"Use impact analysis, context packing, and watch mode to scope risky changes and keep graph-backed answers current during long work sessions.","opensInNewTab":false,"href":"/demo/project-graph/impact"}],"groups":[{"key":"launch","label":"Start Here","featureCount":1,"features":[{"section":"project-graph","slug":"overview","label":"Project Graph","title":"Project Graph Overview","summary":"Understand what `semitexa-project-graph` adds: a stored structural map, an intelligence layer, and task-scoped context for large-codebase work.","opensInNewTab":false,"href":"/demo/project-graph/overview"}]},{"key":"exploration","label":"Explore & Inspect","featureCount":1,"features":[{"section":"project-graph","slug":"inspection","label":"Project Graph","title":"Inspecting the Graph","summary":"Use Project Graph queries and intelligence views to inspect modules, dependencies, flows, events, and hotspots without reconstructing the repository manually.","opensInNewTab":false,"href":"/demo/project-graph/inspection"}]},{"key":"change-safety","label":"Impact & Context","featureCount":1,"features":[{"section":"project-graph","slug":"impact","label":"Project Graph","title":"Impact, Context, and Watch Mode","summary":"Use impact analysis, context packing, and watch mode to scope risky changes and keep graph-backed answers current during long work sessions.","opensInNewTab":false,"href":"/demo/project-graph/impact"}]}]},{"key":"testing","label":"Testing","summary":"Contract-level verification patterns for payloads and other framework boundaries.","icon":"QA","eyebrow":"Verification","starter":false,"prerequisites":["routing"],"featureCount":1,"href":"/demo/testing","features":[{"section":"testing","slug":"payload-contracts","label":"Testing","title":"Payload Contract Testing","summary":"Run one project-level contract suite through the canonical test runner and let strategy profiles verify payload boundaries without hand-writing repetitive negative cases.","opensInNewTab":false,"href":"/demo/testing/payload-contracts"}],"groups":[{"key":"contracts","label":"Contracts","featureCount":1,"features":[{"section":"testing","slug":"payload-contracts","label":"Testing","title":"Payload Contract Testing","summary":"Run one project-level contract suite through the canonical test runner and let strategy profiles verify payload boundaries without hand-writing repetitive negative cases.","opensInNewTab":false,"href":"/demo/testing/payload-contracts"}]}]}],"featureTree":[{"key":"start-here","label":"Start Here","eyebrow":"Guided path","summary":"The smallest reliable sequence that makes Semitexa feel like a system instead of a brochure.","type":"feature-links","href":"/#start-here","features":[{"section":"get-started","slug":"installation","label":"Start Here","title":"Installation","summary":"Create the project, review the baseline env contract, and bring up the Semitexa runtime the supported way.","opensInNewTab":false,"href":"/demo/get-started/installation"},{"section":"get-started","slug":"local-domain","label":"Start Here","title":"Local Domain","summary":"Register .test domains through the built-in local-domain helper instead of relying on ad hoc host setup.","opensInNewTab":false,"href":"/demo/get-started/local-domain"},{"section":"get-started","slug":"module-structure","label":"Start Here","title":"Module Structure","summary":"The minimal Semitexa module is a typed HTTP spine of payload, handler, resource, and template.","opensInNewTab":false,"href":"/demo/get-started/module-structure"},{"section":"get-started","slug":"base-tenant","label":"Start Here","title":"Base Tenant","summary":"Establish one default tenant context early so tenant-aware behavior is visible before the rest of the application grows.","opensInNewTab":false,"href":"/demo/get-started/base-tenant"},{"section":"get-started","slug":"locale-setup","label":"Start Here","title":"Locale Setup","summary":"Configure the minimal Locale contract so translations and locale-aware rendering become explicit early.","opensInNewTab":false,"href":"/demo/get-started/locale-setup"},{"section":"get-started","slug":"ai-console","label":"Start Here","title":"AI Console","summary":"Use the Semitexa AI console as a command translation surface over real operator commands.","opensInNewTab":false,"href":"/demo/get-started/ai-console"},{"section":"project-graph","slug":"overview","label":"Project Graph","title":"Project Graph Overview","summary":"Understand what `semitexa-project-graph` adds: a stored structural map, an intelligence layer, and task-scoped context for large-codebase work.","opensInNewTab":false,"href":"/demo/project-graph/overview"},{"section":"routing","slug":"basic","label":"Routing & Handlers","title":"Basic Route","summary":"Define a route with one access attribute on the payload — no XML, no YAML, no config files.","opensInNewTab":false,"href":"/demo/routing/basic"},{"section":"di","slug":"overview","label":"Dependency Injection","title":"DI Canon","summary":"One canonical DI path for container-managed classes: explicit properties, explicit lifecycles, deterministic boot.","opensInNewTab":false,"href":"/demo/di/overview"}],"featureCount":9},{"key":"full-catalog","label":"Full Catalog","eyebrow":"Route-first map","summary":"The exhaustive live map, still route-first, still real, and still one click away from every feature route.","type":"section-groups","href":"/#full-catalog","sectionKeys":["get-started","routing","di","data","auth","events","rendering","platform","api","cli","project-graph","llm","testing"],"featureCount":81,"sections":[{"key":"get-started","label":"Start Here","sidebarLabel":"Get Started","summary":"The shortest path from fresh scaffold to a trustworthy local Semitexa runtime: install, boot, understand the module map, bind a real host, and reach the first tenant boundary.","icon":"GO","eyebrow":"Onboarding","starter":true,"prerequisites":[],"featureCount":7,"href":"/demo/get-started","features":[{"section":"get-started","slug":"module-structure","label":"Start Here","title":"Module Structure","summary":"The minimal Semitexa module is a typed HTTP spine of payload, handler, resource, and template.","opensInNewTab":false,"href":"/demo/get-started/module-structure"},{"section":"get-started","slug":"installation","label":"Start Here","title":"Installation","summary":"Create the project, review the baseline env contract, and bring up the Semitexa runtime the supported way.","opensInNewTab":false,"href":"/demo/get-started/installation"},{"section":"get-started","slug":"local-domain","label":"Start Here","title":"Local Domain","summary":"Register .test domains through the built-in local-domain helper instead of relying on ad hoc host setup.","opensInNewTab":false,"href":"/demo/get-started/local-domain"},{"section":"get-started","slug":"base-tenant","label":"Start Here","title":"Base Tenant","summary":"Establish one default tenant context early so tenant-aware behavior is visible before the rest of the application grows.","opensInNewTab":false,"href":"/demo/get-started/base-tenant"},{"section":"get-started","slug":"locale-setup","label":"Start Here","title":"Locale Setup","summary":"Configure the minimal Locale contract so translations and locale-aware rendering become explicit early.","opensInNewTab":false,"href":"/demo/get-started/locale-setup"},{"section":"get-started","slug":"ai-console","label":"Start Here","title":"AI Console","summary":"Use the Semitexa AI console as a command translation surface over real operator commands.","opensInNewTab":false,"href":"/demo/get-started/ai-console"},{"section":"get-started","slug":"beyond-controllers","label":"Start Here","title":"Beyond Controllers","summary":"Understand why Semitexa keeps transport, use case, and rendering as separate explicit responsibilities.","opensInNewTab":false,"href":"/demo/get-started/beyond-controllers"}],"groups":[{"key":"structure","label":"Module Structure","featureCount":1,"features":[{"section":"get-started","slug":"module-structure","label":"Start Here","title":"Module Structure","summary":"The minimal Semitexa module is a typed HTTP spine of payload, handler, resource, and template.","opensInNewTab":false,"href":"/demo/get-started/module-structure"}]},{"key":"onboarding","label":"Onboarding","featureCount":6,"features":[{"section":"get-started","slug":"installation","label":"Start Here","title":"Installation","summary":"Create the project, review the baseline env contract, and bring up the Semitexa runtime the supported way.","opensInNewTab":false,"href":"/demo/get-started/installation"},{"section":"get-started","slug":"local-domain","label":"Start Here","title":"Local Domain","summary":"Register .test domains through the built-in local-domain helper instead of relying on ad hoc host setup.","opensInNewTab":false,"href":"/demo/get-started/local-domain"},{"section":"get-started","slug":"base-tenant","label":"Start Here","title":"Base Tenant","summary":"Establish one default tenant context early so tenant-aware behavior is visible before the rest of the application grows.","opensInNewTab":false,"href":"/demo/get-started/base-tenant"},{"section":"get-started","slug":"locale-setup","label":"Start Here","title":"Locale Setup","summary":"Configure the minimal Locale contract so translations and locale-aware rendering become explicit early.","opensInNewTab":false,"href":"/demo/get-started/locale-setup"},{"section":"get-started","slug":"ai-console","label":"Start Here","title":"AI Console","summary":"Use the Semitexa AI console as a command translation surface over real operator commands.","opensInNewTab":false,"href":"/demo/get-started/ai-console"},{"section":"get-started","slug":"beyond-controllers","label":"Start Here","title":"Beyond Controllers","summary":"Understand why Semitexa keeps transport, use case, and rendering as separate explicit responsibilities.","opensInNewTab":false,"href":"/demo/get-started/beyond-controllers"}]}]},{"key":"routing","label":"Routing & Handlers","summary":"Attribute-driven routes, typed handlers, and content negotiation in one coherent request pipeline.","icon":"RT","eyebrow":"HTTP Layer","starter":true,"prerequisites":[],"featureCount":7,"href":"/demo/routing","features":[{"section":"routing","slug":"basic","label":"Routing & Handlers","title":"Basic Route","summary":"Define a route with one access attribute on the payload — no XML, no YAML, no config files.","opensInNewTab":false,"href":"/demo/routing/basic"},{"section":"routing","slug":"parameterized","label":"Routing & Handlers","title":"Parameterized Route","summary":"Path parameters with regex constraints and typed injection.","opensInNewTab":false,"href":"/demo/routing/parameterized/headphones"},{"section":"routing","slug":"env-route-override","label":"Routing & Handlers","title":"Env Route Override","summary":"Keep the payload as the route source of truth while allowing operations to remap the public URL through .env.","opensInNewTab":false,"href":"/demo/routing/env-route-override"},{"section":"routing","slug":"payload-shield","label":"Routing & Handlers","title":"Payload As A Shield","summary":"Hydration happens before the handler, and each setter owns the normalization and guard logic for its own field.","opensInNewTab":false,"href":"/demo/routing/payload-shield"},{"section":"routing","slug":"payload-parts","label":"Routing & Handlers","title":"Payload Parts","summary":"One module owns the route, another module can extend the same payload contract without forking or reopening the base class.","opensInNewTab":false,"href":"/demo/routing/payload-parts"},{"section":"routing","slug":"content-negotiation","label":"Routing & Handlers","title":"Content Negotiation","summary":"One endpoint, multiple response formats — automatically.","opensInNewTab":false,"href":"/demo/routing/content-negotiation"},{"section":"routing","slug":"public-endpoint","label":"Routing & Handlers","title":"Public Payload","summary":"Anonymous endpoints opt in explicitly with the public access attribute. Every other payload requires authentication.","opensInNewTab":false,"href":"/demo/routing/public-endpoint"}],"groups":[{"key":"foundations","label":"Foundations","featureCount":3,"features":[{"section":"routing","slug":"basic","label":"Routing & Handlers","title":"Basic Route","summary":"Define a route with one access attribute on the payload — no XML, no YAML, no config files.","opensInNewTab":false,"href":"/demo/routing/basic"},{"section":"routing","slug":"parameterized","label":"Routing & Handlers","title":"Parameterized Route","summary":"Path parameters with regex constraints and typed injection.","opensInNewTab":false,"href":"/demo/routing/parameterized/headphones"},{"section":"routing","slug":"env-route-override","label":"Routing & Handlers","title":"Env Route Override","summary":"Keep the payload as the route source of truth while allowing operations to remap the public URL through .env.","opensInNewTab":false,"href":"/demo/routing/env-route-override"}]},{"key":"request-model","label":"Request Model","featureCount":2,"features":[{"section":"routing","slug":"payload-shield","label":"Routing & Handlers","title":"Payload As A Shield","summary":"Hydration happens before the handler, and each setter owns the normalization and guard logic for its own field.","opensInNewTab":false,"href":"/demo/routing/payload-shield"},{"section":"routing","slug":"payload-parts","label":"Routing & Handlers","title":"Payload Parts","summary":"One module owns the route, another module can extend the same payload contract without forking or reopening the base class.","opensInNewTab":false,"href":"/demo/routing/payload-parts"}]},{"key":"delivery","label":"Delivery","featureCount":2,"features":[{"section":"routing","slug":"content-negotiation","label":"Routing & Handlers","title":"Content Negotiation","summary":"One endpoint, multiple response formats — automatically.","opensInNewTab":false,"href":"/demo/routing/content-negotiation"},{"section":"routing","slug":"public-endpoint","label":"Routing & Handlers","title":"Public Payload","summary":"Anonymous endpoints opt in explicitly with the public access attribute. Every other payload requires authentication.","opensInNewTab":false,"href":"/demo/routing/public-endpoint"}]}]},{"key":"di","label":"Dependency Injection","summary":"Single-path DI with explicit lifecycles, deterministic contracts, and stable boot behavior for long-running workers.","icon":"DI","eyebrow":"Container","starter":true,"prerequisites":[],"featureCount":5,"href":"/demo/di","features":[{"section":"di","slug":"overview","label":"Dependency Injection","title":"DI Canon","summary":"One canonical DI path for container-managed classes: explicit properties, explicit lifecycles, deterministic boot.","opensInNewTab":false,"href":"/demo/di/overview"},{"section":"di","slug":"readonly","label":"Dependency Injection","title":"Readonly Injection","summary":"One explicit DI path, one shared worker instance — fast at runtime and stable under reload.","opensInNewTab":false,"href":"/demo/di/readonly"},{"section":"di","slug":"mutable","label":"Dependency Injection","title":"Mutable Injection","summary":"Execution-scoped services get a fresh clone every run — safe state without contaminating the worker.","opensInNewTab":false,"href":"/demo/di/mutable"},{"section":"di","slug":"factory","label":"Dependency Injection","title":"Factory Injection","summary":"On-demand creation stays explicit — lazy instances without falling back to service locator habits.","opensInNewTab":false,"href":"/demo/di/factory"},{"section":"di","slug":"contracts","label":"Dependency Injection","title":"Service Contracts","summary":"Depend on contracts, but keep ownership explicit — deterministic substitution instead of runtime magic.","opensInNewTab":false,"href":"/demo/di/contracts"}],"groups":[{"key":"container-basics","label":"Container Basics","featureCount":5,"features":[{"section":"di","slug":"overview","label":"Dependency Injection","title":"DI Canon","summary":"One canonical DI path for container-managed classes: explicit properties, explicit lifecycles, deterministic boot.","opensInNewTab":false,"href":"/demo/di/overview"},{"section":"di","slug":"readonly","label":"Dependency Injection","title":"Readonly Injection","summary":"One explicit DI path, one shared worker instance — fast at runtime and stable under reload.","opensInNewTab":false,"href":"/demo/di/readonly"},{"section":"di","slug":"mutable","label":"Dependency Injection","title":"Mutable Injection","summary":"Execution-scoped services get a fresh clone every run — safe state without contaminating the worker.","opensInNewTab":false,"href":"/demo/di/mutable"},{"section":"di","slug":"factory","label":"Dependency Injection","title":"Factory Injection","summary":"On-demand creation stays explicit — lazy instances without falling back to service locator habits.","opensInNewTab":false,"href":"/demo/di/factory"},{"section":"di","slug":"contracts","label":"Dependency Injection","title":"Service Contracts","summary":"Depend on contracts, but keep ownership explicit — deterministic substitution instead of runtime magic.","opensInNewTab":false,"href":"/demo/di/contracts"}]}]},{"key":"data","label":"Persistence","summary":"Attribute-mapped resources, repositories, filtering, pagination, and relations with real demo data.","icon":"DB","eyebrow":"Persistence","starter":true,"prerequisites":[],"featureCount":9,"href":"/demo/data","features":[{"section":"data","slug":"domain-models","label":"Persistence","title":"Domain-Level Models","summary":"Semitexa separates persistence resources from business models. Resources map tables; domain models carry behavior and invariants.","opensInNewTab":false,"href":"/demo/data/domain-models"},{"section":"data","slug":"repository-workflow","label":"Persistence","title":"Repository Workflow","summary":"The canonical Semitexa path: handlers depend on repository contracts, repositories return domain models, and persistence resources stay behind the boundary.","opensInNewTab":false,"href":"/demo/data/repository-workflow"},{"section":"data","slug":"schema-sync","label":"Persistence","title":"Schema Sync, Not Migration Churn","summary":"Semitexa creates SQL only when the real schema changed, blocks destructive drops by default, and logs the exact DDL plan as SQL and JSON.","opensInNewTab":false,"href":"/demo/data/schema-sync"},{"section":"data","slug":"query","label":"Persistence","title":"Query Builder","summary":"Compose type-safe queries with a fluent API — no raw SQL, no magic strings.","opensInNewTab":false,"href":"/demo/data/query"},{"section":"data","slug":"filtering","label":"Persistence","title":"Filtering","summary":"Mark a property #[Filterable] and the ORM handles the rest — no manual WHERE clauses.","opensInNewTab":false,"href":"/demo/data/filtering"},{"section":"data","slug":"pagination","label":"Persistence","title":"Pagination","summary":"Offset and cursor pagination out of the box — switch modes with a single query parameter.","opensInNewTab":false,"href":"/demo/data/pagination"},{"section":"data","slug":"relations","label":"Persistence","title":"Relations","summary":"Declare parent and child links on the resource itself, then read typed relations from the handler.","opensInNewTab":false,"href":"/demo/data/relations"},{"section":"data","slug":"table-extension","label":"Persistence","title":"Shared Table Extension","summary":"Two modules can extend one table independently, and the ORM merges the schema without forcing either side to edit the other.","opensInNewTab":false,"href":"/demo/data/table-extension"},{"section":"data","slug":"n-plus-one","label":"Persistence","title":"N+1 Without Magic","summary":"Semitexa avoids N+1 by using resource slices for the exact columns and relations each screen needs, instead of hiding database traffic behind implicit relation loading.","opensInNewTab":false,"href":"/demo/data/n-plus-one"}],"groups":[{"key":"modeling","label":"Modeling & Workflow","featureCount":3,"features":[{"section":"data","slug":"domain-models","label":"Persistence","title":"Domain-Level Models","summary":"Semitexa separates persistence resources from business models. Resources map tables; domain models carry behavior and invariants.","opensInNewTab":false,"href":"/demo/data/domain-models"},{"section":"data","slug":"repository-workflow","label":"Persistence","title":"Repository Workflow","summary":"The canonical Semitexa path: handlers depend on repository contracts, repositories return domain models, and persistence resources stay behind the boundary.","opensInNewTab":false,"href":"/demo/data/repository-workflow"},{"section":"data","slug":"schema-sync","label":"Persistence","title":"Schema Sync, Not Migration Churn","summary":"Semitexa creates SQL only when the real schema changed, blocks destructive drops by default, and logs the exact DDL plan as SQL and JSON.","opensInNewTab":false,"href":"/demo/data/schema-sync"}]},{"key":"querying","label":"Querying","featureCount":6,"features":[{"section":"data","slug":"query","label":"Persistence","title":"Query Builder","summary":"Compose type-safe queries with a fluent API — no raw SQL, no magic strings.","opensInNewTab":false,"href":"/demo/data/query"},{"section":"data","slug":"filtering","label":"Persistence","title":"Filtering","summary":"Mark a property #[Filterable] and the ORM handles the rest — no manual WHERE clauses.","opensInNewTab":false,"href":"/demo/data/filtering"},{"section":"data","slug":"pagination","label":"Persistence","title":"Pagination","summary":"Offset and cursor pagination out of the box — switch modes with a single query parameter.","opensInNewTab":false,"href":"/demo/data/pagination"},{"section":"data","slug":"relations","label":"Persistence","title":"Relations","summary":"Declare parent and child links on the resource itself, then read typed relations from the handler.","opensInNewTab":false,"href":"/demo/data/relations"},{"section":"data","slug":"table-extension","label":"Persistence","title":"Shared Table Extension","summary":"Two modules can extend one table independently, and the ORM merges the schema without forcing either side to edit the other.","opensInNewTab":false,"href":"/demo/data/table-extension"},{"section":"data","slug":"n-plus-one","label":"Persistence","title":"N+1 Without Magic","summary":"Semitexa avoids N+1 by using resource slices for the exact columns and relations each screen needs, instead of hiding database traffic behind implicit relation loading.","opensInNewTab":false,"href":"/demo/data/n-plus-one"}]}]},{"key":"auth","label":"Security","summary":"Typed session payloads, machine credentials, RBAC, and route protection without string-key auth chaos.","icon":"AU","eyebrow":"Security","starter":false,"prerequisites":[],"featureCount":7,"href":"/demo/auth","features":[{"section":"auth","slug":"session","label":"Security","title":"Session Auth","summary":"Google signs the user in, then the session stores the selected demo role and re-hydrates it on every request.","opensInNewTab":false,"href":"/demo/auth/session"},{"section":"auth","slug":"session-payloads","label":"Security","title":"Session Payloads","summary":"Semitexa forbids string-key session chaos: session state lives in typed Session Payloads or it does not exist.","opensInNewTab":false,"href":"/demo/auth/session-payloads"},{"section":"auth","slug":"google","label":"Security","title":"Google Authorization","summary":"Authorization is required for demo SSE blocks that keep a long-lived backend connection open.","opensInNewTab":false,"href":"/demo/auth/google"},{"section":"auth","slug":"machine","label":"Security","title":"Machine Auth","summary":"Service-to-service authentication via Bearer tokens — scoped, revocable, and audited.","opensInNewTab":false,"href":"/demo/auth/machine"},{"section":"auth","slug":"protected","label":"Security","title":"Protected Route","summary":"Add one access attribute and one optional permission attribute and the framework enforces access — 401 for unauthenticated requests, 403 for unauthorized ones.","opensInNewTab":false,"href":"/demo/auth/protected"},{"section":"auth","slug":"requires-permission","label":"Security","title":"Requires Permission","summary":"Declare one permission slug on the payload and let the framework enforce it before your handler runs.","opensInNewTab":false,"href":"/demo/auth/requires-permission"},{"section":"auth","slug":"rbac","label":"Security","title":"RBAC","summary":"Hybrid RBAC with coarse-grained capabilities, exact permission slugs, and module-owned permission catalogs.","opensInNewTab":false,"href":"/demo/auth/rbac"}],"groups":[{"key":"identity","label":"Identity","featureCount":4,"features":[{"section":"auth","slug":"session","label":"Security","title":"Session Auth","summary":"Google signs the user in, then the session stores the selected demo role and re-hydrates it on every request.","opensInNewTab":false,"href":"/demo/auth/session"},{"section":"auth","slug":"session-payloads","label":"Security","title":"Session Payloads","summary":"Semitexa forbids string-key session chaos: session state lives in typed Session Payloads or it does not exist.","opensInNewTab":false,"href":"/demo/auth/session-payloads"},{"section":"auth","slug":"google","label":"Security","title":"Google Authorization","summary":"Authorization is required for demo SSE blocks that keep a long-lived backend connection open.","opensInNewTab":false,"href":"/demo/auth/google"},{"section":"auth","slug":"machine","label":"Security","title":"Machine Auth","summary":"Service-to-service authentication via Bearer tokens — scoped, revocable, and audited.","opensInNewTab":false,"href":"/demo/auth/machine"}]},{"key":"access-control","label":"Access Control","featureCount":3,"features":[{"section":"auth","slug":"protected","label":"Security","title":"Protected Route","summary":"Add one access attribute and one optional permission attribute and the framework enforces access — 401 for unauthenticated requests, 403 for unauthorized ones.","opensInNewTab":false,"href":"/demo/auth/protected"},{"section":"auth","slug":"requires-permission","label":"Security","title":"Requires Permission","summary":"Declare one permission slug on the payload and let the framework enforce it before your handler runs.","opensInNewTab":false,"href":"/demo/auth/requires-permission"},{"section":"auth","slug":"rbac","label":"Security","title":"RBAC","summary":"Hybrid RBAC with coarse-grained capabilities, exact permission slugs, and module-owned permission catalogs.","opensInNewTab":false,"href":"/demo/auth/rbac"}]}]},{"key":"events","label":"Async","summary":"Synchronous and deferred event flows, queues, and SSE-style interactions.","icon":"EV","eyebrow":"Async","starter":false,"prerequisites":[],"featureCount":5,"href":"/demo/events","features":[{"section":"events","slug":"arena","label":"Async","title":"Execution Arena","summary":"Launch the same backend intent in sync, Swoole async, and queued modes, then watch the proof arrive over SSE.","opensInNewTab":false,"href":"/demo/events/arena"},{"section":"events","slug":"sync","label":"Async","title":"Sync Events","summary":"Dispatch an event and all sync listeners run before the response is sent.","opensInNewTab":false,"href":"/demo/events/sync"},{"section":"events","slug":"deferred","label":"Async","title":"Deferred Handler","summary":"Heavy work runs after the response is sent — the user gets instant feedback.","opensInNewTab":false,"href":"/demo/events/deferred"},{"section":"events","slug":"queued","label":"Async","title":"Queued Handler","summary":"Events survive restarts and scale across workers — backed by a durable message queue.","opensInNewTab":false,"href":"/demo/events/queued"},{"section":"events","slug":"sse","label":"Async","title":"SSE Stream","summary":"Real-time server push without WebSockets — connect once and receive real backend events over plain HTTP.","opensInNewTab":false,"href":"/demo/events/sse"}],"groups":[{"key":"event-flow","label":"Event Flow","featureCount":5,"features":[{"section":"events","slug":"arena","label":"Async","title":"Execution Arena","summary":"Launch the same backend intent in sync, Swoole async, and queued modes, then watch the proof arrive over SSE.","opensInNewTab":false,"href":"/demo/events/arena"},{"section":"events","slug":"sync","label":"Async","title":"Sync Events","summary":"Dispatch an event and all sync listeners run before the response is sent.","opensInNewTab":false,"href":"/demo/events/sync"},{"section":"events","slug":"deferred","label":"Async","title":"Deferred Handler","summary":"Heavy work runs after the response is sent — the user gets instant feedback.","opensInNewTab":false,"href":"/demo/events/deferred"},{"section":"events","slug":"queued","label":"Async","title":"Queued Handler","summary":"Events survive restarts and scale across workers — backed by a durable message queue.","opensInNewTab":false,"href":"/demo/events/queued"},{"section":"events","slug":"sse","label":"Async","title":"SSE Stream","summary":"Real-time server push without WebSockets — connect once and receive real backend events over plain HTTP.","opensInNewTab":false,"href":"/demo/events/sse"}]}]},{"key":"rendering","label":"UI Rendering & SSR","summary":"One rendering story from handler to HTML: page data, page regions, and live updates stay in the same server-driven model instead of splitting into frontend and backend template logic.","icon":"UI","eyebrow":"Frontend","starter":false,"prerequisites":[],"featureCount":15,"href":"/demo/rendering","features":[{"section":"rendering","slug":"philosophy","label":"UI Rendering & SSR","title":"SSR Philosophy","summary":"Semitexa SSR is one continuous rendering architecture: page, slots, deferred regions, live refresh, and interactive components stay inside one server-owned story.","opensInNewTab":false,"href":"/demo/rendering/philosophy"},{"section":"rendering","slug":"resource-dtos","label":"UI Rendering & SSR","title":"Resource DTOs","summary":"A Resource DTO is the one typed source of presentation data: handlers shape it once, templates consume it everywhere, and no view has to dissect random arrays.","opensInNewTab":false,"href":"/demo/rendering/resource-dtos"},{"section":"rendering","slug":"slots","label":"UI Rendering & SSR","title":"Slot Resources","summary":"Each page region is its own resource pipeline with the same template system as the main page — no scattered partial glue, no mystery wiring.","opensInNewTab":false,"href":"/demo/rendering/slots"},{"section":"rendering","slug":"components","label":"UI Rendering & SSR","title":"Components","summary":"Reusable, attribute-registered UI components — discovered automatically from the classmap.","opensInNewTab":false,"href":"/demo/rendering/components"},{"section":"rendering","slug":"seo","label":"UI Rendering & SSR","title":"SEO","summary":"Set title, description, and Open Graph tags from your handler — no template hacks needed.","opensInNewTab":false,"href":"/demo/rendering/seo"},{"section":"rendering","slug":"assets","label":"UI Rendering & SSR","title":"Asset Pipeline","summary":"Declare assets with glob patterns in assets.json — served, versioned, and injected automatically.","opensInNewTab":false,"href":"/demo/rendering/assets"},{"section":"rendering","slug":"component-scripts","label":"UI Rendering & SSR","title":"Component Script Assets","summary":"A Semitexa SSR component can own its optional enhancement asset, so behavior travels with the component instead of leaking into page-level glue.","opensInNewTab":false,"href":"/demo/rendering/component-scripts"},{"section":"rendering","slug":"deferred-scripts","label":"UI Rendering & SSR","title":"Script Injection","summary":"Deferred blocks carry their own JS — injected once when the block arrives, never duplicated.","opensInNewTab":false,"href":"/demo/rendering/deferred-scripts"},{"section":"rendering","slug":"deferred","label":"UI Rendering & SSR","title":"Deferred Blocks","summary":"SSR renders the shell first, then expensive regions stream in as real HTML over SSE — no SPA handoff and no client-side page rebuild.","opensInNewTab":true,"href":"/demo/rendering/deferred"},{"section":"rendering","slug":"deferred-encapsulation","label":"UI Rendering & SSR","title":"Block Isolation","summary":"Two identical blocks on the same page run independently — scoped DOM, scoped JS, no conflicts.","opensInNewTab":false,"href":"/demo/rendering/deferred-encapsulation"},{"section":"rendering","slug":"deferred-live","label":"UI Rendering & SSR","title":"Live Widgets","summary":"A live slot can refresh itself on a timer while the page stays SSR-first — no SPA runtime and no handwritten polling layer.","opensInNewTab":false,"href":"/demo/rendering/deferred-live"},{"section":"rendering","slug":"reactive-report","label":"UI Rendering & SSR","title":"Reactive Report","summary":"Background work updates an SSR-first slot in place, so the UI feels live without falling back to SPA state orchestration.","opensInNewTab":false,"href":"/demo/rendering/reactive-report"},{"section":"rendering","slug":"reactive-import","label":"UI Rendering & SSR","title":"Reactive Import","summary":"Background batches keep moving, and the page reflects server progress as live HTML instead of a client-managed progress app.","opensInNewTab":false,"href":"/demo/rendering/reactive-import"},{"section":"rendering","slug":"reactive-analytics","label":"UI Rendering & SSR","title":"Reactive Analytics","summary":"Independent analytics jobs can light up one dashboard progressively, while the page stays server-rendered from the first byte.","opensInNewTab":false,"href":"/demo/rendering/reactive-analytics"},{"section":"rendering","slug":"reactive-ai","label":"UI Rendering & SSR","title":"Reactive AI Task","summary":"Submit a task and watch the AI pipeline stages reveal one by one as the cron job processes it.","opensInNewTab":false,"href":"/demo/rendering/reactive-ai"}],"groups":[{"key":"rendering-model","label":"SSR Foundation","featureCount":8,"features":[{"section":"rendering","slug":"philosophy","label":"UI Rendering & SSR","title":"SSR Philosophy","summary":"Semitexa SSR is one continuous rendering architecture: page, slots, deferred regions, live refresh, and interactive components stay inside one server-owned story.","opensInNewTab":false,"href":"/demo/rendering/philosophy"},{"section":"rendering","slug":"resource-dtos","label":"UI Rendering & SSR","title":"Resource DTOs","summary":"A Resource DTO is the one typed source of presentation data: handlers shape it once, templates consume it everywhere, and no view has to dissect random arrays.","opensInNewTab":false,"href":"/demo/rendering/resource-dtos"},{"section":"rendering","slug":"slots","label":"UI Rendering & SSR","title":"Slot Resources","summary":"Each page region is its own resource pipeline with the same template system as the main page — no scattered partial glue, no mystery wiring.","opensInNewTab":false,"href":"/demo/rendering/slots"},{"section":"rendering","slug":"components","label":"UI Rendering & SSR","title":"Components","summary":"Reusable, attribute-registered UI components — discovered automatically from the classmap.","opensInNewTab":false,"href":"/demo/rendering/components"},{"section":"rendering","slug":"seo","label":"UI Rendering & SSR","title":"SEO","summary":"Set title, description, and Open Graph tags from your handler — no template hacks needed.","opensInNewTab":false,"href":"/demo/rendering/seo"},{"section":"rendering","slug":"assets","label":"UI Rendering & SSR","title":"Asset Pipeline","summary":"Declare assets with glob patterns in assets.json — served, versioned, and injected automatically.","opensInNewTab":false,"href":"/demo/rendering/assets"},{"section":"rendering","slug":"component-scripts","label":"UI Rendering & SSR","title":"Component Script Assets","summary":"A Semitexa SSR component can own its optional enhancement asset, so behavior travels with the component instead of leaking into page-level glue.","opensInNewTab":false,"href":"/demo/rendering/component-scripts"},{"section":"rendering","slug":"deferred-scripts","label":"UI Rendering & SSR","title":"Script Injection","summary":"Deferred blocks carry their own JS — injected once when the block arrives, never duplicated.","opensInNewTab":false,"href":"/demo/rendering/deferred-scripts"}]},{"key":"deferred","label":"Deferred Delivery","featureCount":2,"features":[{"section":"rendering","slug":"deferred","label":"UI Rendering & SSR","title":"Deferred Blocks","summary":"SSR renders the shell first, then expensive regions stream in as real HTML over SSE — no SPA handoff and no client-side page rebuild.","opensInNewTab":true,"href":"/demo/rendering/deferred"},{"section":"rendering","slug":"deferred-encapsulation","label":"UI Rendering & SSR","title":"Block Isolation","summary":"Two identical blocks on the same page run independently — scoped DOM, scoped JS, no conflicts.","opensInNewTab":false,"href":"/demo/rendering/deferred-encapsulation"}]},{"key":"live","label":"Reactive UI","featureCount":5,"features":[{"section":"rendering","slug":"deferred-live","label":"UI Rendering & SSR","title":"Live Widgets","summary":"A live slot can refresh itself on a timer while the page stays SSR-first — no SPA runtime and no handwritten polling layer.","opensInNewTab":false,"href":"/demo/rendering/deferred-live"},{"section":"rendering","slug":"reactive-report","label":"UI Rendering & SSR","title":"Reactive Report","summary":"Background work updates an SSR-first slot in place, so the UI feels live without falling back to SPA state orchestration.","opensInNewTab":false,"href":"/demo/rendering/reactive-report"},{"section":"rendering","slug":"reactive-import","label":"UI Rendering & SSR","title":"Reactive Import","summary":"Background batches keep moving, and the page reflects server progress as live HTML instead of a client-managed progress app.","opensInNewTab":false,"href":"/demo/rendering/reactive-import"},{"section":"rendering","slug":"reactive-analytics","label":"UI Rendering & SSR","title":"Reactive Analytics","summary":"Independent analytics jobs can light up one dashboard progressively, while the page stays server-rendered from the first byte.","opensInNewTab":false,"href":"/demo/rendering/reactive-analytics"},{"section":"rendering","slug":"reactive-ai","label":"UI Rendering & SSR","title":"Reactive AI Task","summary":"Submit a task and watch the AI pipeline stages reveal one by one as the cron job processes it.","opensInNewTab":false,"href":"/demo/rendering/reactive-ai"}]}]},{"key":"platform","label":"Tenancy","summary":"Multi-tenant resolution, tenant-aware configuration, and strict isolation of data and background work.","icon":"TN","eyebrow":"Multi-Tenant","starter":false,"prerequisites":["data","rendering"],"featureCount":5,"href":"/demo/platform","features":[{"section":"platform","slug":"tenancy-resolution","label":"Tenancy","title":"Tenant Context Resolution","summary":"See how Semitexa resolves the active tenant from subdomain, header, path, or query input before the rest of the platform runs.","opensInNewTab":false,"href":"/demo/platform/tenancy-resolution"},{"section":"platform","slug":"tenancy-config","label":"Tenancy","title":"Per-Tenant Configuration","summary":"Three demo tenants with distinct branding -- switch tenant, everything changes without if/else.","opensInNewTab":false,"href":"/demo/platform/tenancy-config"},{"section":"platform","slug":"tenancy-layers","label":"Tenancy","title":"Multi-Layer Tenancy","summary":"Organization, Locale, Theme, Environment -- four independent layers compose into one TenantContext.","opensInNewTab":false,"href":"/demo/platform/tenancy-layers"},{"section":"platform","slug":"tenancy-isolation","label":"Tenancy","title":"Data Isolation","summary":"Product listing scoped by tenant -- switch tenant, list changes. Zero manual WHERE clauses.","opensInNewTab":false,"href":"/demo/platform/tenancy-isolation"},{"section":"platform","slug":"tenancy-queue","label":"Tenancy","title":"Queue Tenant Propagation","summary":"Tenant context travels with queued jobs -- _tenant key injected automatically, restored by worker.","opensInNewTab":false,"href":"/demo/platform/tenancy-queue"}],"groups":[{"key":"resolution","label":"Tenant Resolution","featureCount":1,"features":[{"section":"platform","slug":"tenancy-resolution","label":"Tenancy","title":"Tenant Context Resolution","summary":"See how Semitexa resolves the active tenant from subdomain, header, path, or query input before the rest of the platform runs.","opensInNewTab":false,"href":"/demo/platform/tenancy-resolution"}]},{"key":"configuration","label":"Tenant Configuration","featureCount":2,"features":[{"section":"platform","slug":"tenancy-config","label":"Tenancy","title":"Per-Tenant Configuration","summary":"Three demo tenants with distinct branding -- switch tenant, everything changes without if/else.","opensInNewTab":false,"href":"/demo/platform/tenancy-config"},{"section":"platform","slug":"tenancy-layers","label":"Tenancy","title":"Multi-Layer Tenancy","summary":"Organization, Locale, Theme, Environment -- four independent layers compose into one TenantContext.","opensInNewTab":false,"href":"/demo/platform/tenancy-layers"}]},{"key":"isolation","label":"Isolation & Work","featureCount":2,"features":[{"section":"platform","slug":"tenancy-isolation","label":"Tenancy","title":"Data Isolation","summary":"Product listing scoped by tenant -- switch tenant, list changes. Zero manual WHERE clauses.","opensInNewTab":false,"href":"/demo/platform/tenancy-isolation"},{"section":"platform","slug":"tenancy-queue","label":"Tenancy","title":"Queue Tenant Propagation","summary":"Tenant context travels with queued jobs -- _tenant key injected automatically, restored by worker.","opensInNewTab":false,"href":"/demo/platform/tenancy-queue"}]}]},{"key":"api","label":"API","summary":"External API endpoints, machine auth, versioning, and consumer-facing schema behavior.","icon":"API","eyebrow":"Machine","starter":false,"prerequisites":["routing","auth"],"featureCount":7,"href":"/demo/api","features":[{"section":"api","slug":"rest-api","label":"API","title":"REST API","summary":"Classic Semitexa REST endpoints with typed payloads, versioning, and consumer-friendly response shaping.","opensInNewTab":false,"href":"/demo/api/rest-api"},{"section":"api","slug":"structured-errors","label":"API","title":"Structured Errors","summary":"Throw domain exceptions and let semitexa-api map them into stable machine-readable error envelopes.","opensInNewTab":false,"href":"/demo/api/structured-errors"},{"section":"api","slug":"active-version","label":"API","title":"Active Version","summary":"The current collection endpoint with a clean X-Api-Version header and no deprecation noise.","opensInNewTab":false,"href":"/demo/api/active-version"},{"section":"api","slug":"sunset-version","label":"API","title":"Sunset Version","summary":"A deprecated product endpoint that emits both Deprecation and Sunset headers.","opensInNewTab":false,"href":"/demo/api/sunset-version"},{"section":"api","slug":"schema-discovery","label":"API","title":"Schema Discovery","summary":"A mini Swagger-style explorer for the live product API contract, schema endpoint, and response shapes.","opensInNewTab":false,"href":"/demo/api/schema-discovery"},{"section":"api","slug":"graphql","label":"API","title":"GraphQL API","summary":"GraphQL-first Semitexa contracts built with typed payloads and typed output DTOs instead of resolver sprawl.","opensInNewTab":false,"href":"/demo/api/graphql"},{"section":"api","slug":"rest-graphql","label":"API","title":"REST + GraphQL","summary":"One Semitexa use case can serve both REST and GraphQL without duplicating handler logic into separate resolver classes.","opensInNewTab":false,"href":"/demo/api/rest-graphql"}],"groups":[{"key":"public-api","label":"REST Surface","featureCount":4,"features":[{"section":"api","slug":"rest-api","label":"API","title":"REST API","summary":"Classic Semitexa REST endpoints with typed payloads, versioning, and consumer-friendly response shaping.","opensInNewTab":false,"href":"/demo/api/rest-api"},{"section":"api","slug":"structured-errors","label":"API","title":"Structured Errors","summary":"Throw domain exceptions and let semitexa-api map them into stable machine-readable error envelopes.","opensInNewTab":false,"href":"/demo/api/structured-errors"},{"section":"api","slug":"active-version","label":"API","title":"Active Version","summary":"The current collection endpoint with a clean X-Api-Version header and no deprecation noise.","opensInNewTab":false,"href":"/demo/api/active-version"},{"section":"api","slug":"sunset-version","label":"API","title":"Sunset Version","summary":"A deprecated product endpoint that emits both Deprecation and Sunset headers.","opensInNewTab":false,"href":"/demo/api/sunset-version"}]},{"key":"schema","label":"Schema Discovery","featureCount":3,"features":[{"section":"api","slug":"schema-discovery","label":"API","title":"Schema Discovery","summary":"A mini Swagger-style explorer for the live product API contract, schema endpoint, and response shapes.","opensInNewTab":false,"href":"/demo/api/schema-discovery"},{"section":"api","slug":"graphql","label":"API","title":"GraphQL API","summary":"GraphQL-first Semitexa contracts built with typed payloads and typed output DTOs instead of resolver sprawl.","opensInNewTab":false,"href":"/demo/api/graphql"},{"section":"api","slug":"rest-graphql","label":"API","title":"REST + GraphQL","summary":"One Semitexa use case can serve both REST and GraphQL without duplicating handler logic into separate resolver classes.","opensInNewTab":false,"href":"/demo/api/rest-graphql"}]}]},{"key":"cli","label":"CLI","summary":"Operational, introspection, and AI-oriented command surfaces that explain and drive the framework from the terminal.","icon":"CLI","eyebrow":"Operations","starter":false,"prerequisites":["routing"],"featureCount":6,"href":"/demo/cli","features":[{"section":"cli","slug":"describe-commands","label":"CLI","title":"Project Graph Introspection","summary":"Routes, modules, contracts, and handlers can be introspected directly from the CLI instead of reverse-engineering the framework graph by hand.","opensInNewTab":false,"href":"/demo/cli/describe-commands"},{"section":"cli","slug":"runtime-maintenance","label":"CLI","title":"Runtime Maintenance","summary":"Reload workers, clear stale cache, sync registries, lint architecture rules, and probe handler wiring without reaching for ad-hoc shell scripts.","opensInNewTab":false,"href":"/demo/cli/runtime-maintenance"},{"section":"cli","slug":"scaffolding-generators","label":"CLI","title":"Scaffolding Generators","summary":"Scaffold modules, pages, payloads, services, and contracts through commands that already understand Semitexa structure and AI-friendly output modes.","opensInNewTab":false,"href":"/demo/cli/scaffolding-generators"},{"section":"cli","slug":"workers-scheduling","label":"CLI","title":"Workers & Scheduling","summary":"Run queues, scheduler pools, mail delivery, webhooks, and tenant-scoped commands from a coherent operator surface instead of bespoke daemons.","opensInNewTab":false,"href":"/demo/cli/workers-scheduling"},{"section":"cli","slug":"ai-tooling","label":"CLI","title":"AI Tooling Surface","summary":"Semitexa exposes AI-facing commands as explicit CLI contracts: capabilities, skills, log access, and a local assistant entrypoint.","opensInNewTab":false,"href":"/demo/cli/ai-tooling"},{"section":"cli","slug":"orm-console","label":"CLI","title":"ORM Console Toolkit","summary":"The ORM ships with a practical CLI surface: status, diff, sync, and seed commands with dry-run safety and SQL plan export.","opensInNewTab":false,"href":"/demo/cli/orm-console"}],"groups":[{"key":"inspection","label":"Describe & Inspect","featureCount":2,"features":[{"section":"cli","slug":"describe-commands","label":"CLI","title":"Project Graph Introspection","summary":"Routes, modules, contracts, and handlers can be introspected directly from the CLI instead of reverse-engineering the framework graph by hand.","opensInNewTab":false,"href":"/demo/cli/describe-commands"},{"section":"cli","slug":"runtime-maintenance","label":"CLI","title":"Runtime Maintenance","summary":"Reload workers, clear stale cache, sync registries, lint architecture rules, and probe handler wiring without reaching for ad-hoc shell scripts.","opensInNewTab":false,"href":"/demo/cli/runtime-maintenance"}]},{"key":"automation","label":"Automation","featureCount":4,"features":[{"section":"cli","slug":"scaffolding-generators","label":"CLI","title":"Scaffolding Generators","summary":"Scaffold modules, pages, payloads, services, and contracts through commands that already understand Semitexa structure and AI-friendly output modes.","opensInNewTab":false,"href":"/demo/cli/scaffolding-generators"},{"section":"cli","slug":"workers-scheduling","label":"CLI","title":"Workers & Scheduling","summary":"Run queues, scheduler pools, mail delivery, webhooks, and tenant-scoped commands from a coherent operator surface instead of bespoke daemons.","opensInNewTab":false,"href":"/demo/cli/workers-scheduling"},{"section":"cli","slug":"ai-tooling","label":"CLI","title":"AI Tooling Surface","summary":"Semitexa exposes AI-facing commands as explicit CLI contracts: capabilities, skills, log access, and a local assistant entrypoint.","opensInNewTab":false,"href":"/demo/cli/ai-tooling"},{"section":"cli","slug":"orm-console","label":"CLI","title":"ORM Console Toolkit","summary":"The ORM ships with a practical CLI surface: status, diff, sync, and seed commands with dry-run safety and SQL plan export.","opensInNewTab":false,"href":"/demo/cli/orm-console"}]}]},{"key":"project-graph","label":"Project Graph","summary":"The `semitexa-project-graph` package: stored structural graph, intelligence layer, impact analysis, and task-scoped context for serious repository work.","icon":"PG","eyebrow":"AI Accelerator","starter":true,"prerequisites":["cli"],"featureCount":3,"href":"/demo/project-graph","features":[{"section":"project-graph","slug":"overview","label":"Project Graph","title":"Project Graph Overview","summary":"Understand what `semitexa-project-graph` adds: a stored structural map, an intelligence layer, and task-scoped context for large-codebase work.","opensInNewTab":false,"href":"/demo/project-graph/overview"},{"section":"project-graph","slug":"inspection","label":"Project Graph","title":"Inspecting the Graph","summary":"Use Project Graph queries and intelligence views to inspect modules, dependencies, flows, events, and hotspots without reconstructing the repository manually.","opensInNewTab":false,"href":"/demo/project-graph/inspection"},{"section":"project-graph","slug":"impact","label":"Project Graph","title":"Impact, Context, and Watch Mode","summary":"Use impact analysis, context packing, and watch mode to scope risky changes and keep graph-backed answers current during long work sessions.","opensInNewTab":false,"href":"/demo/project-graph/impact"}],"groups":[{"key":"launch","label":"Start Here","featureCount":1,"features":[{"section":"project-graph","slug":"overview","label":"Project Graph","title":"Project Graph Overview","summary":"Understand what `semitexa-project-graph` adds: a stored structural map, an intelligence layer, and task-scoped context for large-codebase work.","opensInNewTab":false,"href":"/demo/project-graph/overview"}]},{"key":"exploration","label":"Explore & Inspect","featureCount":1,"features":[{"section":"project-graph","slug":"inspection","label":"Project Graph","title":"Inspecting the Graph","summary":"Use Project Graph queries and intelligence views to inspect modules, dependencies, flows, events, and hotspots without reconstructing the repository manually.","opensInNewTab":false,"href":"/demo/project-graph/inspection"}]},{"key":"change-safety","label":"Impact & Context","featureCount":1,"features":[{"section":"project-graph","slug":"impact","label":"Project Graph","title":"Impact, Context, and Watch Mode","summary":"Use impact analysis, context packing, and watch mode to scope risky changes and keep graph-backed answers current during long work sessions.","opensInNewTab":false,"href":"/demo/project-graph/impact"}]}]},{"key":"llm","label":"LLM Module","sidebarLabel":"LLM","summary":"The dedicated `semitexa/llm` module: AI assistant entrypoint, skill discovery, planner, executor, provider backends, and skill authoring rules.","icon":"AI","eyebrow":"semitexa/llm","starter":false,"prerequisites":["cli"],"featureCount":4,"href":"/demo/llm","features":[{"section":"llm","slug":"overview","label":"LLM Module","title":"LLM Module Overview","summary":"What `semitexa/llm` adds to the framework and how your project can expose its own CLI skills to the assistant.","opensInNewTab":false,"href":"/demo/llm/overview"},{"section":"llm","slug":"providers","label":"LLM Module","title":"Providers & Backends","summary":"Provider contracts, backend resolution, local vs remote Ollama, and the environment knobs that shape LLM runtime behavior.","opensInNewTab":false,"href":"/demo/llm/providers"},{"section":"llm","slug":"skills","label":"LLM Module","title":"Adding Skills","summary":"How a console command becomes AI-executable through `#[AsAiSkill]`, metadata policy, and registry discovery.","opensInNewTab":false,"href":"/demo/llm/skills"},{"section":"llm","slug":"execution-flow","label":"LLM Module","title":"Execution Flow","summary":"How a user request becomes a planner decision, a reviewed skill proposal, and finally a real console execution.","opensInNewTab":false,"href":"/demo/llm/execution-flow"}],"groups":[{"key":"assistant-basics","label":"Assistant Surface","featureCount":2,"features":[{"section":"llm","slug":"overview","label":"LLM Module","title":"LLM Module Overview","summary":"What `semitexa/llm` adds to the framework and how your project can expose its own CLI skills to the assistant.","opensInNewTab":false,"href":"/demo/llm/overview"},{"section":"llm","slug":"providers","label":"LLM Module","title":"Providers & Backends","summary":"Provider contracts, backend resolution, local vs remote Ollama, and the environment knobs that shape LLM runtime behavior.","opensInNewTab":false,"href":"/demo/llm/providers"}]},{"key":"skill-system","label":"Skill System","featureCount":2,"features":[{"section":"llm","slug":"skills","label":"LLM Module","title":"Adding Skills","summary":"How a console command becomes AI-executable through `#[AsAiSkill]`, metadata policy, and registry discovery.","opensInNewTab":false,"href":"/demo/llm/skills"},{"section":"llm","slug":"execution-flow","label":"LLM Module","title":"Execution Flow","summary":"How a user request becomes a planner decision, a reviewed skill proposal, and finally a real console execution.","opensInNewTab":false,"href":"/demo/llm/execution-flow"}]}]},{"key":"testing","label":"Testing","summary":"Contract-level verification patterns for payloads and other framework boundaries.","icon":"QA","eyebrow":"Verification","starter":false,"prerequisites":["routing"],"featureCount":1,"href":"/demo/testing","features":[{"section":"testing","slug":"payload-contracts","label":"Testing","title":"Payload Contract Testing","summary":"Run one project-level contract suite through the canonical test runner and let strategy profiles verify payload boundaries without hand-writing repetitive negative cases.","opensInNewTab":false,"href":"/demo/testing/payload-contracts"}],"groups":[{"key":"contracts","label":"Contracts","featureCount":1,"features":[{"section":"testing","slug":"payload-contracts","label":"Testing","title":"Payload Contract Testing","summary":"Run one project-level contract suite through the canonical test runner and let strategy profiles verify payload boundaries without hand-writing repetitive negative cases.","opensInNewTab":false,"href":"/demo/testing/payload-contracts"}]}]}]}],"currentSection":"cli","currentSlug":"orm-console","infoWhat":"The ORM includes a practical console toolkit for schema inspection, diffing, syncing, and seeding with safe defaults.","infoHow":"orm:status reports server capabilities and sync state, orm:diff shows the delta, orm:sync can dry-run or export the SQL plan, and orm:seed applies defaults() upserts for seedable resources.","infoWhy":"A framework should not stop at attributes and repositories. Real teams need an operational surface that explains what will happen before it changes production state.","infoKeywords":[{"term":"orm:status","definition":"Reports database/server capabilities and whether the schema is currently in sync."},{"term":"orm:diff","definition":"Shows structural differences between the code schema and the live database."},{"term":"--output","definition":"Exports the computed SQL plan to a file for audit, review, or deployment pipelines."}],"navMode":"catalog","activeLayerKey":"full-catalog","authUi":{"isAuthenticated":false,"label":"Google user","shortLabel":"Google","email":null,"startUrl":"/demo/auth/google/start?return_to=%2Fdemo","authPageUrl":"/demo/auth/google?return_to=%2Fdemo","accountUrl":"/demo/auth/google?return_to=%2Fdemo","logoutUrl":"/demo/auth/google/logout?return_to=%2Fdemo","actionLabel":"Sign in with Google","signInTitle":"Sign in with Google to unlock advanced demos","signedInLabel":"Authorized as"},"explanation":{"what":"The ORM includes a practical console toolkit for schema inspection, diffing, syncing, and seeding with safe defaults.","how":"orm:status reports server capabilities and sync state, orm:diff shows the delta, orm:sync can dry-run or export the SQL plan, and orm:seed applies defaults() upserts for seedable resources.","why":"A framework should not stop at attributes and repositories. Real teams need an operational surface that explains what will happen before it changes production state.","keywords":[{"term":"orm:status","definition":"Reports database/server capabilities and whether the schema is currently in sync."},{"term":"orm:diff","definition":"Shows structural differences between the code schema and the live database."},{"term":"--output","definition":"Exports the computed SQL plan to a file for audit, review, or deployment pipelines."}]},"sourceCode":{"orm:status Command":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Semitexa\\Orm\\Application\\Console\\Command;\n\nuse Semitexa\\Core\\Attribute\\AsCommand;\nuse Semitexa\\Core\\Console\\BaseCommand;\nuse Semitexa\\Orm\\Adapter\\ServerCapability;\nuse Semitexa\\Orm\\Application\\Service\\Connection\\ConnectionRegistry;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Style\\SymfonyStyle;\n\n#[AsCommand(name: 'orm:status', description: 'Show ORM status: database info, server capabilities, schema summary')]\nclass OrmStatusCommand extends BaseCommand\n{\n    public function __construct(\n        private readonly ConnectionRegistry $connections,\n    ) {\n        parent::__construct();\n    }\n\n    protected function configure(): void\n    {\n        $this->setName('orm:status')\n            ->setDescription('Show ORM status: database info, server capabilities, schema summary')\n            ->addOption('connection', 'c', InputOption::VALUE_REQUIRED, 'Connection name to inspect', 'default');\n    }\n\n    protected function execute(InputInterface $input, OutputInterface $output): int\n    {\n        $io = new SymfonyStyle($input, $output);\n        $connectionOption = $input->getOption('connection');\n        $connection = is_string($connectionOption) && $connectionOption !== '' ? $connectionOption : 'default';\n\n        try {\n            $orm = $this->connections->manager($connection);\n            $adapter = $orm->getAdapter();\n            $isSqlite = str_contains(strtolower($adapter::class), 'sqlite');\n\n            // Server info\n            $io->section('Database Server');\n            $serverInfo = [\n                ['Server Version' => $adapter->getServerVersion()],\n                ['Database' => $orm->getDatabaseName()],\n            ];\n            if (!$isSqlite) {\n                $serverInfo[] = ['Pool Size' => (string) $orm->getPool()->getSize()];\n            }\n            $io->definitionList(...$serverInfo);\n\n            // Capabilities\n            $io->section('Server Capabilities');\n            $rows = [];\n            foreach (ServerCapability::cases() as $capability) {\n                $supported = $adapter->supports($capability);\n                $rows[] = [\n                    $capability->value,\n                    $capability->name,\n                    $supported ? '<info>Yes</info>' : '<fg=red>No</>',\n                ];\n            }\n            $io->table(['Capability', 'Name', 'Supported'], $rows);\n\n            // Code schema summary\n            $io->section('Code Schema');\n            $collector = $orm->getSchemaCollector();\n            $schema = $collector->collect();\n\n            $errors = $collector->getErrors();\n            $warnings = $collector->getWarnings();\n\n            $totalColumns = 0;\n            $totalIndexes = 0;\n            foreach ($schema as $table) {\n                $totalColumns += count($table->getColumns());\n                $totalIndexes += count($table->getIndexes());\n            }\n\n            $io->definitionList(\n                ['Tables' => (string) count($schema)],\n                ['Total Columns' => (string) $totalColumns],\n                ['Total Indexes' => (string) $totalIndexes],\n                ['Validation Errors' => (string) count($errors)],\n                ['Validation Warnings' => (string) count($warnings)],\n            );\n\n            if ($errors !== []) {\n                $io->error('Validation errors:');\n                $io->listing($errors);\n            }\n\n            if ($warnings !== []) {\n                $io->warning('Warnings:');\n                $io->listing($warnings);\n            }\n\n            // Sync status\n            $io->section('Sync Status');\n            $comparator = $orm->getSchemaComparator();\n            $diff = $comparator->compare($schema);\n\n            if ($diff->isEmpty()) {\n                $io->success('Database is in sync with code.');\n            } else {\n                $syncEngine = $orm->getSyncEngine();\n                $plan = $syncEngine->buildPlan($diff);\n                $io->warning('Database is out of sync.');\n                $io->text($plan->getSummary());\n            }\n\n            return Command::SUCCESS;\n        } catch (\\Throwable $e) {\n            $io->error('Status check failed: ' . $e->getMessage());\n            if ($output->isVerbose()) {\n                $io->text($e->getTraceAsString());\n            }\n            return Command::FAILURE;\n        }\n    }\n}\n","orm:diff Command":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Semitexa\\Orm\\Application\\Console\\Command;\n\nuse Semitexa\\Core\\Attribute\\AsCommand;\nuse Semitexa\\Core\\Console\\BaseCommand;\nuse Semitexa\\Orm\\Application\\Service\\Connection\\ConnectionRegistry;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Style\\SymfonyStyle;\n\n#[AsCommand(name: 'orm:diff', description: 'Show differences between code schema and database')]\nclass OrmDiffCommand extends BaseCommand\n{\n    public function __construct(\n        private readonly ConnectionRegistry $connections,\n    ) {\n        parent::__construct();\n    }\n\n    protected function configure(): void\n    {\n        $this->setName('orm:diff')\n            ->setDescription('Show differences between code schema and database')\n            ->addOption('connection', 'c', InputOption::VALUE_REQUIRED, 'Connection name to diff', 'default');\n    }\n\n    protected function execute(InputInterface $input, OutputInterface $output): int\n    {\n        $io = new SymfonyStyle($input, $output);\n        $connectionOption = $input->getOption('connection');\n        if (!is_string($connectionOption)) {\n            $io->error('Invalid --connection option value.');\n\n            return Command::FAILURE;\n        }\n\n        $connection = trim($connectionOption);\n        if ($connection === '') {\n            $io->error('The --connection option must not be empty.');\n\n            return Command::FAILURE;\n        }\n\n        try {\n            $orm = $this->connections->manager($connection);\n\n            // 1. Collect schema from code\n            $collector = $orm->getSchemaCollector();\n            $codeSchema = $collector->collect();\n\n            $errors = $collector->getErrors();\n            if ($errors !== []) {\n                $io->error('Schema validation errors:');\n                $io->listing($errors);\n                return Command::FAILURE;\n            }\n\n            // 2. Compare with DB\n            $comparator = $orm->getSchemaComparator();\n            $diff = $comparator->compare($codeSchema);\n\n            if ($diff->isEmpty()) {\n                $io->success('No differences. Database matches code schema.');\n    \n                return Command::SUCCESS;\n            }\n\n            // Display diff\n            foreach ($diff->getCreateTables() as $table) {\n                $io->section(\"+ CREATE TABLE `{$table->name}`\");\n                foreach ($table->getColumns() as $col) {\n                    $io->text(\"    + {$col->name} ({$col->type->canonicalName($col->length, $col->precision, $col->scale)})\");\n                }\n            }\n\n            foreach ($diff->getAddColumns() as $tableName => $columns) {\n                $io->section(\"~ ALTER TABLE `{$tableName}`\");\n                foreach ($columns as $col) {\n                    $io->text(\"    <info>+ ADD COLUMN</info> {$col->name} ({$col->type->canonicalName($col->length, $col->precision, $col->scale)})\");\n                }\n            }\n\n            foreach ($diff->getAlterColumns() as $tableName => $alterations) {\n                if (!isset($diff->getAddColumns()[$tableName])) {\n                    $io->section(\"~ ALTER TABLE `{$tableName}`\");\n                }\n                foreach ($alterations as $alt) {\n                    $col = $alt['column'];\n                    $changes = implode(', ', $alt['changes']);\n                    $io->text(\"    <comment>~ MODIFY COLUMN</comment> {$col->name}: {$changes}\");\n                }\n            }\n\n            foreach ($diff->getDropColumns() as $tableName => $columns) {\n                if (!isset($diff->getAddColumns()[$tableName]) && !isset($diff->getAlterColumns()[$tableName])) {\n                    $io->section(\"~ ALTER TABLE `{$tableName}`\");\n                }\n                foreach ($columns as $colInfo) {\n                    $io->text(\"    <fg=red>- DROP COLUMN</> {$colInfo['name']}\");\n                }\n            }\n\n            foreach ($diff->getAddIndexes() as $tableName => $indexes) {\n                foreach ($indexes as $entry) {\n                    $cols = implode(', ', $entry['index']->columns);\n                    $io->text(\"    <info>+ ADD INDEX</info> {$entry['name']} ({$cols})\");\n                }\n            }\n\n            foreach ($diff->getDropIndexes() as $tableName => $indexNames) {\n                foreach ($indexNames as $name) {\n                    $io->text(\"    <fg=red>- DROP INDEX</> {$name}\");\n                }\n            }\n\n            foreach ($diff->getAddForeignKeys() as $fk) {\n                $io->text(\"    <fg=green>+ ADD FK</> `{$fk->constraintName()}` ({$fk->table}.{$fk->column} → {$fk->referencedTable}.{$fk->referencedColumn}) ON DELETE {$fk->onDelete->value}\");\n            }\n\n            foreach ($diff->getDropForeignKeys() as $entry) {\n                $io->text(\"    <fg=red>- DROP FK</> `{$entry['constraintName']}` from `{$entry['table']}`\");\n            }\n\n            foreach ($diff->getDropTables() as $dbTable) {\n                $phase = $dbTable->tableComment === 'SEMITEXA_DEPRECATED' ? 'phase 2 — DROP' : 'phase 1 — deprecate';\n                $io->section(\"- DROP TABLE `{$dbTable->name}` ({$phase})\");\n            }\n\n            return Command::SUCCESS;\n        } catch (\\Throwable $e) {\n            $io->error('Diff failed: ' . $e->getMessage());\n            if ($output->isVerbose()) {\n                $io->text($e->getTraceAsString());\n            }\n            return Command::FAILURE;\n        }\n    }\n}\n","orm:sync Command":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Semitexa\\Orm\\Application\\Console\\Command;\n\nuse Semitexa\\Core\\Attribute\\AsCommand;\nuse Semitexa\\Core\\Console\\BaseCommand;\nuse Semitexa\\Orm\\Application\\Service\\Connection\\ConnectionRegistry;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Style\\SymfonyStyle;\n\n#[AsCommand(name: 'orm:sync', description: 'Synchronize ORM schema with the database')]\nclass OrmSyncCommand extends BaseCommand\n{\n    public function __construct(\n        private readonly ConnectionRegistry $connections,\n    ) {\n        parent::__construct();\n    }\n\n    protected function configure(): void\n    {\n        $this->setName('orm:sync')\n            ->setDescription('Synchronize ORM schema with the database')\n            ->addOption('connection', 'c', InputOption::VALUE_REQUIRED, 'Connection name to sync', 'default')\n            ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Show SQL plan without executing')\n            ->addOption('allow-destructive', null, InputOption::VALUE_NONE, 'Allow destructive operations (DROP, type narrowing)')\n            ->addOption('output', 'o', InputOption::VALUE_REQUIRED, 'Save SQL plan to file');\n    }\n\n    protected function execute(InputInterface $input, OutputInterface $output): int\n    {\n        $io = new SymfonyStyle($input, $output);\n        $connectionOption = $input->getOption('connection');\n        if (!is_string($connectionOption)) {\n            $io->error('Invalid --connection option value.');\n\n            return Command::FAILURE;\n        }\n\n        $connection = trim($connectionOption);\n        if ($connection === '') {\n            $io->error('The --connection option must not be empty.');\n\n            return Command::FAILURE;\n        }\n\n        $dryRun = (bool) $input->getOption('dry-run');\n        $allowDestructive = (bool) $input->getOption('allow-destructive');\n        $outputOption = $input->getOption('output');\n        $outputFile = is_string($outputOption) && $outputOption !== '' ? $outputOption : null;\n\n        try {\n            $orm = $this->connections->manager($connection);\n\n            // 1. Collect schema from code\n            $io->section(\"Collecting schema from code (connection: {$connection})...\");\n            $collector = $orm->getSchemaCollector();\n            $codeSchema = $collector->collect();\n\n            $errors = $collector->getErrors();\n            if ($errors !== []) {\n                $io->error('Schema validation errors:');\n                $io->listing($errors);\n                return Command::FAILURE;\n            }\n\n            $warnings = $collector->getWarnings();\n            if ($warnings !== []) {\n                $io->warning('Schema warnings:');\n                $io->listing($warnings);\n            }\n\n            $io->text(sprintf('Found %d table(s) in code.', count($codeSchema)));\n\n            // 2. Compare with DB\n            $io->section('Comparing with database...');\n            $comparator = $orm->getSchemaComparator();\n            $diff = $comparator->compare($codeSchema);\n\n            if ($diff->isEmpty()) {\n                $io->success('Database is up to date. No changes needed.');\n\n                return Command::SUCCESS;\n            }\n\n            // 3. Build execution plan\n            $syncEngine = $orm->getSyncEngine();\n            $plan = $syncEngine->buildPlan($diff);\n\n            $io->text($plan->getSummary());\n            $io->newLine();\n\n            // Show plan details\n            $safeOps = $plan->getSafeOperations();\n            $destructiveOps = $plan->getDestructiveOperations();\n\n            if ($safeOps !== []) {\n                $io->section('Safe operations:');\n                foreach ($safeOps as $op) {\n                    $io->text(\"  <info>[{$op->type->value}]</info> {$op->description}\");\n                    if ($output->isVerbose()) {\n                        $io->text(\"    SQL: {$op->sql}\");\n                    }\n                }\n            }\n\n            if ($destructiveOps !== []) {\n                $io->section('Destructive operations:');\n                foreach ($destructiveOps as $op) {\n                    $io->text(\"  <fg=red>[{$op->type->value}]</> {$op->description}\");\n                    if ($output->isVerbose()) {\n                        $io->text(\"    SQL: {$op->sql}\");\n                    }\n                }\n\n                if (!$allowDestructive) {\n                    $io->warning('Destructive operations will be skipped. Use --allow-destructive to include them.');\n                }\n            }\n\n            // Save to file if requested\n            if ($outputFile !== null) {\n                $statements = $plan->toSqlStatements($allowDestructive);\n                $content = implode(\";\\n\", $statements) . \";\\n\";\n                file_put_contents($outputFile, $content);\n                $io->text(\"SQL plan saved to: {$outputFile}\");\n            }\n\n            // Execute if not dry-run\n            if ($dryRun) {\n                $io->note('Dry run mode — no changes applied.');\n\n                return Command::SUCCESS;\n            }\n\n            $executed = $syncEngine->execute($plan, $allowDestructive);\n            $io->success(sprintf('Executed %d operation(s).', count($executed)));\n\n            $orm->shutdown();\n            return Command::SUCCESS;\n        } catch (\\Throwable $e) {\n            $io->error('Sync failed: ' . $e->getMessage());\n            if ($output->isVerbose()) {\n                $io->text($e->getTraceAsString());\n            }\n            return Command::FAILURE;\n        }\n    }\n}\n","orm:seed Command":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Semitexa\\Orm\\Application\\Console\\Command;\n\nuse Semitexa\\Core\\Attribute\\AsCommand;\nuse Semitexa\\Core\\Console\\BaseCommand;\nuse Semitexa\\Orm\\OrmManager;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Style\\SymfonyStyle;\n\n#[AsCommand(name: 'orm:seed', description: 'Run defaults() upsert for all Resource classes with seed data')]\nclass OrmSeedCommand extends BaseCommand\n{\n    public function __construct(\n        private readonly OrmManager $orm,\n    ) {\n        parent::__construct();\n    }\n\n    protected function configure(): void\n    {\n        $this->setName('orm:seed')\n            ->setDescription('Run defaults() upsert for all Resource classes with seed data');\n    }\n\n    protected function execute(InputInterface $input, OutputInterface $output): int\n    {\n        $io = new SymfonyStyle($input, $output);\n\n        try {\n            $orm = $this->orm;\n\n            $io->section('Running seed (defaults) upsert...');\n\n            $results = $orm->getSeedRunner()->run();\n\n            if ($results === []) {\n                $io->note('No Resource classes with defaults() found.');\n    \n                return Command::SUCCESS;\n            }\n\n            $totalInserted = 0;\n            $totalUpdated = 0;\n            $totalUnchanged = 0;\n\n            $rows = [];\n            foreach ($results as $tableName => $stats) {\n                $rows[] = [$tableName, $stats['inserted'], $stats['updated'], $stats['unchanged']];\n                $totalInserted += $stats['inserted'];\n                $totalUpdated += $stats['updated'];\n                $totalUnchanged += $stats['unchanged'];\n            }\n\n            $io->table(\n                ['Table', 'Inserted', 'Updated', 'Unchanged'],\n                $rows,\n            );\n\n            $io->success(sprintf(\n                'Seed complete: %d inserted, %d updated, %d unchanged across %d table(s).',\n                $totalInserted,\n                $totalUpdated,\n                $totalUnchanged,\n                count($results),\n            ));\n\n            return Command::SUCCESS;\n        } catch (\\Throwable $e) {\n            $io->error('Seed failed: ' . $e->getMessage());\n            if ($output->isVerbose()) {\n                $io->text($e->getTraceAsString());\n            }\n            return Command::FAILURE;\n        }\n    }\n}\n"},"resultPreviewTemplate":"@project-layouts-semitexa-demo/components/previews/orm-console-toolkit.html.twig","resultPreviewData":{"commands":[{"name":"bin/semitexa orm:status","purpose":"Show DB/server capabilities and whether schema is in sync.","value":"Gives fast operational context before any change."},{"name":"bin/semitexa orm:diff","purpose":"List code-vs-database differences.","value":"Lets reviewers see pending table, column, index, and FK changes."},{"name":"bin/semitexa orm:sync --dry-run","purpose":"Build the execution plan without executing it.","value":"Safe default for CI, review, and local inspection."},{"name":"bin/semitexa orm:sync --output plan.sql","purpose":"Export the SQL plan to a file.","value":"Useful for audit trails and DevOps handoff."},{"name":"bin/semitexa orm:seed","purpose":"Run defaults() upserts for seedable resources.","value":"Makes local/demo environments reproducible quickly."}],"snippets":[{"label":"Inspect current sync state","code":"bin/semitexa orm:status\nbin/semitexa orm:diff"},{"label":"Review SQL before execution","code":"bin/semitexa orm:sync --dry-run -vv\nbin/semitexa orm:sync --dry-run --output var/migrations/history/review.sql"},{"label":"Apply safe changes, then seed","code":"bin/semitexa orm:sync\nbin/semitexa orm:seed"}]},"l2ContentTemplate":"@project-layouts-semitexa-demo/components/previews/orm-console-rules.html.twig","l2ContentData":{"rules":["Start with orm:status or orm:diff when you need to understand schema state quickly.","Treat orm:sync --dry-run as the normal review path, not as an exotic extra flag.","Use --allow-destructive only when the team intentionally wants to include DROP and narrowing operations.","Export plans with --output when another human or deployment system needs the exact SQL artifact."]},"__page_document_html_iri":"/demo/cli/orm-console","__page_document_json_iri":"/demo/cli/orm-console?_format=json","__page_alternates":[{"type":"application/json","href":"/demo/cli/orm-console?_format=json"}]}