Protobuf Schema Strategy
Concept
Protocol Buffer (.proto) definitions in the monorepo define the wire format for all data exchanged between clients and server. Protobuf provides compact binary serialization for sync payloads and API communication.
Type generation for native mobile apps is handled by UniFFI (see Shared Rust Core), not protobuf code generation. The shared core crate owns the data model definitions; protobuf handles how that data is serialized on the wire. Protobuf serialization lives in core (public) since both clients and server need to encode/decode wire data.
What Lives in Proto
proto/
score.proto
drill.proto
event.proto
roster.proto
user.proto
Each .proto file defines the wire format for a domain entity.
Example:
message Score {
bytes score_id = 1; // UUID v7 (16 bytes)
bytes shooter_id = 2; // UUID v7
bytes drill_id = 3; // UUID v7
int64 timestamp = 4;
float time = 5;
int32 points = 6;
int32 penalties = 7;
bool pass = 8;
bool voided = 9;
bytes recorded_by = 10; // UUID v7
}Role in the Architecture
| Tool | Role |
|---|---|
| Core crate (public) | Owns data model definitions (structs, enums). Source of truth for client-safe business logic. |
| UniFFI | Generates typed Swift and Kotlin bindings from the Rust core. Handles cross-language type safety. |
| Protobuf | Defines compact binary wire format for API communication and sync. The core crate implements protobuf serialization/deserialization. |
Why Protobuf for Wire Format
- Compact encoding — protobuf binary format is significantly smaller than JSON. Score entries that are 100-200 bytes as JSON compress further with protobuf.
- Type-safe serialization — you can’t accidentally send a string where a number belongs.
- Schema evolution — protobuf’s field numbering system allows adding fields without breaking existing clients.
- Efficient on poor connections — smaller payloads sync faster on degraded cell signal at ranges.
Breaking Change Detection
Buf linting and breaking change detection can enforce backward compatibility rules in CI — removing a field, changing a field type, or reusing a field number is flagged before merge.
ConnectRPC
The proto definitions are the foundation for ConnectRPC, the chosen RPC framework for all client-server communication. Service definitions are added alongside message definitions in the proto/ directory. ConnectRPC generates type-safe clients for Swift, Kotlin, and web from these service definitions. See API Design for full details.