CrateStack v0 PRD
1. Product Summary
CrateStack is a Rust-native, schema-first backend framework layer for building typed database-backed HTTP REST APIs, generated clients, declarative authorization policies, and custom business procedures. Developers define their data model, authorization rules, field exposure directives, custom fields, and procedures in.cstack schema files, then include them in Rust using:
sqlx behind the scenes for database access and supports pluggable transport composition so applications can use JSON, CBOR, sequence-aware transports such as application/cbor-seq, and future COSE envelopes without sacrificing developer experience.
CrateStack v0 is intentionally focused:
- Rust-first
- PostgreSQL-first
- Axum-first
- SQLx-backed
- HTTP REST only
- Schema-defined ORM models
- Schema-defined authorization policies
- Schema-defined CRUD exposure controls
- Schema-defined field visibility and filterability controls
- Schema-defined custom fields
- Schema-defined procedures
- Framework-delegated authentication
- Pluggable codecs
- Pluggable framing
- Optional COSE envelope support
- Generated Rust clients as a first-class output
2. Problem Statement
Rust backend developers often need to repeatedly build the same foundation across projects:- database models
- typed query APIs
- REST CRUD endpoints
- request and response structs
- authorization checks
- business procedures
- stable internal client libraries
- pagination and filtering
- serialization format handling
- framework integration
2.1 Representative Use Cases
- Internal catalog or CMS service Teams can define models, policies, and procedures once, then get generated CRUD routes and typed Rust delegates without hand-writing every handler and query parser.
- CBOR-first service boundary Platforms that do not want to normalize around JSON can keep generated HTTP APIs and clients aligned with a CBOR-first contract from day one.
-
Policy-heavy content or workflow APIs
Applications can encode data visibility rules such as
published || authorId == auth().idin schema policy declarations instead of duplicating checks across handlers and queries. -
Shared server and client contract generation
Teams can use a
.cstackschema to drive generated routes, Rust delegate usage, and experimental generated client outputs from the same source of truth.
3. Goals
3.1 Product Goals
- Let developers define data models and policies in
.cstackfiles. - Generate a typed Rust ORM client from the schema.
- Generate canonical HTTP REST CRUD routes for schema models.
- Support schema-configurable CRUD exposure per model and per operation.
- Support separate schema directives for field visibility and filterability.
- Support custom schema-defined procedures for business logic.
- Enforce model-level and procedure-level permissions.
- Delegate authentication to the host framework or application.
- Avoid forcing JSON as the wire format.
- Support JSON and CBOR as first-class codecs.
- Support framing-aware transports, including
application/cbor-seq, where route semantics justify them. - Support COSE as a transport envelope layer.
- Use SQLx behind the scenes for database execution.
- Generate Rust clients for the canonical HTTP APIs.
- Provide a clean
include_schema!developer experience. - Support resolver-backed custom fields.
3.2 Developer Experience Goals
The ideal developer flow:.cstack file, implements generated procedure traits and custom-field resolver traits, provides authentication context through the framework, and gets REST endpoints plus a typed ORM and generated client contracts.
Canonical transport design and HTTP negotiation rules are documented in:
../architecture/transport-architecture.md../architecture/http-transport-contract.md
4. Non-Goals for v0
CrateStack v0 explicitly does not include:- RPC transport.
- GraphQL.
- schema-first transport and client generation remain the core outputs.
- Production-stable non-Rust client generation in the initial slice.
- Built-in authentication.
- Session management.
- OAuth, JWT, password hashing, or login flows.
- Multi-database support beyond PostgreSQL.
- A complete migration engine.
- Polymorphic models.
- Deep nested writes.
- Advanced include trees.
- A broad plugin marketplace.
as_systemor superuser bypass APIs.- Automatic policy bypass inside procedures.
- Prisma compatibility as a formal goal.
- ZenStack compatibility as a formal goal.
5. Target Users
5.1 Primary Users
Rust backend developers who want:- typed database access
- generated REST endpoints
- schema-driven authorization
- framework-level authentication integration
- CBOR/COSE-capable HTTP APIs
- low-boilerplate CRUD and business procedure support
5.2 Secondary Users
Teams building:- internal services
- secure APIs
- embedded or constrained-environment backends
- public REST APIs requiring non-JSON formats
- policy-heavy data services
6. Core Concepts
6.1 .cstack Schema
The .cstack schema is the source of truth for:
- datasource configuration
- auth context shape
- database models
- fields
- relations
- constraints
- model-level permissions
- CRUD exposure controls
- field visibility rules
- field filterability rules
- model event emission directives
- custom-field resolution declarations
- custom input/output types
- procedures
- procedure-level permissions
6.2 ORM Client
CrateStack generates a typed Rust ORM client with model delegates:6.3 REST CRUD
CrateStack generates conventional REST endpoints for models:6.4 Procedures
Procedures are schema-defined custom business operations implemented by the application. Example:6.5 Permissions
Permissions are schema-defined authorization rules. Model example:6.6 Authentication Delegation
CrateStack does not authenticate users. The host application or framework is responsible for:- login
- sessions
- JWT verification
- cookies
6.7 Custom Fields
Schemas may declare resolver-backed custom fields:thumbnailUrl from internal infrastructure like imgproxy without making that wiring part of every handler.
6.8 Generated Clients
Generated HTTP routes are the normal API surface of a CrateStack service. The framework should generate:- a Rust async client first
- a Dart client later, designed for Riverpod-based frontends
- OAuth
- user lookup
CoolContext that represents the already-authenticated request identity.
6.7 Codec
A codec converts typed Rust values to and from HTTP request/response bodies. Examples:- CBOR
- JSON, optional only
- MessagePack, possible later
6.8 Envelope
An envelope wraps already-encoded bytes for signing, verification, encryption, or MAC operations. Examples:- no envelope
- COSE_Sign1
- COSE_Encrypt0
- COSE_Mac0
7. Example Schema
8. Functional Requirements
8.1 Schema Parsing
CrateStack must parse.cstack files containing:
- datasource blocks
- auth blocks
- model blocks
- type blocks
- procedure declarations
- mutation procedure declarations
- scalar fields
- optional fields
- list fields
- model attributes
- field attributes
- permission expressions
Required scalar types for v0
Json is a database/value type only. It must not imply JSON as the HTTP wire format.
Required field attributes for v0
Required model attributes for v0
@@paged boundary:
@@pagedis a bare model-level opt-in only- it only changes the generated top-level list route for that model
- generated
GET /{models}responses becomePage<Model>instead ofModel[] - generated Rust and Dart model
list(...)and projection-drivenlistView(...)clients follow the same paged contract - paging is still offset-based through
limitandoffset - nested relation collections and detail routes are unaffected
Required procedure attributes for v0
Page<T> boundary:
- only supported on procedure return types
Tmust be a declared model ortype- generated wire shape is
items,totalCount, andpageInfo
- no user-defined generic schema types such as
type Foo<T> - no scalar page items such as
Page<Int> - no nested page containers such as
Page<Page<Post>> - no optional or list-wrapped page containers such as
Page<Post>?orPage<Post>[] - no
Page<T>support on model fields, type fields, auth fields, or procedure arguments - no alternative built-in paged container variations beyond the canonical
Page<T>envelope above
8.2 Semantic Analysis
CrateStack must validate:- duplicate model names
- duplicate type names
- duplicate field names
- unknown field types
- invalid scalar types
- invalid relation references
- missing primary keys
- invalid policy actions
- invalid auth field references
- invalid model field references in policies
- invalid procedure input types
- invalid procedure return types
- duplicate procedure names
- unsupported database provider values
8.3 Macro Integration
The primary integration point is:- read the schema file relative to
CARGO_MANIFEST_DIR - parse the schema
- analyze the schema
- generate Rust modules and types
- generate ORM delegates
- generate policy code
- generate procedure traits
- generate REST routes
- trigger recompilation when the schema changes
8.4 ORM Requirements
8.4.1 Generated Delegates
For each model, generate a delegate:8.4.2 Query Features for v0
Required:- equality filters
- boolean filters
- simple string filters
- ordering
- limit
- offset
- primary-key lookup
containsstarts_withends_withinnot_in
8.4.3 SQL Backend
CrateStack v0 must use SQLx behind the scenes. Recommended implementation:sqlx::PgPoolsqlx::QueryBuilder<Postgres>- generated
sqlx::FromRowstructs - dynamic SQL for filters and policies
8.4.4 Policy Injection
Read, update, and delete policies must be injected into SQL where possible. Example policy:8.5 Permission Requirements
8.5.1 Supported Actions
Model permissions support:8.5.2 Default Deny
If no applicable allow rule exists, the operation must be denied.8.5.3 Multiple Allow Rules
Multiple allow rules for the same action are OR-combined. Example:8.5.4 Auth Context
Policies may reference:auth() == null means unauthenticated.
auth() != null means authenticated.
8.5.5 Procedure Permissions
Procedure-level permissions are checked before calling the application-provided procedure implementation. Example:8.5.6 No System Bypass in v0
CrateStack v0 must not provide:8.6 Procedure Requirements
8.6.1 Schema Declaration
CrateStack supports:8.6.2 Generated Types
CrateStack generates input and output types for procedure arguments and return values. Input types derive:8.6.3 Generated Procedure Trait
CrateStack generates a trait that the application must implement. Example:8.6.4 Procedure Registration
Applications register procedure implementations through the builder:8.6.5 Procedure ORM API
CrateStack may also expose procedures through a typed local API:8.6.6 Procedure REST API
Procedures are exposed as HTTP POST endpoints:- avoids complex query encoding
- works with CBOR bodies
- works with COSE envelopes
- avoids pretending arbitrary procedures are pure resources
- keeps transport simple
8.7 REST Requirements
8.7.1 Model CRUD Routes
For every model with applicable permissions, generate:8.7.2 Query Parameters
Required v0 query parameters:curl examples:
where= expressions are canonical. not(...) binds tighter than ,, and , binds tighter than |; repeated , and repeated | chains are left-associative. Parentheses override the default grouping. For example, where=a=true,b=true|c=true parses as ((a=true,b=true)|c=true), and where=not(author.profile.nickname=Zulu,published=true) negates the full grouped subexpression.
Legacy or= remains supported only as a compatibility convenience for a top-level OR list such as or=title__startsWith=Pub|author.email=owner@example.com. New contract text and examples should prefer canonical grouped where= because it is the only route form that supports nesting, mixed AND/OR grouping, and not(...).
Current relation support requires explicit field metadata:
fieldsis validated against the generated scalar model fields for the requested resource.includeis validated as a declared relation path such asauthor.profile.includeFields[path]is validated against scalar fields on the already-included relation at that exact path.includeFields[path]is rejected unlessinclude=pathis also present.- nested include trees now materialize on list and fetch routes through declared relation paths only.
includeFields[path]narrows each included path payload independently.- ordering support remains separate from include materialization and still does not extend to to-many sort paths.
fieldsanswers: which scalar fields should the primary resource return?includeanswers: which declared relation paths should be embedded?includeFields[path]answers: which scalar fields should that embedded path return?
- card/list views that only need
id,title, and one related label - admin grids that need compact rows plus a related owner email
- mobile detail previews where the embedded relation should stay small for bandwidth and cache efficiency
- to-many includes where each embedded row only needs identifiers and display text
- root
Selectionbuilders choose root scalar fields and nested include paths - nested
IncludeSelectionbuilders choose scalar fields and nested include paths under the already-included relation - projection wrappers decode projected payloads without changing the wire contract
- exact type-level projection remains intentionally looser than the projection wrapper surface
@relation(fields:[...],references:[...]) declarations rather than foreign-key inference.
To-many relations must use an explicit quantifier operator (some, every, or none) before the target field path. In this slice, relation-aware sort support follows nested to-one paths such as sort=author.email or sort=author.profile.nickname, missing related rows currently sort with explicit NULLS LAST behavior, and the model primary key is appended automatically as a deterministic tie-break when relation ordering is used without an explicit primary-key term. Any path that crosses a to-many relation remains unsupported for ordering. fields is validated against the generated scalar model fields for the requested resource, and include is validated as a declared relation path. Nested include paths now materialize on list and fetch routes, and includeFields[path] narrows the payload at each already-included relation path. Exact type-level projection and child-collection sort/pagination remain intentionally out of scope for this slice. Generated typed delegates expose the same supported relation filter and nested to-one ordering paths through both compatibility helpers such as cratestack_schema::post::author::email_desc() and cratestack_schema::post::author::profile::nickname_eq(...), and a builder-style DSL such as cratestack_schema::post::author().email().desc(), cratestack_schema::post::author().profile().nickname().eq(...), and cratestack_schema::user::sessions().some().label().contains(...) for where_expr(...) usage. Those builder expressions can now be combined directly with .and(...), .or(...), and .not()-equivalent grouping through FilterExpr, for example post::author().profile().nickname().eq("Zulu").and(post::published().is_true()).or(post::title().contains("Draft")). The route grammar remains narrower than the full generated delegate surface where true: the typed delegate DSL still exposes composition through where_expr(...) and typed builders rather than every delegate capability being representable as route query syntax. Legacy orderBy remains accepted as a compatibility alias for sort, but new contract text and generated clients should prefer sort.
Practical relation query examples:
Additional clarification for the current implemented boundary:
includeis now validated as a declared relation path rather than only a top-level relation name.- Nested include paths now materialize on list and fetch routes.
includeFields[path]narrows the payload at each already-included relation path.- What remains out of scope is exact type-level projection and child-collection sort/pagination, not nested include trees themselves.
- treat
fields,include, andincludeFields[path]as three separate controls rather than one overloaded selector includeFields[path]narrows the payload at each already-included relation path- exact type-level projection and child-collection sort/pagination remain out of scope for this slice
8.7.3 Request and Response Body
Bodies must be encoded using the configuredCoolCodec.
JSON must not be assumed by the generated code.
8.7.4 Content Negotiation
For v0, CrateStack may enforce a single configured codec per router. Example:Accept, CrateStack should return:
Accept negotiation and always return the configured codec content type.
8.7.5 Error Responses
Errors should also be encoded using the configured codec. Canonical error shape:8.8 Codec Requirements
8.8.1 Codec Trait
CrateStack core exposes:8.8.2 Required Codecs
v0 should provide:8.8.3 CBOR Requirements
CBOR should support all generated model and procedure input/output types through Serde. Recommended implementation crate:8.8.4 Generated Types
All generated transport types must derive:8.9 COSE Envelope Requirements
8.9.1 Envelope Trait
CrateStack core exposes:8.9.2 Required Envelopes
Core provides:CoseSign1Envelope initially.
8.9.3 Processing Order
Request processing:8.9.4 Auth Interaction
COSE verification may enrichCoolContext, but it must not replace framework-level authentication unless the host application explicitly chooses that behavior.
Example possible enrichment:
8.10 Authentication Context Requirements
CrateStack must expose a flexible context type:CoolContext from request extensions.
9. Architecture
9.1 Crate Layout
Recommended workspace:9.2 Generated Code Structure
include_schema! generates:
9.3 Request Pipeline
Model CRUD request:9.4 SQL Generation Strategy
Use generated metadata plus SQLx query builders. Read example:10. Public API Sketch
10.1 Application Setup
10.2 COSE Setup
10.3 ORM Usage
10.4 Procedure Usage
11. Error Handling
CrateStack should use one primary error type:12. Security Requirements
- Default deny for all model and procedure operations.
- No generated route should bypass policy checks.
- Procedure implementations must use normal policy-protected ORM methods.
- No
as_systemAPI in v0. - Policy checks should be SQL-injected for read/update/delete where possible.
- Procedure-level permissions must be checked before calling implementation code.
- Auth context must come from host application or framework integration.
- Codec errors must not leak sensitive internals.
- Database errors should be sanitized before transport response.
- COSE verification failure must reject the request before decoding application data.
- COSE metadata should be available for audit or policy extensions later.
- Generated code must avoid SQL injection by using bind parameters.
13. CLI Requirements
Even though the primary integration isinclude_schema!, a CLI is useful for validation and future migration support.
Required v0 CLI commands:
14. Testing Requirements
14.1 Parser Tests
- valid schemas
- invalid schemas
- diagnostic locations
- procedures
- policies
- auth blocks
- type blocks
14.2 Semantic Tests
- duplicate names
- unknown types
- invalid auth references
- invalid model references
- missing primary keys
- invalid procedure return types
14.3 Policy Tests
- read policy SQL generation
- update policy SQL generation
- delete policy SQL generation
- create policy checks
- procedure policy checks
- delegated DB-backed procedure auth checks
- default deny behavior
14.4 ORM Tests
- create
- find unique
- find many
- update
- delete
- filtering
- pagination
- ordering
14.5 REST Tests
- CRUD routes
- procedure routes
- CBOR request decoding
- CBOR response encoding
- unsupported content type
- forbidden access
- unauthorized access
- not found
14.6 COSE Tests
- valid signed request
- invalid signature
- missing signature
- response signing
- key resolution failure
14.7 Integration Tests
Use temporary PostgreSQL database or test containers. Test a full app flow:15. Milestones
Implementation kickoff note: The current repo slice completes Milestone 0 plus a narrow parser/macro/codec/CLI spike from Milestones 1, 3, and 7. Current implementation note: The current repo slice now also starts Milestone 4 withcratestack-sqlx, generated model structs, generated type structs, generated create/update input structs, a schema-specific CrateStack wrapper, and delegate scaffolding for create, find_many, find_unique, update, and delete.
Current limitations:
- Generated SQL currently assumes snake_case column names and naive pluralized snake_case table names.
- The current SQLx slice supports
where_with AND-combined scalar filters plusorder_bywith explicit ascending/descending clauses. - The current filter model is intentionally narrow and currently targets
eq,ne,in, stringcontains, stringstarts_with, boolean convenience helpers, andis_null/is_not_nullfor optional fields. - Generated create inputs currently exclude
@idand@default(...)fields. - Generated update inputs currently use optional patch fields and only include changed columns in SQL.
- Read policy SQL injection now exists for
@@allow(...)and@@deny(...)rules onfind_manyandfind_unique, with deny taking precedence over allow. - The supported model-policy subset is intentionally tiny:
auth() != null,auth() == null, boolean field checks,field == literal,field != literal,field == auth().field,field != auth().field,auth().field == literal,auth().field != literal, andallaction expansion, with&&/||support inside a single rule. - Policy parsing is still compile-time only inside the macro layer, and unsupported policy expressions fail code generation.
- Write-policy enforcement now exists for
create,update, anddelete, but only for the same tiny predicate subset used by the current read-policy implementation. - Create policies are evaluated against generated input values plus auth context before insertion, while update/delete policies are injected into SQL row scoping; create-time auth-derived defaults now support the narrow
@default(auth().field)form before create-policy evaluation. - DB-backed policy integration coverage now exists behind an env-gated test path using
CRATESTACK_TEST_DATABASE_URL. - The current executable auth/policy capability matrix now lives in
../reference/auth-support-matrix.md. - Procedure-level policy execution now exists through generated runtime wrappers under
cratestack_schema::procedures::*and reuses canonical policy types fromcratestack-policy. - The current procedure-policy subset now supports grouped
&&/||,auth() == null, nestedargs.<field>access, input-vs-auth comparisons, and input-vs-input comparisons, but it still does not expose a general DB-querying procedure policy language. - Generated procedure registry traits now exist and provide the first narrow execution contract for procedure implementations.
- Model-level
@@emit(...)directives now support the narrowcreated,updated, anddeletedevent set, generated typed subscription helpers undercratestack_schema::events, transactional outbox writes inside generated SQLx mutations, and explicitcratestack_schema::events().drain()style replay/drain hooks for in-process delivery. - Generated Axum procedure routes now exist for procedure invocation and enforce procedure policy checks plus delegated
@authorize(...)checks before handler execution. - Generated Axum model routes now exist for
GET /{modelPlural},GET /{modelPlural}/{id},POST /{modelPlural},PATCH /{modelPlural}/{id}, andDELETE /{modelPlural}/{id}and reuse the same codec/context/policy pattern. - The generated HTTP layer now enforces a single configured codec per router for
AcceptandContent-Type, returning406 Not Acceptableand415 Unsupported Media Typefor mismatches. - The current HTTP model slice is still intentionally narrow: list routes now expose canonical
fields, shallow declared-relationinclude, relation-specificincludeFields[relation], canonicalsort,limit,offset, scalar equality filters, a small operator suffix set (__ne,__lt,__lte,__gt,__gte,__in,__contains,__startsWith,__isNull) withcuid, UUID, and DateTime parsing, canonical groupedwhere=expressions withnot(...)>,(AND) >|(OR) precedence and left-associative chaining, and recursive relation filters backed by explicit@relation(fields:[...],references:[...])metadata, with to-many traversal requiring explicitsome/every/nonequantifiers and any to-manysortpath remaining unsupported. LegacyorderByis still accepted only as a compatibility alias. The route grammar remains narrower than the full generated delegate/runtime filter surface, while write routes forward directly into the generated delegate/runtime layer without a richer request DSL. cratestack/compose.ymlnow provides a local PostgreSQL 18 instance for driving DB-backed tests throughCRATESTACK_TEST_DATABASE_URL.- Arbitrary policy functions, explicit impersonation/acting-as semantics, and a general DB-querying procedure policy language remain future work.
Milestone 0: Project Skeleton
Deliverables:- workspace setup
- core crates
- basic CI
- formatter/linter
- initial docs
Milestone 1: Schema Parser
Deliverables:- parse datasource
- parse auth block
- parse models
- parse fields
- parse attributes
- parse type blocks
- parse procedures
- parse permissions
Milestone 2: Semantic Analyzer
Deliverables:- schema IR
- validation errors
- type resolution
- policy expression validation
- procedure signature validation
Milestone 3: Macro Codegen
Deliverables:include_schema!- generated model structs
- generated input structs
- generated procedure trait
- generated basic
CrateStacktype
Milestone 4: SQLx ORM
Deliverables:- PostgreSQL-only execution
- create
- find unique
- find many
- update
- delete
- simple filters
- limit/offset
- ordering
Milestone 5: Policy Enforcement
Deliverables:- model read policy
- model create policy
- model update policy
- model delete policy
- default deny
- procedure allow checks
Milestone 6: Axum REST
Deliverables:- generated CRUD routes
- generated procedure routes
- path/query/body parsing
- error responses
- request context extraction
Milestone 7: Codec System
Deliverables:CoolCodectrait- CBOR codec crate
- optional JSON codec crate
- generated handlers generic over codec
Milestone 8: Envelope System
Deliverables:CoolEnvelopetraitNoEnvelope- initial COSE Sign1 envelope
- request verification
- response signing
Milestone 9: Hardening and Docs
Deliverables:- security review
- integration examples
- tutorial
- API reference
- migration notes
- release candidate
16. v0 Acceptance Criteria
CrateStack v0 is successful when a developer can:- Create a
.cstackschema with models, policies, types, and procedures. - Include it with
cratestack::include_schema!("schema.cstack"). - Instantiate the generated
CrateStacktype with a SQLx PostgreSQL pool. - Register procedure implementations.
- Use the generated ORM client in Rust.
- Mount generated Axum REST routes.
- Send CBOR requests to CRUD endpoints.
- Send CBOR requests to procedure endpoints.
- Receive CBOR responses.
- Enforce model permissions by auth context.
- Enforce procedure permissions by auth context.
- Confirm unauthorized operations are denied by default.
- Run without enabling JSON features.
- Optionally wrap requests/responses with a COSE envelope.
17. Open Questions
- Should procedure endpoints use
/api/$procs/name,/api/_procedures/name, or/api/actions/name? - Should read-like procedures ever support GET, or should v0 require POST for all procedures?
- Should the generated schema module always be named
cratestack_schema, or should the macro allow custom names? - Should codec selection be per-router, per-request, or compile-time feature based?
- Should COSE verification be allowed to populate
CoolContext.auth, or only transport metadata? - Should migrations be included in v0 or deferred?
- Should relation support be included in the first release or delayed until after scalar CRUD is stable?
- Should JSON be provided as an official optional crate from day one or delayed?
- Should policy expressions support custom functions in v0?
- Should generated handlers support pluralization customization?
18. Recommended Initial Decisions
For v0, make these decisions explicit:- Use Axum only.
- Use PostgreSQL only.
- Use SQLx only.
- Use POST for all procedures.
- Use
/api/$procs/{name}for procedures initially. - Make CBOR the first official codec.
- Make JSON optional and not part of core.
- Make COSE an optional envelope crate.
- Keep authentication entirely external.
- Use default-deny permission semantics.
- Do not implement
as_system. - Generate a fixed
cratestack_schemamodule in v0. - Keep plugin architecture narrow: codec, envelope, auth/context extraction, and later hooks.
19. Risks
19.1 Macro Complexity
Large generated code from a procedural macro may produce difficult compiler errors. Mitigation:- strong schema diagnostics before codegen
- readable generated identifiers
- optional debug output later
- CLI
print-ir
19.2 SQL Policy Correctness
Incorrect policy injection could leak data. Mitigation:- default deny
- snapshot tests for generated SQL
- property-style authorization tests
- avoid policy bypass APIs in v0
19.3 Codec/Envelope Coupling
Mixing CBOR and COSE incorrectly could make the transport hard to reason about. Mitigation:- keep codec and envelope traits separate
- document strict processing order
- test request and response pipelines thoroughly
19.4 Scope Creep
ORMs, REST generation, policy systems, and procedure systems can expand endlessly. Mitigation:- PostgreSQL only
- Axum only
- no separate service-description format requirement
- no RPC
- no GraphQL
- no multi-db
- no full migration engine in v0
19.5 Rust Type Generation Ergonomics
Generated APIs may become verbose or unidiomatic. Mitigation:- start with simple delegates
- prioritize readable generated code
- provide examples early
- iterate with real app usage
20. Long-Term Roadmap
After v0:- Relation loading.
- Nested includes.
- Nested writes.
- Migration engine.
- Additional databases.
- Actix integration.
- Poem integration.
- More codecs.
- More COSE envelope modes.
- Policy custom functions.
- Hooks.
- Soft delete plugin.
- Field-level encryption plugin.
- Generated admin UI metadata.
- Optional additional documentation/export surfaces.
- Optional client generation.
- More advanced procedure routing.
- Better diagnostics and editor tooling.
21. One-Sentence Product Definition
CrateStack is a Rust-native schema-first framework layer that turns.cstack files into a typed SQLx-backed ORM, policy-protected REST CRUD API, and custom REST procedure endpoints with pluggable CBOR/COSE-capable transport support.