package storage import ( "context" "time" "github.com/tech/sendico/pkg/db" "github.com/tech/sendico/pkg/mlogger" "go.mongodb.org/mongo-driver/v2/bson" ) // TaskStatus tracks delivery task lifecycle. type TaskStatus string const ( TaskStatusPending TaskStatus = "PENDING" TaskStatusRetry TaskStatus = "RETRY" TaskStatusDelivered TaskStatus = "DELIVERED" TaskStatusFailed TaskStatus = "FAILED" ) // Endpoint describes one target callback endpoint. type Endpoint struct { ID bson.ObjectID ClientID string URL string SigningMode string SecretRef string Headers map[string]string MaxAttempts int MinDelay time.Duration MaxDelay time.Duration RequestTimeout time.Duration } // Task is one callback delivery job. type Task struct { ID bson.ObjectID EventID string EndpointID bson.ObjectID EndpointURL string SigningMode string SecretRef string Headers map[string]string Payload []byte Attempt int MaxAttempts int MinDelay time.Duration MaxDelay time.Duration RequestTimeout time.Duration Status TaskStatus NextAttemptAt time.Time } // TaskDefaults are applied when creating tasks. type TaskDefaults struct { MaxAttempts int MinDelay time.Duration MaxDelay time.Duration RequestTimeout time.Duration } // Options configures mongo collections. type Options struct { InboxCollection string TasksCollection string EndpointsCollection string } // InboxRepo controls event dedupe state. type InboxRepo interface { TryInsert(ctx context.Context, eventID, clientID, eventType string, at time.Time) (bool, error) } // EndpointRepo resolves endpoints for events. type EndpointRepo interface { FindActiveByClientAndType(ctx context.Context, clientID, eventType string) ([]Endpoint, error) } // TaskRepo manages callback tasks. type TaskRepo interface { UpsertTasks(ctx context.Context, eventID string, endpoints []Endpoint, payload []byte, defaults TaskDefaults, at time.Time) error LockNextTask(ctx context.Context, now time.Time, workerID string, lockTTL time.Duration) (*Task, error) MarkDelivered(ctx context.Context, taskID bson.ObjectID, httpCode int, latency time.Duration, at time.Time) error MarkRetry(ctx context.Context, taskID bson.ObjectID, attempt int, nextAttemptAt time.Time, lastError string, httpCode int, at time.Time) error MarkFailed(ctx context.Context, taskID bson.ObjectID, attempt int, lastError string, httpCode int, at time.Time) error } // Repository is the callbacks persistence contract. type Repository interface { Inbox() InboxRepo Endpoints() EndpointRepo Tasks() TaskRepo } // New creates a Mongo-backed callbacks repository. func New(logger mlogger.Logger, conn *db.MongoConnection) (Repository, error) { return newMongoRepository(logger, conn) }