# CreditService Specification > Version: 1.0 | Status: Draft | Last Updated: 2025-12-11 ## 1. Overview ### 1.1 Purpose CreditService is a centralized credit/quota management system that acts as the "bank" for PhotonCloud. It manages project-based resource usage accounting and billing, providing admission control for resource creation requests and periodic billing based on usage metrics from NightLight. ### 1.2 Scope - **In scope**: - Project wallet/balance management - Admission control (pre-creation checks) - Usage-based billing via NightLight integration - Transaction logging and audit trail - Quota enforcement - **Out of scope**: - Payment processing (external system) - Pricing configuration (admin API, separate) - User-facing billing UI (separate frontend) ### 1.3 Design Goals - **Multi-tenant**: Strict project isolation with org hierarchy - **High availability**: Distributed storage via ChainFire/FlareDB - **Low latency**: Admission control must not add >10ms to resource creation - **Auditability**: Complete transaction history - **Integration**: Seamless with IAM, NightLight, and all resource services ## 2. Architecture ### 2.1 Crate Structure ``` creditservice/ ├── crates/ │ ├── creditservice-types/ # Core types (Wallet, Transaction, Quota) │ ├── creditservice-proto/ # gRPC proto definitions │ ├── creditservice-api/ # gRPC service implementations │ ├── creditservice-server/ # Server binary │ └── creditservice-client/ # Client library ├── proto/ │ └── creditservice.proto └── Cargo.toml ``` ### 2.2 Data Flow ``` Resource Service (PlasmaVMC, etc.) │ ▼ ┌─────────────────────────────────────────────────────────┐ │ CreditService │ │ ┌─────────────┐ ┌──────────────┐ ┌────────────┐ │ │ │ Admission │───▶│ Wallet │◀───│ Billing │ │ │ │ Control │ │ Manager │ │ Batch │ │ │ └─────────────┘ └──────────────┘ └────────────┘ │ │ │ │ ▲ │ │ ▼ ▼ │ │ │ ┌─────────────────────────────────────────────┤ │ │ │ ChainFire/FlareDB │ │ │ └─────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ │ NightLight │ (Metrics) │ ``` ### 2.3 Dependencies | Crate | Purpose | |-------|---------| | tokio | Async runtime | | tonic | gRPC framework | | chainfire-client | Distributed KV for wallets | | flaredb-client | Metadata storage (optional) | | iam-client | Authentication/authorization | | nightlight-client | Usage metrics (NightLight) | | rust_decimal | Precise credit calculations | ## 3. API ### 3.1 gRPC Services ```protobuf syntax = "proto3"; package creditservice.v1; // CreditService provides credit/quota management service CreditService { // Wallet operations rpc GetWallet(GetWalletRequest) returns (GetWalletResponse); rpc CreateWallet(CreateWalletRequest) returns (CreateWalletResponse); rpc TopUp(TopUpRequest) returns (TopUpResponse); rpc GetTransactions(GetTransactionsRequest) returns (GetTransactionsResponse); // Admission Control (called by resource services) rpc CheckQuota(CheckQuotaRequest) returns (CheckQuotaResponse); rpc ReserveCredits(ReserveCreditsRequest) returns (ReserveCreditsResponse); rpc CommitReservation(CommitReservationRequest) returns (CommitReservationResponse); rpc ReleaseReservation(ReleaseReservationRequest) returns (ReleaseReservationResponse); // Billing (internal) rpc ProcessBilling(ProcessBillingRequest) returns (ProcessBillingResponse); // Quota management rpc SetQuota(SetQuotaRequest) returns (SetQuotaResponse); rpc GetQuota(GetQuotaRequest) returns (GetQuotaResponse); } ``` ### 3.2 Admission Control Flow ``` 1. Resource Service receives creation request 2. Resource Service calls CheckQuota(project_id, resource_type, quantity) 3. If approved: a. ReserveCredits(project_id, estimated_cost) -> reservation_id b. Create resource c. CommitReservation(reservation_id, actual_cost) 4. If failed: a. ReleaseReservation(reservation_id) ``` ### 3.3 Client Library ```rust use creditservice_client::Client; let client = Client::connect("http://creditservice:8090").await?; // Check if resource can be created let check = client.check_quota(CheckQuotaRequest { project_id: "proj-123".into(), resource_type: ResourceType::VmInstance, quantity: 1, estimated_cost: Some(Decimal::new(100, 2)), // 1.00 credits }).await?; if check.allowed { // Reserve and create let reservation = client.reserve_credits(ReserveCreditsRequest { project_id: "proj-123".into(), amount: Decimal::new(100, 2), description: "VM instance creation".into(), }).await?; // ... create resource ... client.commit_reservation(CommitReservationRequest { reservation_id: reservation.id, actual_amount: Decimal::new(95, 2), // actual cost }).await?; } ``` ## 4. Data Models ### 4.1 Core Types ```rust /// Project wallet containing credit balance pub struct Wallet { /// Project ID (primary key) pub project_id: String, /// Organization ID (for hierarchy) pub org_id: String, /// Current available balance pub balance: Decimal, /// Reserved credits (pending reservations) pub reserved: Decimal, /// Total credits ever deposited pub total_deposited: Decimal, /// Total credits consumed pub total_consumed: Decimal, /// Wallet status pub status: WalletStatus, /// Creation timestamp pub created_at: DateTime, /// Last update timestamp pub updated_at: DateTime, } pub enum WalletStatus { Active, Suspended, // Insufficient balance Closed, } /// Credit transaction record pub struct Transaction { pub id: Uuid, pub project_id: String, pub transaction_type: TransactionType, pub amount: Decimal, pub balance_after: Decimal, pub description: String, pub resource_id: Option, pub created_at: DateTime, } pub enum TransactionType { TopUp, // Credit addition Reservation, // Temporary hold Charge, // Actual consumption Release, // Reservation release Refund, // Credit return BillingCharge, // Periodic billing } /// Credit reservation (2-phase commit) pub struct Reservation { pub id: Uuid, pub project_id: String, pub amount: Decimal, pub status: ReservationStatus, pub description: String, pub expires_at: DateTime, pub created_at: DateTime, } pub enum ReservationStatus { Pending, Committed, Released, Expired, } /// Resource quota limits pub struct Quota { pub project_id: String, pub resource_type: ResourceType, pub limit: i64, pub current_usage: i64, } pub enum ResourceType { VmInstance, VmCpu, VmMemoryGb, StorageGb, NetworkPort, LoadBalancer, DnsZone, // ... extensible } ``` ### 4.2 Storage Format - **Engine**: ChainFire (for HA) or FlareDB (for scale) - **Serialization**: Protocol Buffers - **Key format**: ``` /credit/wallet/{project_id} -> Wallet /credit/txn/{project_id}/{txn_id} -> Transaction /credit/rsv/{reservation_id} -> Reservation /credit/quota/{project_id}/{type} -> Quota ``` ## 5. Configuration ### 5.1 Config File Format (TOML) ```toml [service] api_addr = "0.0.0.0:8090" metrics_addr = "0.0.0.0:9090" [storage] # ChainFire for HA, FlareDB for scale backend = "chainfire" # or "flaredb" endpoints = ["chainfire-1:2379", "chainfire-2:2379", "chainfire-3:2379"] [billing] # Billing interval in seconds interval_seconds = 3600 # hourly # NightLight endpoint for usage metrics nightlight_endpoint = "http://nightlight:8080" [reservation] # Reservation expiry (uncommitted reservations) expiry_seconds = 300 # 5 minutes [auth] # IAM endpoint for token validation iam_endpoint = "http://iam:8080" [tls] enabled = true cert_file = "/etc/creditservice/tls.crt" key_file = "/etc/creditservice/tls.key" ca_file = "/etc/creditservice/ca.crt" ``` ### 5.2 Environment Variables | Variable | Default | Description | |----------|---------|-------------| | CREDITSERVICE_API_ADDR | 0.0.0.0:8090 | API listen address | | CREDITSERVICE_STORAGE_BACKEND | chainfire | Storage backend | | CREDITSERVICE_BILLING_INTERVAL | 3600 | Billing interval (seconds) | | CREDITSERVICE_NIGHTLIGHT_ENDPOINT | - | NightLight endpoint | ## 6. Security ### 6.1 Authentication - mTLS for service-to-service communication - IAM token validation for API requests ### 6.2 Authorization - **Wallet operations**: Requires `credit:wallets:*` permission on project scope - **Admission control**: Service accounts with `credit:admission:check` permission - **Billing**: Internal service account only ### 6.3 Multi-tenancy - All operations scoped to project_id - Org hierarchy enforced (org admin can manage project wallets) - Cross-project access denied at API layer ## 7. Operations ### 7.1 Deployment - **Single node**: For development/testing - **Cluster mode**: ChainFire backend for HA ### 7.2 Monitoring Prometheus metrics exposed: - `creditservice_wallet_balance{project_id}` - Current balance - `creditservice_transactions_total{type}` - Transaction counts - `creditservice_admission_latency_seconds` - Admission control latency - `creditservice_billing_charges_total` - Billing charges processed ### 7.3 Health Endpoints - `GET /healthz` - Liveness probe - `GET /readyz` - Readiness probe (storage connectivity) ## 8. NightLight Integration ### 8.1 Usage Metrics Query CreditService queries NightLight for resource usage: ```promql # VM CPU hours per project sum by (project_id) ( increase(vm_cpu_seconds_total[1h]) ) / 3600 # Storage GB-hours sum by (project_id) ( avg_over_time(storage_bytes_total[1h]) ) / (1024^3) ``` ### 8.2 Billing Batch Process 1. Query NightLight for usage metrics per project 2. Calculate charges based on pricing rules 3. Deduct from project wallet 4. Log transactions 5. Suspend wallets with negative balance ## 9. Error Codes | Code | Meaning | |------|---------| | INSUFFICIENT_CREDITS | Not enough credits for operation | | QUOTA_EXCEEDED | Resource quota limit reached | | WALLET_SUSPENDED | Wallet is suspended | | WALLET_NOT_FOUND | Project wallet does not exist | | RESERVATION_EXPIRED | Credit reservation has expired | | INVALID_AMOUNT | Amount must be positive | ## Appendix ### A. Pricing Model (Example) | Resource | Unit | Price (credits/hour) | |----------|------|---------------------| | VM CPU | vCPU | 0.01 | | VM Memory | GB | 0.005 | | Storage | GB | 0.001 | | Network Egress | GB | 0.05 | ### B. Glossary - **Wallet**: Project-level credit account - **Admission Control**: Pre-creation check for sufficient credits/quota - **Reservation**: Temporary credit hold during resource creation - **Billing Batch**: Periodic process to charge for usage