service backend
This commit is contained in:
25
api/ledger/storage/model/account.go
Normal file
25
api/ledger/storage/model/account.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/tech/sendico/pkg/db/storable"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
)
|
||||
|
||||
// Account represents a ledger account that holds balances for a specific currency.
|
||||
type Account struct {
|
||||
storable.Base `bson:",inline" json:",inline"`
|
||||
model.PermissionBound `bson:",inline" json:",inline"`
|
||||
|
||||
AccountCode string `bson:"accountCode" json:"accountCode"` // e.g., "asset:cash:usd"
|
||||
Currency string `bson:"currency" json:"currency"` // ISO 4217 currency code
|
||||
AccountType AccountType `bson:"accountType" json:"accountType"` // asset, liability, revenue, expense
|
||||
Status AccountStatus `bson:"status" json:"status"` // active, frozen, closed
|
||||
AllowNegative bool `bson:"allowNegative" json:"allowNegative"` // debit policy: allow negative balances
|
||||
IsSettlement bool `bson:"isSettlement,omitempty" json:"isSettlement,omitempty"` // marks org-level default contra account
|
||||
Metadata map[string]string `bson:"metadata,omitempty" json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// Collection implements storable.Storable.
|
||||
func (*Account) Collection() string {
|
||||
return AccountsCollection
|
||||
}
|
||||
27
api/ledger/storage/model/account_balance.go
Normal file
27
api/ledger/storage/model/account_balance.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/pkg/db/storable"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
// AccountBalance represents the current balance of a ledger account.
|
||||
// This is a materialized view updated atomically with journal entries.
|
||||
type AccountBalance struct {
|
||||
storable.Base `bson:",inline" json:",inline"`
|
||||
model.PermissionBound `bson:",inline" json:",inline"`
|
||||
|
||||
AccountRef primitive.ObjectID `bson:"accountRef" json:"accountRef"` // unique per account+currency
|
||||
Balance string `bson:"balance" json:"balance"` // stored as string for exact decimal
|
||||
Currency string `bson:"currency" json:"currency"` // ISO 4217 currency code
|
||||
Version int64 `bson:"version" json:"version"` // for optimistic locking
|
||||
LastUpdated time.Time `bson:"lastUpdated" json:"lastUpdated"` // timestamp of last balance update
|
||||
}
|
||||
|
||||
// Collection implements storable.Storable.
|
||||
func (*AccountBalance) Collection() string {
|
||||
return AccountBalancesCollection
|
||||
}
|
||||
26
api/ledger/storage/model/journal_entry.go
Normal file
26
api/ledger/storage/model/journal_entry.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/pkg/db/storable"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
)
|
||||
|
||||
// JournalEntry represents an atomic ledger transaction with multiple posting lines.
|
||||
type JournalEntry struct {
|
||||
storable.Base `bson:",inline" json:",inline"`
|
||||
model.PermissionBound `bson:",inline" json:",inline"`
|
||||
|
||||
IdempotencyKey string `bson:"idempotencyKey" json:"idempotencyKey"` // unique key for deduplication
|
||||
EventTime time.Time `bson:"eventTime" json:"eventTime"` // business event timestamp
|
||||
EntryType EntryType `bson:"entryType" json:"entryType"` // credit, debit, transfer, fx, fee, adjust, reverse
|
||||
Description string `bson:"description" json:"description"`
|
||||
Metadata map[string]string `bson:"metadata,omitempty" json:"metadata,omitempty"`
|
||||
Version int64 `bson:"version" json:"version"` // for ordering and optimistic locking
|
||||
}
|
||||
|
||||
// Collection implements storable.Storable.
|
||||
func (*JournalEntry) Collection() string {
|
||||
return JournalEntriesCollection
|
||||
}
|
||||
27
api/ledger/storage/model/outbox.go
Normal file
27
api/ledger/storage/model/outbox.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/pkg/db/storable"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
)
|
||||
|
||||
// OutboxEvent represents a pending event to be published to NATS.
|
||||
// Part of the transactional outbox pattern for reliable event delivery.
|
||||
type OutboxEvent struct {
|
||||
storable.Base `bson:",inline" json:",inline"`
|
||||
model.OrganizationBoundBase `bson:",inline" json:",inline"`
|
||||
|
||||
EventID string `bson:"eventId" json:"eventId"` // deterministic ID for NATS Msg-Id deduplication
|
||||
Subject string `bson:"subject" json:"subject"` // NATS subject to publish to
|
||||
Payload []byte `bson:"payload" json:"payload"` // JSON-encoded event data
|
||||
Status OutboxStatus `bson:"status" json:"status"` // pending, sent, failed
|
||||
Attempts int `bson:"attempts" json:"attempts"` // number of delivery attempts
|
||||
SentAt *time.Time `bson:"sentAt,omitempty" json:"sentAt,omitempty"`
|
||||
}
|
||||
|
||||
// Collection implements storable.Storable.
|
||||
func (*OutboxEvent) Collection() string {
|
||||
return OutboxCollection
|
||||
}
|
||||
24
api/ledger/storage/model/posting_line.go
Normal file
24
api/ledger/storage/model/posting_line.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/tech/sendico/pkg/db/storable"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
// PostingLine represents a single debit or credit line in a journal entry.
|
||||
type PostingLine struct {
|
||||
storable.Base `bson:",inline" json:",inline"`
|
||||
model.PermissionBound `bson:",inline" json:",inline"`
|
||||
|
||||
JournalEntryRef primitive.ObjectID `bson:"journalEntryRef" json:"journalEntryRef"`
|
||||
AccountRef primitive.ObjectID `bson:"accountRef" json:"accountRef"`
|
||||
Amount string `bson:"amount" json:"amount"` // stored as string for exact decimal, positive = credit, negative = debit
|
||||
Currency string `bson:"currency" json:"currency"` // ISO 4217 currency code
|
||||
LineType LineType `bson:"lineType" json:"lineType"` // main, fee, spread, reversal
|
||||
}
|
||||
|
||||
// Collection implements storable.Storable.
|
||||
func (*PostingLine) Collection() string {
|
||||
return PostingLinesCollection
|
||||
}
|
||||
78
api/ledger/storage/model/types.go
Normal file
78
api/ledger/storage/model/types.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package model
|
||||
|
||||
import "github.com/tech/sendico/pkg/model"
|
||||
|
||||
// Collection names used by the ledger persistence layer.
|
||||
const (
|
||||
AccountsCollection = "ledger_accounts"
|
||||
JournalEntriesCollection = "journal_entries"
|
||||
PostingLinesCollection = "posting_lines"
|
||||
AccountBalancesCollection = "account_balances"
|
||||
OutboxCollection = "outbox"
|
||||
)
|
||||
|
||||
// AccountType defines the category of account (asset, liability, revenue, expense).
|
||||
type AccountType string
|
||||
|
||||
const (
|
||||
AccountTypeAsset AccountType = "asset"
|
||||
AccountTypeLiability AccountType = "liability"
|
||||
AccountTypeRevenue AccountType = "revenue"
|
||||
AccountTypeExpense AccountType = "expense"
|
||||
)
|
||||
|
||||
// AccountStatus tracks the operational state of an account.
|
||||
type AccountStatus string
|
||||
|
||||
const (
|
||||
AccountStatusActive AccountStatus = "active"
|
||||
AccountStatusFrozen AccountStatus = "frozen"
|
||||
AccountStatusClosed AccountStatus = "closed"
|
||||
)
|
||||
|
||||
// EntryType categorizes journal entries by their business purpose.
|
||||
type EntryType string
|
||||
|
||||
const (
|
||||
EntryTypeCredit EntryType = "credit"
|
||||
EntryTypeDebit EntryType = "debit"
|
||||
EntryTypeTransfer EntryType = "transfer"
|
||||
EntryTypeFX EntryType = "fx"
|
||||
EntryTypeFee EntryType = "fee"
|
||||
EntryTypeAdjust EntryType = "adjust"
|
||||
EntryTypeReverse EntryType = "reverse"
|
||||
)
|
||||
|
||||
// LineType distinguishes the role of a posting line within a journal entry.
|
||||
type LineType string
|
||||
|
||||
const (
|
||||
LineTypeMain LineType = "main"
|
||||
LineTypeFee LineType = "fee"
|
||||
LineTypeSpread LineType = "spread"
|
||||
LineTypeReversal LineType = "reversal"
|
||||
)
|
||||
|
||||
// OutboxStatus tracks the delivery state of an outbox event.
|
||||
type OutboxStatus string
|
||||
|
||||
const (
|
||||
OutboxStatusPending OutboxStatus = "pending"
|
||||
OutboxStatusSent OutboxStatus = "sent"
|
||||
OutboxStatusFailed OutboxStatus = "failed"
|
||||
)
|
||||
|
||||
// Money represents an exact decimal amount with its currency.
|
||||
type Money struct {
|
||||
Currency string `bson:"currency" json:"currency"`
|
||||
Amount string `bson:"amount" json:"amount"` // stored as string for exact decimal representation
|
||||
}
|
||||
|
||||
// LedgerMeta carries organization-scoped metadata for ledger entities.
|
||||
type LedgerMeta struct {
|
||||
model.OrganizationBoundBase `bson:",inline" json:",inline"`
|
||||
|
||||
RequestRef string `bson:"requestRef,omitempty" json:"requestRef,omitempty"`
|
||||
TraceRef string `bson:"traceRef,omitempty" json:"traceRef,omitempty"`
|
||||
IdempotencyKey string `bson:"idempotencyKey,omitempty" json:"idempotencyKey,omitempty"`
|
||||
}
|
||||
Reference in New Issue
Block a user