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

  1. a Rust 2024 multi-crate workspace under cratestack/
  2. schema parsing and semantic validation for an initial .cstack subset
  3. compile-time role-specific macros: include_server_schema!("…", db = Postgres) (also db = None for database-free servers), include_embedded_schema!, include_client_schema! — each emits a cratestack_schema module shaped for one deployment shape, with strict disjoint backend output (server never emits rusqlite, embedded never emits sqlx)
  4. 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-item BatchResponse<M> envelope with savepoint isolation
  5. generated Axum model CRUD and procedure routes — for transport rest schemas (the default); transport rpc schemas instead get POST /rpc/{op_id} (unary, every CRUD verb + every procedure) plus POST /rpc/batch (sequence of frames in, sequence out in same order, per-frame error isolation, no in-batch dependencies). Streaming for Sequence-kind ops (list-return procedures) works on the same unary route via Accept: application/cbor-seq. Errors on the RPC binding are uniform RpcErrorBody { code, message, details? } with gRPC-style codes — see ADR 0005
  6. host-owned authentication through AuthProvider and internal binding through bind_auth(...) and bind_context(...)
  7. generated Rust, Dart, and TypeScript client support via include_client_schema! (Rust) and the generate-dart / generate-typescript CLI subcommands
  8. policy enforcement for the current supported model and procedure policy subset (server only)
  9. generated telemetry for procedure wrappers, procedure routes, and model list routes
  10. top-level mixin declarations plus model @use(...) expansion for reusable field sets
  11. duplicate-execution protection via IdempotencyLayer with reservation tokens and header replay, backed by either SqlxIdempotencyStore (Postgres) or RedisIdempotencyStore (Redis, via cratestack-redis)
  12. optimistic concurrency via @version with If-Match / ETag round-tripping
  13. transactional audit log via @@audit + cratestack_audit + pluggable AuditSink (server)
  14. explicit transaction isolation via run_in_isolated_tx + procedure @isolation, with commit-time retry
  15. per-principal rate limiting via RateLimitLayer + pluggable RateLimitStore, backed by either InMemoryRateLimitStore (single-replica) or RedisRateLimitStore (Redis, via cratestack-redis, so replicas share one view of consumption), with a configurable StoreErrorPolicy for store failures — Allow by default, but only for transport-class (Unavailable) errors, so a caller-inducible failure such as Redis OOM still refuses — a bounded with_store_timeout (500ms default), and typed, codec-negotiated error bodies on every response the rate-limit and idempotency layers emit themselves. See Rate Limiting
  16. soft delete via @@soft_delete (server and embedded)
  17. forward-only migrations via Migration + apply_pending with checksum drift detection
  18. runtime validators (@length, @range on Int + Decimal, @email, @regex, @uri, @iso4217) with PII-safe error messages
  19. Decimal scalar with two implemented, additive backends (0.8.0+, cratestack#505) — decimal-rust-decimal (default) and decimal-bigdecimal can both be enabled at once, each dependent in the build graph choosing its own; a schema with a Decimal field requires a decimal = RustDecimal | BigDecimal argument on its include_*_schema! call, see Scalars
  20. a crypto-aws-lc-rs Cargo feature on cratestack-pg reserved for a future FIPS-validated TLS provider — not implemented: enabling it is a hard compile_error! (not a working FIPS mode), because making it real needs the TLS backend to become a genuine choice across cratestack-sqlx/cratestack-client-rust first (both currently hard-select the non-FIPS ring backend); see issue #334
  21. embedded SQLite backend via cratestack-rusqlite: sync API, bundled SQLite, the same include_embedded_schema!-driven ModelDelegate shape as the server, with Decimal, Uuid, DateTime, and Json round-tripping exactly through canonical TEXT storage. Compiles to native (mobile via FFI, desktop) AND wasm32-unknown-unknown (browser, OPFS-backed via sqlite-wasm-rs + sqlite-wasm-vfs). One source, three targets.
  22. dialect-agnostic SQL primitives crate cratestack-sql shared by both backends — value types, filter AST, order AST, model descriptor, and a narrow Dialect trait that only varies on placeholder syntax
  23. 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 to None; list-arity fields fall back to an empty Vec; required scalars reject. Same MissingFieldFallback ladder powers model ?fields=… reads and view projections
  24. codec-json opt-out on cratestack-pg, cratestack-sqlite, cratestack-client-rust, and cratestack-client-flutter (0.4.x) — default-on so existing setups are unchanged. Backend services that have standardized on CBOR can build with default-features = false on the facade to drop the JsonCodec wrapper type, the JSON fallback in CborCodec’s content-negotiation path, and the RuntimeTransportClient::Json FFI variant. serde_json stays linked (the view methods decode into serde_json::Value and the FFI bridge still encodes/decodes its bridge payloads as JSON); the opt-out narrows codec-negotiation behavior, not the serde_json-shaped surface area. CBOR stays unconditional (the schema macros emit pub 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
  25. composable RpcLink client middleware chain on the generated TypeScript RPC client (CratestackRpcClientOptions.links), plus a standalone @cratestack/api npm package shipping createBatchLink() (automatic same-tick RPC-call coalescing into POST /rpc/batch) and createLoggerLink() — see RPC transport: client middleware. RPC-transport/TypeScript only; the REST binding and the Rust/Dart clients don’t have an equivalent chain yet
  26. db = None — procedures-only servers with no databaseinclude_server_schema!("…", db = None) requires the schema’s datasource block to declare provider = "none", checked at compile time (a schema declaring provider = "none" alongside any model block is rejected with an error naming the offending model), and produces a genuinely database-free, zero-parameter Cratestack::builder() — no PgPool threaded through anywhere. Built for pure business-logic services, RPC facades in front of another system, or stateless computation endpoints that own no models and no database
  27. cratestack-api facade — a third disjoint facade crate (cratestack = { package = "cratestack-api" }), structurally parallel to the existing cratestack-pg / cratestack-sqlite split, purpose-built for db = None servers: sqlx and cratestack-sqlx are genuinely absent from its dependency graph — not feature-gated off, structurally not a dependency at all — unlike cratestack-pg, which still depends on cratestack-sqlx by default and only sheds it when a consumer opts into default-features = false
  28. SQL views — a view <Name> from <Model>, … block with @from(M.f) source bindings and per-backend @@server_sql / @@embedded_sql (@@sql shorthand), generating a read-only ViewDelegate (or ViewDelegateNoUnique for @@no_unique views); @@materialized for a Postgres-backed materialized view with a manually-invoked refresh(). See ADR 0003 and the Views reference
  29. composite unique constraints@@unique([...]) on a model emits a real, enforced multi-column UNIQUE INDEX on both Postgres and SQLite, usable today as an ON CONFLICT target for hand-written idempotent upserts. Its sibling @@id([...]) (composite primary key) is only authorable and migratable so far — cratestack-migrate emits the DDL, but include_server_schema!/include_embedded_schema! reject any model that declares it with a compile error, since query builders, routing, and all three client generators still assume a single scalar @id column (tracked as issue #136). See the Composite Keys reference
  30. cratestack diff — a standalone CLI command that detects wire-breaking schema changes (a field/model removed or retyped in a way existing clients can’t tolerate) independent of the migration-diff generator
  31. Second, opinionated client layouts — TypeScript --swr adds a file-per-model layout (framework-free plain functions plus useSWR/useSWRMutation hooks) under src/swr/, exported as <package-name>/swr, alongside the default react-query layout in the same package; Dart --preset riverpod (file-per-model, one @riverpod provider per operation, dart_mappable-backed value equality) still replaces the default preset. Both are generation-time choices, not runtime flips. TypeScript’s --preset was removed once --swr became additive — consumers who previously generated twice to get both layouts now need one run
  32. declarative query blocks (0.11.0) — a query name(args): Type block with a raw-SQL body in @@sql("…"), for the reads the generated builders cannot express (two aggregates in one round trip, FILTER (WHERE …), GROUP BY … HAVING, CTEs). Positional $N parameters are validated against the declared argument list at parse time in both directions; the result is an author-declared type (a model is rejected); @allow/@deny are mandatory and deny-by-default, checked inside the single generated entry point before any SQL runs. Postgres and server-only — include_embedded_schema! and include_server_schema!(db = None) both reject a query at compile time — with no REST route, no RPC op ID and no generated client stub. The body executes inside a Postgres READ ONLY transaction, so DML is refused by the engine even inside a data-modifying CTE. See the Declarative Query Blocks guide

Still Narrow Or Deferred

  1. COSE transport remains an unimplemented envelope seam
  2. negotiated multi-codec routing is not complete end-to-end
  3. the parser still validates only an initial schema subset
  4. production-stable exact non-Rust selection typing is not complete
  5. richer exposure controls and some field-level policy features are still deferred
  6. the client runtime remains partially spiked rather than fully mature
  7. the migration runner is forward-only — schema-diff generation and zero-downtime coordination remain out of scope
  8. the embedded SQLite backend does not enforce @@allow / @@deny policies at SQL render time (by design — the client is untrusted; authorization is the server’s concern)
  9. @@audit and @@emit directives are currently no-ops in include_embedded_schema!; the local-journal / local-event-bus implementations (needed for sync-engine wiring) land in a follow-up release
  10. multi-DB server support — include_server_schema! accepts a db = Postgres argument (or db = None, see above) but only Postgres is wired for an actual database backend today; MySQL and SQLite-via-sqlx are non-breaking future additions
  11. @@id([...]) composite primary keys are authorable and migratable but not yet loadable by a running server or embedded app — see item 29 above

Best Fit Right Now

CrateStack is currently strongest for:
  1. internal CRUD-heavy Rust services
  2. teams that want one schema to drive delegates, routes, and client contracts
  3. services that benefit from generated policy checks and typed query builders
  4. CBOR-first or CBOR-aware HTTP APIs that still need JSON fallback
  5. banking-adjacent workloads that need transactional audit, optimistic locking, idempotency, and explicit isolation out of the box
  6. 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-unknown running inside a Dedicated Worker
  1. ../getting-started/quickstart for a minimal setup path
  2. ./banking-readiness for the regulated-workload primitives shipped on feat/banking-readiness
  3. ../guides/auth-provider for the host auth boundary
  4. ../guides/offline-first-sqlite for the embedded SQLite backend (native + browser via OPFS)
  5. ../guides/no-database-procedures for procedures-only servers with no database at all (db = None, the cratestack-api facade)
  6. ../architecture/transport-architecture for transport design
  7. ../reference/views for the view/@@materialized surface
  8. ../reference/composite-keys for @@id([...])/@@unique([...])
  9. ../reference/auth-support-matrix for the current auth and policy surface