Current State
CrateStack already provides a usable Rust-first backend slice, but it is not yet the full target architecture described in the ADR and PRD.Implemented Today
- a Rust 2024 multi-crate workspace under
cratestack/ - schema parsing and semantic validation for an initial
.cstacksubset - compile-time role-specific macros:
include_server_schema!("…", db = Postgres),include_embedded_schema!,include_client_schema!— each emits acratestack_schemamodule shaped for one deployment shape, with strict disjoint backend output (server never emits rusqlite, embedded never emits sqlx) - SQLx-backed model delegates for
create,upsert(insert-or-update on PK conflict),find_many,find_unique,update,delete, plus the five batch primitives (batch_get,batch_create,batch_update,batch_delete,batch_upsert) returning a per-itemBatchResponse<M>envelope with savepoint isolation - generated Axum model CRUD and procedure routes — for
transport restschemas (the default);transport rpcschemas instead getPOST /rpc/{op_id}(unary, every CRUD verb + every procedure) plusPOST /rpc/batch(sequence of frames in, sequence out in same order, per-frame error isolation, no in-batch dependencies). Streaming forSequence-kind ops (list-return procedures) works on the same unary route viaAccept: application/cbor-seq. Errors on the RPC binding are uniformRpcErrorBody { code, message, details? }with gRPC-style codes — see ADR 0005 - host-owned authentication through
AuthProviderand internal binding throughbind_auth(...)andbind_context(...) - generated Rust client support via
include_client_schema!, plus generated Dart package output - policy enforcement for the current supported model and procedure policy subset (server only)
- generated telemetry for procedure wrappers, procedure routes, and model list routes
- top-level
mixindeclarations plus model@use(...)expansion for reusable field sets - duplicate-execution protection via
IdempotencyLayerwith reservation tokens and header replay, backed by eitherSqlxIdempotencyStore(Postgres) orRedisIdempotencyStore(Redis, viacratestack-redis) - optimistic concurrency via
@versionwithIf-Match/ETaground-tripping - transactional audit log via
@@audit+cratestack_audit+ pluggableAuditSink(server) - explicit transaction isolation via
run_in_isolated_tx+ procedure@isolation, with commit-time retry - per-principal rate limiting via
RateLimitLayer+ pluggableRateLimitStore - soft delete via
@@soft_delete(server and embedded) - forward-only migrations via
Migration+apply_pendingwith checksum drift detection - runtime validators (
@length,@rangeon Int + Decimal,@email,@regex,@uri,@iso4217) with PII-safe error messages - Decimal scalar with selectable backend (
rust_decimalorbigdecimal) - FIPS-validated TLS provider toggle via the
crypto-aws-lc-rsworkspace feature - embedded SQLite backend via
cratestack-rusqlite: sync API, bundled SQLite, the sameinclude_embedded_schema!-drivenModelDelegateshape as the server, withDecimal,Uuid,DateTime, andJsonround-tripping exactly through canonical TEXT storage. Compiles to native (mobile via FFI, desktop) ANDwasm32-unknown-unknown(browser, OPFS-backed viasqlite-wasm-rs+sqlite-wasm-vfs). One source, three targets. - dialect-agnostic SQL primitives crate
cratestack-sqlshared by both backends — value types, filter AST, order AST, model descriptor, and a narrowDialecttrait that only varies on placeholder syntax - projection-decode tolerance (0.4.x) — generated client decoders for
?fields=…reads tolerate the server omitting fields the projection didn’t ask for, while still hard-failing on a missing required scalar. Optional scalars (T?) fall back toNone; list-arity fields fall back to an emptyVec; required scalars reject. SameMissingFieldFallbackladder powers model?fields=…reads and view projections codec-jsonopt-out oncratestack-pg,cratestack-sqlite,cratestack-client-rust, andcratestack-client-flutter(0.4.x) — default-on so existing setups are unchanged. Backend services that have standardized on CBOR can build withdefault-features = falseon the facade to drop theJsonCodecwrapper type, the JSON fallback inCborCodec’s content-negotiation path, and theRuntimeTransportClient::JsonFFI variant.serde_jsonstays linked (the view methods decode intoserde_json::Valueand the FFI bridge still encodes/decodes its bridge payloads as JSON); the opt-out narrows codec-negotiation behavior, not theserde_json-shaped surface area. CBOR stays unconditional (the schema macros emitpub struct Client<C = CborCodec>); the projection-view client methods (get_view/list_view/list_view_paged) route through the client’s codec, so they keep working over CBOR
Still Narrow Or Deferred
- COSE transport remains an unimplemented envelope seam
- negotiated multi-codec routing is not complete end-to-end
- the parser still validates only an initial schema subset
- production-stable exact non-Rust selection typing is not complete
- richer exposure controls and some field-level policy features are still deferred
- the client runtime remains partially spiked rather than fully mature
- the shipped rate-limit store is in-memory (single-replica); the trait is pluggable
- the migration runner is forward-only — schema-diff generation and zero-downtime coordination remain out of scope
- the embedded SQLite backend does not enforce
@@allow/@@denypolicies at SQL render time (by design — the client is untrusted; authorization is the server’s concern) @@auditand@@emitdirectives are currently no-ops ininclude_embedded_schema!; the local-journal / local-event-bus implementations (needed for sync-engine wiring) land in a follow-up release- the umbrella
cratestackcrate compiles both backends unconditionally; binary-size feature gating to opt out of the sqlx/tokio stack on embedded-only builds is planned but not yet shipped (embedded-only consumers can already depend directly oncratestack-macros+cratestack-rusqliteto shed the server-side weight) - multi-DB server support —
include_server_schema!accepts adb = Postgresargument but only Postgres is wired today; MySQL and SQLite-via-sqlx are non-breaking future additions
Best Fit Right Now
CrateStack is currently strongest for:- internal CRUD-heavy Rust services
- teams that want one schema to drive delegates, routes, and client contracts
- services that benefit from generated policy checks and typed query builders
- CBOR-first or CBOR-aware HTTP APIs that still need JSON fallback
- banking-adjacent workloads that need transactional audit, optimistic locking, idempotency, and explicit isolation out of the box
- offline-first apps that want one Rust schema definition to drive the server AND an embedded SQLite store — whether on a phone (Flutter or another UI toolkit over FFI), on a desktop, or in a browser tab via OPFS-backed
wasm32-unknown-unknownrunning inside a Dedicated Worker
Read Next
../getting-started/quickstartfor a minimal setup path./banking-readinessfor the regulated-workload primitives shipped onfeat/banking-readiness../guides/auth-providerfor the host auth boundary../guides/offline-first-sqlitefor the embedded SQLite backend (native + browser via OPFS)../architecture/transport-architecturefor transport design../reference/auth-support-matrixfor the current auth and policy surface