βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β USER APPLICATION β
β β
β ββββββββββββ ββββββββββββ ββββββββββββ β
β β User β β Company β β Car β ... Entities β
β ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ β
β β β β β
β βββββββββββββββ΄βββββββββββββββ β
β β β
βββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β THIS-RS FRAMEWORK β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β CORE MODULE (Generic) β β
β β β β
β β ββββββββββββ ββββββββββββ ββββββββββββ β β
β β β Entity β β Link β β Field β β β
β β β Traits β β System β β System β β β
β β ββββββββββββ ββββββββββββ ββββββββββββ β β
β β β β
β β ββββββββββββ ββββββββββββ ββββββββββββ β β
β β β Service β βPluralize β β Module β β β
β β β Traits β β System β β System β β β
β β ββββββββββββ ββββββββββββ ββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βββββββββββββββββββββΌββββββββββββββββββββ β
β βΌ βΌ βΌ β
β βββββββββββ βββββββββββββββ βββββββββββ β
β β LINKS β β CONFIG β βENTITIES β β
β β MODULE ββββββββ€ MODULE βββββββΊβ MODULE β β
β β β β β β β β
β β Service β β YAML Loader β β Macros β β
β βRegistry β β Parser β β β β
β βββββββββββ βββββββββββββββ βββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββ
β STORAGE LAYER β
β β
β ββββββββββββββ β
β β In-Memory β β
β ββββββββββββββ β
β ββββββββββββββ β
β β DynamoDB β β
β ββββββββββββββ β
ββββββββββββββββββββ
The heart of the framework, completely agnostic of concrete entity types.
src/core/
βββ entity.rs β Fundamental traits
β βββ Entity : Base trait (id, type, timestamps, status)
β βββ Data : Inherits Entity, adds name + indexed fields
β βββ Link : Inherits Entity, adds source_id + target_id
β
βββ link.rs β Polymorphic link system
β βββ LinkEntity : Concrete link implementation
β βββ LinkDefinition : Link type configuration
β
βββ field.rs β Types and validation
β βββ FieldValue : Polymorphic value (String, Int, UUID, etc.)
β βββ FieldFormat : Validators (Email, URL, Phone, Custom)
β
βββ service.rs β Service traits
β βββ DataService<T> : CRUD for entities
β βββ LinkService : CRUD for links
β
βββ module.rs β Module system
β βββ Module : Groups entities + config
β βββ EntityFetcher : Fetch entities for link enrichment
β βββ EntityCreator : Create entities dynamically
β
βββ pluralize.rs β Pluralization
β βββ Pluralizer : company β companies
β
βββ auth.rs β Authorization
β βββ AuthProvider : Auth policy provider
β βββ AuthContext : User auth context
β
βββ extractors.rs β HTTP extractors (Axum)
βββ LinkExtractor : Extract link info from URL
βββ DirectLinkExtractor: Extract specific link from URL
Key Principle: No reference to concrete types (User, Car, etc.) in core.
The framework provides a 3-level entity hierarchy:
βββββββββββββββββββββββββββββββββββββββββββ
β Entity (Base) β
β - id: Uuid (auto-generated) β
β - type: String (auto-set) β
β - created_at: DateTime<Utc> β
β - updated_at: DateTime<Utc> β
β - deleted_at: Option<DateTime<Utc>> β
β - status: String β
βββββββββββββββββββ¬ββββββββββββββββββββββββ
β
ββββββββββ΄βββββββββ
β β
βΌ βΌ
βββββββββββββββββββ βββββββββββββββββββ
β Data Entity β β Link Entity β
β (Inherits) β β (Inherits) β
β β β β
β + name: String β β + source_id β
β + custom fieldsβ β + target_id β
β β β + link_type β
βββββββββββββββββββ βββββββββββββββββββ
All entities inherit these fields:
pub trait Entity {
fn id(&self) -> Uuid;
fn entity_type(&self) -> &str;
fn created_at(&self) -> DateTime<Utc>;
fn updated_at(&self) -> DateTime<Utc>;
fn deleted_at(&self) -> Option<DateTime<Utc>>;
fn status(&self) -> &str;
// Utility methods
fn is_deleted(&self) -> bool;
fn is_active(&self) -> bool;
}
Data entities represent domain objects:
pub trait Data: Entity {
fn name(&self) -> &str;
fn indexed_fields(&self) -> Vec<&str>;
fn field_value(&self, field_name: &str) -> Option<FieldValue>;
}
Link entities represent relationships:
pub trait Link: Entity {
fn source_id(&self) -> Uuid;
fn target_id(&self) -> Uuid;
fn link_type(&self) -> &str;
}
The framework provides powerful macros to eliminate boilerplate:
impl_data_entity!Generates a complete Data entity:
impl_data_entity!(Order, "order", ["name", "number"], {
number: String,
amount: f64,
customer_name: Option<String>,
notes: Option<String>,
});
Generates:
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Order {
// Base Entity fields (auto-injected)
pub id: Uuid,
pub entity_type: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub deleted_at: Option<DateTime<Utc>>,
pub status: String,
// Data field (auto-injected)
pub name: String,
// Custom fields
pub number: String,
pub amount: f64,
pub customer_name: Option<String>,
pub notes: Option<String>,
}
impl Entity for Order { /* auto-implemented */ }
impl Data for Order { /* auto-implemented */ }
impl Order {
pub fn new(...) -> Self { /* auto-generated constructor */ }
pub fn soft_delete(&mut self) { /* soft delete support */ }
pub fn touch(&mut self) { /* update timestamp */ }
pub fn set_status(&mut self, status: String) { /* status update */ }
pub fn restore(&mut self) { /* restore from soft delete */ }
}
impl_link_entity!Generates a custom Link entity:
impl_link_entity!(CustomLink, "custom_link", {
metadata_field: String,
});
entity_fields!() - Inject base Entity fieldsdata_fields!() - Inject Entity + name fieldslink_fields!() - Inject Entity + link fieldsManages relationships between entities without knowing their types.
src/links/
βββ handlers.rs β HTTP handlers (Axum)
β βββ list_links : GET /{entity}/{id}/{route_name}
β βββ get_link : GET /links/{link_id}
β βββ get_link_by_route : GET /{source}/{sid}/{route}/{tid}
β βββ create_link : POST /{source}/{sid}/{route}/{tid}
β βββ create_linked_entity: POST /{source}/{sid}/{route}
β βββ update_link : PUT /{source}/{sid}/{route}/{tid}
β βββ delete_link : DELETE /{source}/{sid}/{route}/{tid}
β
βββ registry.rs β Route resolution
β βββ LinkRouteRegistry : URL β LinkDefinition
β
βββ service.rs β Link service implementation
βββ (moved to storage/)
From YAML configuration:
links:
- link_type: owner
source_type: user
target_type: car
forward_route_name: cars-owned
reverse_route_name: owner
Auto-generated routes:
GET /users/{id}/cars-owned β List cars owned by user
POST /users/{id}/cars-owned β Create new car + link
GET /users/{id}/cars-owned/{car_id} β Get specific link
POST /users/{id}/cars-owned/{car_id} β Link existing car
PUT /users/{id}/cars-owned/{car_id} β Update link metadata
DELETE /users/{id}/cars-owned/{car_id} β Delete link
GET /cars/{id}/owner β Get owner of car (reverse)
Modules group related entities and provide services:
pub trait Module: Send + Sync {
fn name(&self) -> &str;
fn entity_types(&self) -> Vec<&str>;
fn links_config(&self) -> Result<LinksConfig>;
fn register_entities(&self, registry: &mut EntityRegistry);
fn get_entity_fetcher(&self, entity_type: &str) -> Option<Arc<dyn EntityFetcher>>;
fn get_entity_creator(&self, entity_type: &str) -> Option<Arc<dyn EntityCreator>>;
}
Dynamically fetches entities for link enrichment:
#[async_trait]
pub trait EntityFetcher: Send + Sync {
async fn fetch_as_json(&self, entity_id: &Uuid) -> Result<serde_json::Value>;
}
Implementation example:
#[async_trait]
impl EntityFetcher for OrderStore {
async fn fetch_as_json(&self, entity_id: &Uuid) -> Result<serde_json::Value> {
let order = self.get(entity_id)
.ok_or_else(|| anyhow::anyhow!("Order not found"))?;
Ok(serde_json::to_value(order)?)
}
}
Dynamically creates entities with automatic linking:
#[async_trait]
pub trait EntityCreator: Send + Sync {
async fn create_from_json(&self, entity_data: serde_json::Value) -> Result<serde_json::Value>;
}
Implementation example:
#[async_trait]
impl EntityCreator for OrderStore {
async fn create_from_json(&self, entity_data: serde_json::Value) -> Result<serde_json::Value> {
let order = Order::new(
entity_data["number"].as_str().unwrap_or("").to_string(),
entity_data["status"].as_str().unwrap_or("active").to_string(),
// ... other fields
);
self.add(order.clone());
Ok(serde_json::to_value(order)?)
}
}
1. HTTP Request
POST /users/{user_id}/cars-owned/{car_id}
Body: { "metadata": { "purchase_date": "2024-01-15" } }
2. Axum Handler (create_link)
β DirectLinkExtractor parses URL
β Extracts: source_id, target_id, link_type
3. LinkService.create()
β Creates LinkEntity
β link_type: "owner"
β source_id: user_id (UUID)
β target_id: car_id (UUID)
4. Storage Layer
β Insert LinkEntity
5. Response
β LinkEntity { id, link_type, source_id, target_id, ... }
1. HTTP Request
POST /users/{user_id}/cars-owned
Body: {
"entity": { "name": "Tesla Model 3", "brand": "Tesla", ... },
"metadata": { "purchase_date": "2024-01-15" }
}
2. Axum Handler (create_linked_entity)
β LinkExtractor parses URL
β Extracts: source_id, entity_type, route_name
3. Get EntityCreator from Module
β module.get_entity_creator("car")
4. EntityCreator.create_from_json()
β Creates new Car entity
β Stores in database
β Returns created entity with ID
5. LinkService.create()
β Creates link: user_id β car_id
6. Response
β {
"entity": { /* created car */ },
"link": { /* created link */ }
}
1. HTTP Request
GET /users/{user_id}/cars-owned
2. LinkRouteRegistry.resolve_route()
β "user" + "cars-owned"
β β LinkDefinition { link_type: "owner", ... }
β β Direction: Forward
3. LinkService.find_by_source()
β source_id: user_id
β source_type: "user"
β link_type: Some("owner")
β target_type: Some("car")
4. Enrich Links (enrich_links_with_entities)
β For each link:
β - Get EntityFetcher for "car"
β - Fetch full car entity by target_id
β - Embed in link response
5. Response
β {
"links": [
{
"id": "link-123",
"source_id": "user-uuid",
"target_id": "car-uuid",
"target": { /* FULL car entity */ },
"metadata": { /* link metadata */ }
}
]
}
Key: No N+1 queries! Entities are fetched efficiently.
Loads and parses YAML configuration:
src/config/
βββ mod.rs
βββ LinksConfig : Complete configuration
βββ EntityConfig : Entity configuration
YAML structure:
entities:
- singular: order
plural: orders
- singular: invoice
plural: invoices
links:
- link_type: has_invoice
source_type: order
target_type: invoice
forward_route_name: invoices
reverse_route_name: order
description: "Order has invoices"
auth:
create:
policy: AllowOwner
roles: ["admin", "user"]
src/storage/
βββ in_memory.rs β In-memory implementation
β βββ InMemoryLinkService
β
βββ dynamodb.rs β DynamoDB implementation
βββ DynamoDbDataService<T>
βββ DynamoDbLinkService
Both implement the same traits:
DataService<T> for entity CRUDLinkService for link CRUDFluent API for building HTTP servers:
let app = ServerBuilder::new()
.with_link_service(InMemoryLinkService::new())
.register_module(billing_module)?
.register_module(catalog_module)?
.build()?;
What it does:
Collects and builds entity routes:
pub struct EntityRegistry {
descriptors: Vec<Box<dyn EntityDescriptor>>,
}
impl EntityRegistry {
pub fn register(&mut self, descriptor: Box<dyn EntityDescriptor>);
pub fn build_routes(&self) -> Router;
}
Core framework never knows concrete types:
// β
Framework uses trait objects
Arc<dyn EntityFetcher>
Arc<dyn EntityCreator>
Arc<dyn DataService<T>>
// β Framework never does this
Arc<OrderStore>
Arc<UserService>
Entities are fetched/created dynamically at runtime:
let fetcher = module.get_entity_fetcher("order")?;
let entity = fetcher.fetch_as_json(&order_id).await?;
Eliminate boilerplate with compile-time generation:
// Input: 4 lines
impl_data_entity!(Order, "order", ["name"], {
amount: f64,
});
// Output: 100+ lines of generated code
Routes and validation defined in YAML:
links:
- link_type: owner
source_type: user
target_type: car
forward_route_name: cars-owned
Modules provide services through trait methods:
impl Module for BillingModule {
fn get_entity_fetcher(&self, entity_type: &str) -> Option<Arc<dyn EntityFetcher>> {
match entity_type {
"order" => Some(Arc::new(self.store.orders.clone())),
_ => None,
}
}
}
β
Zero Boilerplate: Define entities in 4 lines
β
Auto-Generated Routes: No manual routing code
β
Type Safety: Full Rust compile-time checks
β
Consistent Patterns: Same structure everywhere
β
Link Enrichment: No N+1 query problems
β
Extensibility: Easy to add new storage backends
β
Testability: Trait-based design allows mocking
β
Modularity: Clear separation of concerns
β
Maintainability: Generic core never changes
The architecture is designed for maximum productivity with zero compromise on type safety. ππ¦β¨