Getting Started With catalog-service And vaam-mobile
This guide documents the first end-to-end adoption path for CrateStack inside this repo.
Target outcome:
- start from
vaam-backendswith the catalog domain - keep one shared
.cstackschema for the catalog client contract - generate a Dart package under
frontends/vaam-mobile/packages/gen-* - import that generated Dart package into
frontends/vaam-mobile/pubspec.yaml - keep mobile Rust focused on generic request execution, signing, and upload helpers in
frontends/vaam-mobile/rust/vaam_runtime
Current Repo Reality
Verified current state in this repo:vaam-backends/services/catalog-servicenow uses a generated CrateStack router for products and procedures, with only health checks left manual.- The richer catalog relation slice is now live-verified for
ownerSummary,assets,thumbnailAsset,options,variants, and nestedVariant.thumbnailAsset. - The catalog contract is currently described in prose at
vaam-backends/docs/service-interface/catalog-service.md. catalog.cstacknow coversOwner,Asset,ProductOption,Variant,Product, and the publish/upload procedures atvaam-backends/services/catalog-service/schema/catalog.cstack.- The CrateStack CLI currently supports
generate-dart,check,check --format json, andprint-ir. - There is no standalone
generate-rustCLI command yet. - Rust client generation exists today through
include_schema!compile-time codegen. frontends/vaam-mobile/pubspec.yamlalready uses local path dependencies.frontends/vaam-mobile/rust/vaam_runtimeis the mobile-owned Rust runtime crate today.- The schema uses model name
ProductOptionto avoid a RustOption<T>collision while the product relation name remainsoptions. - Runtime DB alignment currently includes
0007_catalog_variant_table_alignment.sqlso the generatedVariantmodel resolves against thevariantstable.
cratestack::include_schema!is compile-time codegen, so schema problems can appear as a slow or seemingly stuckcargo build, not just as a clean validation error.- Reverse relations that are not needed by the generated API can trigger large relation-order and relation-filter expansion costs. Prefer the smallest relation graph that still supports the generated routes and includes you actually use.
- Do not name schema models or types after common Rust prelude/container names such as
Option,Result,String, orVec. Generated code may resolve those names as schema models instead of Rust standard library types.
- Dart package generation is already automated.
- For
vaam-mobile, schema-typed client consumption now lives on the generated Dart side rather than a mobile Rust schema consumer crate. - Mobile Rust still matters for generic request execution, signing, and upload prep, but not for schema-typed catalog APIs.
Editor Setup
For.cstack authoring in VS Code, prefer the first-party extension under cratestack/packages/cratestack-vscode plus the standalone cratestack-lsp binary.
Minimal local setup:
- From
cratestack/, runcargo build -p cratestack-lsp. - From
cratestack/packages/cratestack-vscode, runpnpm installif needed. - Install or run the extension.
- If the server is not already bundled or on
PATH, setcratestack.lsp.pathto the built binary.
include_schema! APIs, keep rust-analyzer.procMacro.enable on and point VS Code at the Cargo workspaces that compile the real schema consumer.
See ../tooling/editor-tooling.md for the full current-state editor feature list and follow-up roadmap.
Recommended File Layout
Recommended shared source-of-truth path:vaam-backends/services/catalog-service/schema/catalog.cstack
- Dart package:
frontends/vaam-mobile/packages/gen_catalog_client - Rust runtime crate:
frontends/vaam-mobile/rust/vaam_runtime
- the backend-owned schema close to the catalog service
- the mobile Dart consumer inside the Flutter package tree that
pubspec.yamlalready uses - the mobile Rust workspace focused on transport/runtime concerns instead of schema-typed catalog APIs
Step 1: Author The First catalog.cstack Schema
Start narrow.
Do not try to encode the entire catalog-service target interface on day one.
Use vaam-backends/docs/service-interface/catalog-service.md as the contract source and begin with one vertical slice such as:
Product- public
GET /products/{productId} - public
GET /products - generated
POST /products,PATCH /products/{productId}, andDELETE /products/{productId} - generated
OwnerandAssetresources backing product relations - includes such as
ownerSummaryandassets - special procedure routes for publish and upload flows
vaam-backends/services/catalog-service/schema/catalog.cstack
- it keeps only the forward relations required by generated product includes
- it avoids reverse links that are attractive in a hand-written ORM model but expensive in the current code generator
- it keeps model names away from Rust standard library identifiers that can poison generated code
Step 2: Validate The Schema
Fromcratestack/:
vaam-backends/:
cratestack-cli -- check validates schema structure, but it does not prove that the full Rust proc-macro expansion remains cheap enough or avoids Rust name collisions.
Step 3: Keep Mobile Rust Generic
Forvaam-mobile, do not create a schema-typed Rust consumer crate.
Keep frontends/vaam-mobile/rust/vaam_runtime focused on:
- request signing
- request execution
- upload preparation
- generic transport/codec bridging for the app’s Dio stack
Step 5.1: Host Auth Through AuthProvider
Generated CrateStack routers no longer need a route-local context resolver closure. The host application provides one AuthProvider implementation and registers it once.
Example from vaam-backends/services/catalog-service/src/lib.rs:
auth().field lookups so existing schemas do not need to change immediately.
Step 6: Generate The Dart Package
This is the step where the schema stops being a nice idea and starts becoming app code. ✨ Fromcratestack/:
frontends/vaam-mobile/packages/gen_catalog_client
.cstack schema changes or the Dart generator/templates change. Generated packages are materialized output, so enum additions or other type-shape changes do not appear in gen_catalog_client until you regenerate it.
If the schema changed but the generated package did not, re-run the generator before debugging the mobile package.
For example, after adding:
generate-dart before gen_catalog_client exposes OwnerType in its Dart API.
The generated output is a real Flutter-style package, not a single loose Dart file. Expect:
pubspec.yamlREADME.mdCHANGELOG.mdanalysis_options.yamllib/gen_catalog_client.dartlib/src/...example/main.darttest/gen_catalog_client_test.dart
enum types in lib/src/models.dart and uses them across generated inputs, projected wrappers, and procedure surfaces.
That keeps feature code nicer too: less 'merchant' string soup, more actual types. 🍜
Example generated Dart shape:
Step 7: Import The Dart Package Into vaam-mobile
Update frontends/vaam-mobile/pubspec.yaml:
Step 8: Wire The Generated Runtime Bridge In Flutter
The generated package expects aCrateStackRuntimeBridge implementation plus provider overrides.
Minimal bridge shape:
Step 9: Use The Generated Dart Client
Example projected read:frontends/vaam-mobile/lib/src/features/discovery/data/catalog_client_example.dart
- override
genCatalogClientRuntimeBridgeProvider - override
genCatalogClientBasePathProviderto''for the current catalog service - consume generated projected reads and procedures through a small app-owned facade
getView/listView- selection builders
- projected wrapper objects
- projection builders flattened into canonical query params by the generated package
- generated procedure methods for special flows such as publish and uploads
- generated relation wrappers for
ownerSummaryandassets - Riverpod integration through the generated adapter and base-path providers
Step 10: Recommended First E2E Scope
For the first real repo adoption, keep the scope narrow:- one backend-owned schema file at
vaam-backends/services/catalog-service/schema/catalog.cstack - one Dart package at
frontends/vaam-mobile/packages/gen_catalog_client - one Rust runtime crate at
frontends/vaam-mobile/rust/vaam_runtime - one projected product fetch in Flutter
- one Dio-to-Rust transport verification path in the mobile runtime wiring
- schema shape
- backend contract alignment
- Dart package generation path
- first real schema ownership and client import ergonomics
- mobile transport/runtime integration ergonomics
Known Gaps
This guide is accurate to the current repo, but these gaps still matter:catalog-serviceis still an early slice, so the schema should keep growing in narrow vertical steps- exact type-level projection remains stronger on Rust than on Dart
- this first schema intentionally avoids
/products/mineand other owner-specific convenience routes - special flows such as
publishand uploads now live as generated CrateStack procedures rather than manual handlers - request-authorizer hooks exist in Rust, but full COSE transport completion is still deferred
- current generated backend routing uses the CBOR codec path rather than the older JSON fallback behavior
- current generated backend auth is intentionally simplified to header/context-based auth for this slice
- the generated Dart package now depends on an app-provided adapter seam; host apps still own Dio stack composition and interceptor policy
- the mobile Rust transport path is currently generic and request-driven rather than schema-native
- the Flutter-facing wrapper does not yet expose persisted state or runtime-configurable SQLite selection through the public Dart-facing surface
Recommended Next Follow-Up
After this guide is used once for real, the highest-value follow-up is:- extend
schema/catalog.cstackto the next real catalog slice - regenerate
frontends/vaam-mobile/packages/gen_catalog_client - keep the mobile adapter/interceptor wiring aligned with the regenerated package
- record the friction points
- decide whether the next improvement should be:
- public-read/protected-write router splitting in CrateStack
- JSON fallback for generated backend routes
- better shared schema placement/tooling
- tighter mobile runtime integration