feat: backend MVP (auth/rbac, catalog, orders, fulfillment, invoices) + specs + scaffolds
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::Type;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)]
|
||||
#[sqlx(type_name = "user_role", rename_all = "snake_case")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum UserRole {
|
||||
PlatformAdmin,
|
||||
ShopOwner,
|
||||
ShopStaff,
|
||||
Customer,
|
||||
}
|
||||
|
||||
impl UserRole {
|
||||
pub fn is_shop_role(self) -> bool {
|
||||
matches!(self, UserRole::ShopOwner | UserRole::ShopStaff)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)]
|
||||
#[sqlx(type_name = "shop_status", rename_all = "snake_case")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ShopStatus {
|
||||
Active,
|
||||
Suspended,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, sqlx::FromRow)]
|
||||
pub struct User {
|
||||
pub id: Uuid,
|
||||
pub email: String,
|
||||
#[serde(skip_serializing)]
|
||||
pub password_hash: String,
|
||||
pub display_name: String,
|
||||
pub role: UserRole,
|
||||
pub shop_id: Option<Uuid>,
|
||||
pub locale: String,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, sqlx::FromRow)]
|
||||
pub struct Shop {
|
||||
pub id: Uuid,
|
||||
pub name: serde_json::Value,
|
||||
pub slug: String,
|
||||
pub status: ShopStatus,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)]
|
||||
#[sqlx(type_name = "product_status", rename_all = "snake_case")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ProductStatus {
|
||||
Draft,
|
||||
Published,
|
||||
Unpublished,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, sqlx::FromRow)]
|
||||
pub struct Category {
|
||||
pub id: Uuid,
|
||||
pub parent_id: Option<Uuid>,
|
||||
pub name: serde_json::Value,
|
||||
pub slug: String,
|
||||
pub position: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, sqlx::FromRow)]
|
||||
pub struct Product {
|
||||
pub id: Uuid,
|
||||
pub shop_id: Uuid,
|
||||
pub category_id: Option<Uuid>,
|
||||
pub slug: String,
|
||||
pub name: serde_json::Value,
|
||||
pub description: serde_json::Value,
|
||||
pub images: serde_json::Value,
|
||||
pub status: ProductStatus,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, sqlx::FromRow)]
|
||||
pub struct Sku {
|
||||
pub id: Uuid,
|
||||
pub product_id: Uuid,
|
||||
pub sku_code: String,
|
||||
pub attributes: serde_json::Value,
|
||||
pub price_minor: i64,
|
||||
pub currency: String,
|
||||
pub stock: i32,
|
||||
pub active: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, sqlx::FromRow)]
|
||||
pub struct Currency {
|
||||
pub code: String,
|
||||
pub name: serde_json::Value,
|
||||
pub symbol: String,
|
||||
pub exponent: i16,
|
||||
pub is_base: bool,
|
||||
pub rate_to_base: rust_decimal::Decimal,
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)]
|
||||
#[sqlx(type_name = "order_status", rename_all = "snake_case")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum OrderStatus {
|
||||
PendingPayment,
|
||||
Paid,
|
||||
Fulfilling,
|
||||
Shipped,
|
||||
Completed,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)]
|
||||
#[sqlx(type_name = "shipment_status", rename_all = "snake_case")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ShipmentStatus {
|
||||
Pending,
|
||||
Shipped,
|
||||
Delivered,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)]
|
||||
#[sqlx(type_name = "invoice_status", rename_all = "snake_case")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum InvoiceStatus {
|
||||
Requested,
|
||||
Issued,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)]
|
||||
#[sqlx(type_name = "invoice_kind", rename_all = "snake_case")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum InvoiceKind {
|
||||
Personal,
|
||||
Company,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, sqlx::FromRow)]
|
||||
pub struct Order {
|
||||
pub id: Uuid,
|
||||
pub order_no: String,
|
||||
pub shop_id: Uuid,
|
||||
pub user_id: Uuid,
|
||||
pub status: OrderStatus,
|
||||
pub currency: String,
|
||||
pub total_minor: i64,
|
||||
pub shipping_address: serde_json::Value,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, sqlx::FromRow)]
|
||||
pub struct OrderItem {
|
||||
pub id: Uuid,
|
||||
pub order_id: Uuid,
|
||||
pub sku_id: Uuid,
|
||||
pub product_name: serde_json::Value,
|
||||
pub sku_code: String,
|
||||
pub image: Option<String>,
|
||||
pub unit_price_minor: i64,
|
||||
pub qty: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, sqlx::FromRow)]
|
||||
pub struct Shipment {
|
||||
pub id: Uuid,
|
||||
pub shipment_no: String,
|
||||
pub order_id: Uuid,
|
||||
pub carrier: String,
|
||||
pub tracking_no: String,
|
||||
pub status: ShipmentStatus,
|
||||
pub shipped_at: Option<DateTime<Utc>>,
|
||||
pub delivered_at: Option<DateTime<Utc>>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, sqlx::FromRow)]
|
||||
pub struct ShipmentItem {
|
||||
pub shipment_id: Uuid,
|
||||
pub order_item_id: Uuid,
|
||||
pub qty: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, sqlx::FromRow)]
|
||||
pub struct Invoice {
|
||||
pub id: Uuid,
|
||||
pub invoice_no: Option<String>,
|
||||
pub order_id: Uuid,
|
||||
pub user_id: Uuid,
|
||||
pub title: String,
|
||||
pub tax_no: Option<String>,
|
||||
pub kind: InvoiceKind,
|
||||
pub amount_minor: i64,
|
||||
pub currency: String,
|
||||
pub status: InvoiceStatus,
|
||||
pub issued_at: Option<DateTime<Utc>>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
Reference in New Issue
Block a user