Collections Module Architecture
This document outlines the architectural design of the collections module, which handles subscription payment processing across multiple collection workflows.
Overview
The collections module implements a modular architecture that separates concerns between different collection types while maintaining shared core functionality.
Architecture Principles
Core Components
Base Collector
The foundational component that provides shared dependencies and common collection operations.
Responsibilities
-
Managing dependencies (users, payments, subscriptions, notifications)
-
Providing controlled access to sensitive operations
-
Implementing core collection logic
-
Handling payment submissions and receipt generation
Interface Contract
type BaseCollectorIface interface {
attemptCollection(ctx context.Context, state *collectionState) error
getGBClient() growthbook.API
getLockClient() dynamo.Locker
getPaymentsAPI() payments.API
getUsersAPI() users.API
getSubRepo() subscriptions.Repository
getSubHistoryRepo() history.Repository
}
Specialized Collectors
Purpose-built collectors that handle specific collection scenarios by composing base functionality.
Webhook Balance Collector
Processes subscription collections triggered by account balance updates via webhooks.
Key Features: * Real-time balance monitoring * Multiple subscription handling * Feature flag integration
Design Pattern
type WebhookBalanceCollector struct {
base BaseCollectorIface
}
func (c *WebhookBalanceCollector) CollectWebhookBalance(
ctx context.Context,
userID string,
accountUpdate *txnModels.Account,
) error {
// Specialized logic for webhook processing
return c.base.attemptCollection(ctx, state)
}
Data Flow
-
Input Processing: Specialized collectors receive external events
-
State Preparation: Collection state is assembled from user data and subscriptions
-
Validation: Business rules and feature flags are evaluated
-
Collection Attempt: Base collector executes payment and record updates
-
Notification: Success receipts are sent to users
Extension Patterns
Adding New Collector Types
-
Implement specialized collector struct
-
Compose
BaseCollectorIfacefor shared functionality -
Add business logic specific to collection scenario
-
Register with appropriate worker/handler
Example: Batch Collector
type BatchCollector struct {
base BaseCollectorIface
}
func NewBatchCollector(base BaseCollectorIface) *BatchCollector {
return &BatchCollector{base: base}
}
func (b *BatchCollector) ProcessBatch(ctx context.Context, userIDs []string) error {
for _, userID := range userIDs {
// Batch-specific logic
err := b.base.attemptCollection(ctx, state)
// Handle batch processing concerns
}
}