Both wire-format concerns are now enforced by the type system via serde,
eliminating manual conversions at every layer:
SnowflakeId (id encryption on the wire):
- All DTO id fields use SnowflakeId instead of String; serialization emits
encode_id (cipher+base62 under ID_ENCODING), deserialization accepts both
forms and rejects garbage with 400
- Services/models pass SnowflakeId through; parse_id only remains at
untyped boundaries (Path<String>/Query/batch ids)
- utoipa PartialSchema/ToSchema impls added; reader ecommerce permissions
seeded (cart/orders/product_comments/favorites) across all 3 schemas
- reserved_usernames site option (data-driven, 4-128 charset validation)
Price (money wire format is yuan):
- New Price type (sqlx-transparent over i64 cents) with yuan serde,
arithmetic ops, checked helpers, DbBigint coercion for CRUD macros
- Models/commands/DTOs across product/variant/cart/order/payment/coupon/
wallet/shipping/favorites all use Price; arithmetic stays integer cents
- Admin submits yuan, storefront formatPrice only adds the currency symbol
- Fix coupon Fixed-discount semantics (discount capped at order amount)
AGENTS.md documents both conventions.