feat: multi-tenancy, OpenAPI docs, blockchain listener, event sourcing#1
Open
temma02 wants to merge 5 commits into
Open
feat: multi-tenancy, OpenAPI docs, blockchain listener, event sourcing#1temma02 wants to merge 5 commits into
temma02 wants to merge 5 commits into
Conversation
- Add migration 0042: tenants table (id, name, slug, max_creators, max_tips_per_day, is_active), tenant_configs table, and tenant_id FK columns on creators and tips - Add Tenant model with CreateTenantRequest / UpdateTenantRequest DTOs - Add TenantAnalyticsService with correct creator_username join - Add tenant_controller: CRUD + analytics + usage queries - Add /tenants REST routes (GET/POST list, GET/PUT/DELETE by id, GET analytics, GET usage) wired into v1 and v2 routers - Fix tenancy/mod.rs duplicate pub mod declarations - Add missing usage_analytics to routes/mod.rs Closes Bonizozo#235
- Extend ApiDoc with health, teams, and tenants paths - Add #[utoipa::path] annotations to health (liveness + readiness) and all tenant routes (CRUD + analytics + usage) - Add ToSchema to CreateTenantRequest, UpdateTenantRequest, TenantResponse, TenantAnalytics, TenantUsage - Register all new schemas and response examples in ApiDoc components - Add health / teams / tenants tags with descriptions - Document multi-tenancy X-Tenant-ID header in API overview - Interactive explorer available at /swagger-ui Closes Bonizozo#237
- Fix EventProcessor to persist full event data: event_type, transaction_hash, and ledger_sequence (parsed from paging_token) into indexed_events table via ON CONFLICT DO NOTHING for idempotency - Add indexer::spawn() — starts BlockchainListener as a background Tokio task; reads HORIZON_URL and STELLAR_CONTRACT_ID from env; gracefully skips when Redis is unavailable (cursor falls back to 0) - Wire indexer::spawn() into main.rs after monitoring_service::spawn The listener streams Horizon SSE transactions with exponential-backoff retry (2s base, 60s cap), filters by contract ID, classifies events as tip/withdraw/unknown, and records Prometheus metrics for processed events, failures, retry attempts, and indexer lag. Closes Bonizozo#238
- Add version field to all Event variants (default=1, serde default for backward compat with stored events that predate versioning) - Migration 0043: add events.version column and event_snapshots table (aggregate_id, sequence_number, snapshot_data JSONB) - EventStore: append now stores version; add load_from, load_up_to for scoped queries; write_snapshot auto-fires every 50 events; load_latest_snapshot returns (seq, CreatorProjection) - Replayer.creator_state: snapshot + delta replay (O(delta) not O(n)) - Replayer.creator_state_at: uses load_up_to with DB-scoped sequence filter instead of the previous broken in-memory take_while - Add Serialize/Deserialize to CreatorProjection for snapshot storage - Add EventStore to AppState; build CommandBus after state construction to avoid circular dependency; inject CommandBus as axum Extension Closes Bonizozo#228
…ener-eventsourcing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR implements four features across four commits.
Bonizozo#235 — Multi-Tenancy Support
Migration
0042_tenancy_canonical:tenantstable (id,name,slug,max_creators,max_tips_per_day,is_active),tenant_configstable, andtenant_idFK columns oncreatorsandtips(all idempotent).Model
src/models/tenant.rs:Tenant,CreateTenantRequest(slug validation),UpdateTenantRequest,TenantResponse.Controller
src/controllers/tenant_controller.rs: CRUD + analytics + usage queries. Provisioning runs in a single transaction.Routes
src/routes/tenants.rs:POST/GET /tenants,GET/PUT/DELETE /tenants/:id,GET /tenants/:id/analytics,GET /tenants/:id/usage. Wired into both/api/v1and/api/v2.Tenancy layer: fixed duplicate
pub moddeclarations insrc/tenancy/mod.rs; fixedanalytics.rsto join oncreator_usernameinstead of non-existent columns. Fixed pre-existing missingusage_analyticsinsrc/routes/mod.rs.Closes Bonizozo#235
Bonizozo#237 — API Documentation with OpenAPI
Extended the existing
utoipa+SwaggerUisetup:#[utoipa::path]annotations with request/response examples on all tenant routes and health routes (/health,/ready).ToSchemaadded toCreateTenantRequest,UpdateTenantRequest,TenantResponse,TenantAnalytics,TenantUsage.ApiDocextended with health + teams + tenants paths, all new schemas, new tags,ReportMessageRequest(was missing), and multi-tenancy header note.Interactive explorer at
/swagger-ui, raw spec at/api-docs/openapi.json.Closes Bonizozo#237
Bonizozo#238 — Blockchain Event Listener
EventProcessor.persist_event: now inserts full row (event_type,transaction_hash,ledger_sequenceparsed from paging token) withON CONFLICT DO NOTHING.indexer::spawn(): readsHORIZON_URL/STELLAR_CONTRACT_IDfrom env, startsBlockchainListeneras a background Tokio task, gracefully skips when Redis is unavailable.main.rs:indexer::spawn()called at startup.Listener streams Horizon SSE with exponential-backoff retry (2 s base, 60 s cap), filters by contract ID, classifies tip/withdraw/unknown events, records Prometheus metrics.
Closes Bonizozo#238
Bonizozo#228 — Event Sourcing Architecture
version: i32on everyEventvariant with#[serde(default)]for backward compat with stored events that predate versioning.0043:events.versioncolumn +event_snapshotstable (aggregate_id,sequence_number,snapshot_data JSONB).EventStore:appendstores version; newload_from,load_up_to;write_snapshotauto-fires every 50 events per aggregate;load_latest_snapshotreturns(seq, CreatorProjection).Replayer.creator_state: snapshot + delta replay — O(delta) not O(n).Replayer.creator_state_at: was broken (double load, ignored DB sequence numbers); now usesload_up_towith DB-sideWHERE sequence_number <= $2.CreatorProjection: addedSerialize/Deserializefor snapshot storage.EventStoreadded toAppState;CommandBusbuilt post-state-construction to avoid circular dependency, injected as axumExtension.Closes Bonizozo#228
What was tested
IF NOT EXISTS,ON CONFLICT DO NOTHING).events/types.rsandevents/projections.rscover serialization round-trips and projection correctness.