Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Architecture choices in generated projects

cargo rullst new records product capabilities that materially change the generated application. Version 12 intentionally exposes one audited application architecture instead of presenting incomplete compatibility markers as equal implementations. The framework specification and capability ledger remain authoritative.

ORM style

Version 12 database-backed projects are generated with Active Record. The CLI does not ask for a global ORM architecture and does not expose an --orm flag. The framework’s repository APIs remain available when an application needs an explicit persistence boundary.

Architecturev12/v13 directionTrade-off
Active RecordThe single generated v12 profile and a retained v13 optionConcise, but persistence concerns remain close to models.
Data Mapper / RepositoryApplication-owned in v12; planned as a separately complete v13 profileMore explicit persistence boundary and more code to maintain.
HybridNot a global project profileThe two styles may naturally coexist per module, but the application must define that boundary.

Earlier v12 prerelease menus offered three labels, but Repository and Hybrid shared generation branches and support varied by blueprint. Removing those selectors does not remove ORM APIs; it prevents the generator from claiming equivalent end-to-end profiles before the generated routes, services and tests support them consistently. All database operations still need parameter binding, authorization and transaction design.

For most CRUD-oriented applications, start with Active Record and introduce a repository around domains that genuinely need a separate persistence boundary.

Database engines and capabilities

The first database selector chooses exactly one SQL Active Record backend:

SelectionCurrent v12 boundary
SQLiteLocal SQLx pool, migrations and relational ORM contract.
PostgreSQLSQLx PostgreSQL pool and live container CRUD/schema contract.
MySQLSQLx MySQL pool and live MySQL CRUD/schema contract.
MariaDBThe same MySQL protocol implementation with a separate live MariaDB contract.
TursoTyped Turso/libSQL primary profile for the blank full-stack or API starter; SQLx-specific blueprints do not offer it.

A second multi-select adds zero or more independent capabilities and accepts Enter with no selection. Capabilities already selected by the primary profile or CLI flags are omitted. Turso supplies explicit edge SQL, transactions and checked migrations; MongoDB supplies portable document CRUD; DuckDB supplies bounded analytics; SurrealDB supplies document CRUD and bounded read-only graph queries; Qdrant supplies bounded dense-vector operations. Selecting one adds the precise Cargo features and environment keys, but does not make every model portable between different database families.

This split prevents a Turso, MongoDB, analytics, or graph label from generating an application whose SQL Active Record migrations cannot run. See the Polyglot Persistence guide for the APIs and limits.

Frontend profile

Version 12 generates server-rendered html! views with HTMX enhancement and does not ask for a frontend engine or expose a --frontend flag. The five labels shown by earlier prerelease wizards were not five complete, interchangeable renderers:

SelectionCurrent v12 boundary
HTMX + Tailwind SSRAudited default scaffold using server-rendered html! views. There is no project-local SPA bundle, but HTMX and styles are still browser assets that must be pinned and served.
LiveViewCore supplies LiveComponent, Live::mount and live_ws_handler. The application registers routes and supplies the HTMX WebSocket extension, authentication and reconnect policy.
Wasm Island#[island], make:island and build:client provide a dual-target hydration foundation. Asset delivery, CSP, state, routing and browser E2E remain application work.
Pico.cssRecords the compatibility profile; the application must add, pin and serve Pico.css and validate the resulting pages.
TeraAdds the Tera dependency in the generated manifest. A complete file-template renderer and migration of every blueprint view are not generated automatically.

Version 13 should model independent capabilities instead of one misleading global frontend selector: rendering (SSR or API), interaction (HTMX, LiveView or Wasm islands), styling (the bundled design or an explicitly materialized CSS system), and templating (html! or a fully generated file-template path). A combination should appear only after its assets, routes and browser behavior have equivalent tests.

Full-stack versus headless API

  • Full-stack blueprints include server-rendered routes and relevant local tool integration.
  • --api generates a JSON-oriented Blank project without HTML view rendering; product blueprints reject it instead of silently retaining their HTML routes.

Generated code is application code. Review its routes, auth boundaries, database schema and dependencies before deployment.

Optional AI

Selecting AI adds rullst-ai and its provider-agnostic client foundation. Providers still require explicit credentials or the documented deterministic mock mode. Ollama can keep prompt traffic on infrastructure you operate, but “local” alone does not establish an air gap. Measure compile time, binary size, latency, quality and cost for the chosen provider and model.

Cache and queues

Without Redis, Rullst offers process-local memory cache and local queue options. With Redis selected, the generated project can configure the feature-gated Redis adapters.

There is deliberately no silent production fallback from Redis to memory: a distributed deployment that loses Redis must not pretend that independent process-local state is equivalent. Choose the backend explicitly and test its failure policy. Core realtime broadcast/presence remains in-process; Redis cache and queue support does not turn it into distributed WebSocket pub/sub.

Studio and Nexus

  • Studio’s supported v12 launcher is debug-only, binds to loopback and verifies direct peer information. It shows only data supplied by real local probes.
  • Nexus uses a local-development policy or explicit release credentials. A dependency or generated route does not remove the need for application RBAC.

Neither interface should be exposed publicly without an application-owned identity, authorization, TLS and network policy.

Omni packaging

Rullst uses a web-first, platform-enhanced model. The web application is the canonical universally reachable product; the server remains authoritative for domain rules, authentication, authorization, persistence, realtime and security. Omni may package that interface and later add scoped native capabilities, but it must not fork the business model or trust a client-side decision as authority.

cargo rullst make:omni scaffolds a Tauri-powered shell and commands for desktop and mobile targets. Deterministic generation pins the local Tauri CLI, requires an explicit validated backend URL and application-owned identifier for mobile, derives or validates product metadata, generates real platform icon assets and fails when an explicitly requested platform cannot be initialized. The packaged bootstrap exposes no remote IPC. A native navigation policy allows only Tauri’s local origin and the configured backend’s exact origin, leaving OAuth/external links for a reviewed system-browser/deep-link contract.

rullst::client_contract supplies one shared rullst.client v1 JSON boundary for browser, server and future platform-enhanced code. It negotiates positive versions, rejects unknown outer fields and oversized bodies, and carries typed payloads, correlation, optional mutation idempotency, server time and bounded failure codes. It deliberately has no user/tenant/role claim: authentication, authorization, domain validation and durable replay handling remain server work. This is a transport foundation for rich clients, not offline sync.

The opt-in native offline-sync profile builds a bounded state machine on that transport boundary. It keeps cached server records separate from queued local proposals, requires unique idempotency keys, uses explicit server revisions and cursors, isolates conflicts from automatic replay, and makes incremental/full resync transitions atomic within the state value. Its encrypted v1 snapshot is AES-256-GCM authenticated to an exact account and rotation-key id. The framework adds a static-dispatch foreground coordinator with request budgets, mandatory timeouts and cursor-progress checks, but does not choose client-wins, accept cached authorization, own a platform key, or silently write/contact an arbitrary filesystem, browser store or endpoint. Keychain/Keystore, atomic platform persistence, concrete authenticated HTTP, retry/background scheduling and later schema migrations remain application/platform decisions until dedicated adapters have evidence.

Path-aware workflows generate disposable applications and check desktop on Linux/macOS/Windows, an Android debug APK and an iOS simulator target. All three passed for commit 755fbd61933bed04369e0eb5de50b11275db5e3d.

That gate proves reproducible generation and simulator compilation only. It does not automatically mount offline synchronization, secure remote networking, platform signing, privacy declarations, physical-device behavior, store publication, native updater policy or every frontend profile. Push, biometrics, OS secure storage, deep links and offline state must be opt-in, least-privilege additions with platform tests. Treat the generated shell as application-owned packaging code that must be reviewed, signed and tested on each supported target.

Engineering invariants

Repository policy requires typed failures rather than production panic!, unwrap() or expect(), explicit SQL parameterization/sanitization, and the workspace test/Clippy/format gates. These are review and CI rules, not a claim that arbitrary application code or third-party dependencies cannot panic.

Rullst exposes Axum/Tower integration so applications can add middleware and routes directly. That escape hatch also means the final security and observability composition belongs to the application.

Practical starting points

  • Single-process CRUD application: use the generated Active Record, html! SSR and HTMX profile with memory cache.
  • Domain-heavy service on v12: introduce repositories per module with explicit transaction boundaries. In v13, select a Data Mapper / Repository project profile only after its blueprint has full generated-route and test parity.
  • Multi-process application: a configured shared cache/queue plus deployment tests; do not assume realtime is distributed.
  • Rich browser interaction: opt into LiveView or Wasm foundations only with application-owned integration and browser tests until a complete v13 profile exists.

Revisit these choices as evidence changes. Do not infer performance, security or availability from a wizard label.