data

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 1, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotFound indicates the requested resource does not exist.
	ErrNotFound = errors.New("resource not found")

	// ErrConflict indicates the operation conflicts with existing state.
	ErrConflict = errors.New("resource conflict")

	// ErrForbidden indicates the caller lacks permission for the operation.
	ErrForbidden = errors.New("forbidden: insufficient permissions")

	// ErrInternal indicates an unexpected internal failure.
	ErrInternal = errors.New("internal error")

	// ErrNoProcurementPrice is returned when COGS cannot be computed because
	// one or more ingredients have no procurement price on record.
	ErrNoProcurementPrice = errors.New("no procurement price on record")

	// ErrInsufficientStock is returned when available units cannot be computed
	// because one or more ingredients have no stock record yet.
	ErrInsufficientStock = errors.New("insufficient stock")

	// ErrInvalidProductType is returned when an operation is attempted on a
	// product of the wrong type (e.g. setting a recipe on a simple product).
	ErrInvalidProductType = errors.New("invalid product type for operation")

	// ErrUnitCostRequired is returned when a stock movement of type procurement
	// or opening_balance is recorded without a unit_cost.
	ErrUnitCostRequired = errors.New("unit_cost is required for this movement reason")

	// ErrUnitCostForbidden is returned when a unit_cost is supplied for a stock
	// movement type that does not accept one (waste, adjustment_up, adjustment_down).
	ErrUnitCostForbidden = errors.New("unit_cost must not be set for this movement reason")

	// ErrInitialStockIncomplete is returned when a product is created with
	// only one of initial quantity / initial unit cost set — both or neither
	// are required, since together they form one procurement movement.
	ErrInitialStockIncomplete = errors.New(
		"initial quantity and initial unit cost must both be set, or neither",
	)

	// ErrStationBusy is returned when a session is opened on a station that
	// already has an open session.
	ErrStationBusy = errors.New("station already has an open session")

	// ErrSessionAlreadyClosed is returned when a close is attempted on a session
	// that is already in the closed state.
	ErrSessionAlreadyClosed = errors.New("session is already closed")

	// ErrOpenOrdersExist is returned when a close is attempted on a session that
	// still has orders in open status.
	ErrOpenOrdersExist = errors.New("session has open orders and cannot be closed")

	// ErrPaymentMismatch is returned when the sum of payment amounts does not
	// equal the order total.
	ErrPaymentMismatch = errors.New("payment total does not match order total")

	// ErrInvalidPaymentMethod is returned when a payment method is not in the
	// configured allowed set.
	ErrInvalidPaymentMethod = errors.New("payment method is not accepted")

	// ErrOrderNotPaid is returned when an operation that requires a paid order
	// (void, return) is attempted on an order in another state.
	ErrOrderNotPaid = errors.New("order is not in paid status")

	// ErrOrderNotOpen is returned when an operation that requires an open order
	// (add item, checkout) is attempted on an order in another state, or when
	// an order is created on a closed session.
	ErrOrderNotOpen = errors.New("order is not in open status")

	// ErrOrderAlreadyVoided is returned when a void is attempted on an order
	// that is already voided.
	ErrOrderAlreadyVoided = errors.New("order is already voided")

	// ErrUnbalancedEntry is returned when a journal entry's debit total does not
	// equal its credit total (violates double-entry bookkeeping).
	ErrUnbalancedEntry = errors.New(
		"journal entry is unbalanced: debit total must equal credit total",
	)

	// ErrDiscountExceedsTotal is returned when the computed discount amount equals
	// or exceeds the order item subtotal or order total it is being applied to.
	ErrDiscountExceedsTotal = errors.New("discount amount exceeds order total")

	// ErrInvalidIntent is returned when an upload is attempted against an
	// intent that isn't in the registered UploadIntent set.
	ErrInvalidIntent = errors.New("invalid upload intent")

	// ErrUnsupportedMimeType is returned when an uploaded file's declared or
	// sniffed content type isn't allowed for the requested intent.
	ErrUnsupportedMimeType = errors.New("unsupported file type for this upload intent")

	// ErrFileTooLarge is returned when an uploaded file exceeds the requested
	// intent's configured size limit.
	ErrFileTooLarge = errors.New("file exceeds the maximum size for this upload intent")
)

Functions

func IsValidUploadIntent

func IsValidUploadIntent(intent string) bool

IsValidUploadIntent reports whether intent is a registered upload intent.

Types

type AccountingRepoer

type AccountingRepoer interface {
	// GetAccountByCode returns the account with the given COA code.
	GetAccountByCode(ctx context.Context, code string) (*model.Account, error)

	// ListAccounts returns all accounts ordered by code.
	ListAccounts(ctx context.Context) ([]model.Account, error)

	// CreateJournalEntry persists a JournalEntry together with all its JournalLines
	// in a single atomic operation. The entry's ID and each line's ID are set before
	// insertion; entry.CreatedAt is set to the current UTC time.
	CreateJournalEntry(ctx context.Context, entry *model.JournalEntry) error

	// ListJournalEntriesByCompany returns a paginated list of journal entries.
	// Lines are NOT hydrated — call ListJournalLinesByEntry separately.
	ListJournalEntriesByCompany(
		ctx context.Context,
		companyID uuid.UUID,
		q SupportsPagination,
	) (*dto.PaginationResults[model.JournalEntry], error)

	// BalanceByAccount returns the sum of debits and credits per COA account
	// for all journal entries that belong to companyID.
	BalanceByAccount(ctx context.Context, companyID uuid.UUID) ([]model.AccountBalance, error)
}

AccountingRepoer persists chart-of-accounts data and double-entry journal entries.

type BranchRepoer

type BranchRepoer interface {
	GetByID(ctx context.Context, id uuid.UUID) (*model.Branch, error)
	ListByCompany(
		ctx context.Context,
		companyID uuid.UUID,
		q SupportsPagination,
	) (*dto.PaginationResults[model.Branch], error)
	Create(ctx context.Context, entity *model.Branch) error
	Update(ctx context.Context, entity *model.Branch) error
	Delete(ctx context.Context, id uuid.UUID) error
	WithTx(ctx context.Context, fn func(BranchRepoer) error) error
}

BranchRepoer defines the persistence contract for branch records.

type CompanyRepoer

type CompanyRepoer interface {
	GetByID(ctx context.Context, id uuid.UUID) (*model.Company, error)
	GetByHandle(ctx context.Context, handle string) (*model.Company, error)
	ListByOwner(
		ctx context.Context,
		ownerID uuid.UUID,
		q SupportsPagination,
	) (*dto.PaginationResults[model.Company], error)
	Create(ctx context.Context, entity *model.Company) error
	Update(ctx context.Context, entity *model.Company) error
	Delete(ctx context.Context, id uuid.UUID) error
	WithTx(ctx context.Context, fn func(CompanyRepoer) error) error
}

CompanyRepoer defines the persistence contract for company records. List is scoped by owner_id because a user may own multiple companies (pro).

type Crudable

type Crudable[T any] interface {
	GetByID(ctx context.Context, id uuid.UUID) (*T, error)
	Paginate(ctx context.Context, q SupportsPagination) (*dto.PaginationResults[T], error)
	Create(ctx context.Context, entity *T) error
	Update(ctx context.Context, entity *T) error
	Delete(ctx context.Context, id uuid.UUID) error
}

Crudable is a generic interface for repositories that support standard CRUD operations.

type CrudableWithTx

type CrudableWithTx[T any, R any] interface {
	Crudable[T]
	TxAware[R]
}

CrudableWithTx combines Crudable with transaction support. T is the entity type; R is the repo type passed inside the transaction.

type CustomerRepoer

type CustomerRepoer interface {
	GetByID(ctx context.Context, id uuid.UUID) (*model.Customer, error)
	ListByCompany(
		ctx context.Context,
		companyID uuid.UUID,
		search string,
		q SupportsPagination,
	) (*dto.PaginationResults[model.Customer], error)
	Create(ctx context.Context, entity *model.Customer) error
	Update(ctx context.Context, entity *model.Customer) error
	Delete(ctx context.Context, id uuid.UUID) error
	WithTx(ctx context.Context, fn func(CustomerRepoer) error) error
}

CustomerRepoer defines the persistence contract for customer records.

type DiscountRepoer

type DiscountRepoer interface {
	Create(ctx context.Context, entity *model.Discount) error
	GetByID(ctx context.Context, id uuid.UUID) (*model.Discount, error)
	ListByCompany(
		ctx context.Context,
		companyID uuid.UUID,
		search string,
		q SupportsPagination,
	) (*dto.PaginationResults[model.Discount], error)
	Update(ctx context.Context, entity *model.Discount) error
	Delete(ctx context.Context, id uuid.UUID) error
}

DiscountRepoer provides CRUD access to the named discount catalog.

type Enqueuer

type Enqueuer interface {
	// Send enqueues a named job with a JSON payload. Non-transactional.
	Send(ctx context.Context, name string, payload []byte) error
	// SendTx is like Send but within an existing *sql.Tx — atomic with the caller's write.
	SendTx(ctx context.Context, tx *sql.Tx, name string, payload []byte) error
}

Enqueuer enqueues named background jobs. The OSS implementation wraps goqite (SQLite-backed). Pro injects its own via core.WithEnqueuer — e.g. River for PostgreSQL.

type Event

type Event struct {
	Name    string
	Payload map[string]any
}

Event is a domain event payload.

type EventEmitter

type EventEmitter interface {
	Emit(ctx context.Context, event Event) error
}

EventEmitter dispatches domain events to subscribers. Implemented by the job queue in Phase 7; nil until then.

type ExpenseRepoer

type ExpenseRepoer interface {
	Create(ctx context.Context, entity *model.Expense) error
	GetByID(ctx context.Context, id uuid.UUID) (*model.Expense, error)
	ListByCompany(
		ctx context.Context,
		companyID uuid.UUID,
		search string,
		q SupportsPagination,
	) (*dto.PaginationResults[model.Expense], error)
}

ExpenseRepoer defines the persistence contract for expense records.

type FileRepoer

type FileRepoer interface {
	Create(ctx context.Context, entity *model.File) error
	GetByID(ctx context.Context, id, companyID uuid.UUID) (*model.File, error)
	Delete(ctx context.Context, id, companyID uuid.UUID) error
}

FileRepoer provides CRUD access to uploaded file metadata.

type FileStorage

type FileStorage interface {
	Put(ctx context.Context, key string, r io.Reader, size int64) error
	Get(ctx context.Context, key string) (io.ReadCloser, error)
	Delete(ctx context.Context, key string) error
}

FileStorage stores and retrieves file bytes by key. Implementations never see or need an absolute path — the key is relative to the backend's root (e.g. a bucket, or a base directory on disk).

type IntentConfig

type IntentConfig struct {
	// Prefix is prepended to the generated filename to form the storage key,
	// e.g. "avatars/" -> "<companyID>/avatars/<uuid>.webp".
	Prefix           string
	AllowedMIMETypes []string
	MaxSizeBytes     int64
	URLExpiry        time.Duration
}

IntentConfig is the validation/config for one UploadIntent.

func LookupIntent

func LookupIntent(intent UploadIntent) (IntentConfig, bool)

LookupIntent returns the config for a given intent, and whether it exists.

type InventoryQuerier

type InventoryQuerier interface {
	// LPP returns the Last Procurement Price for the given product (ingredient).
	// Returns ErrNoProcurementPrice if no procurement stock movement exists yet.
	LPP(ctx context.Context, productID uuid.UUID) (int64, error)

	// CurrentStock returns the current stock level (in product units) for the
	// given ingredient product.
	// Returns ErrInsufficientStock if no stock record exists yet.
	CurrentStock(ctx context.Context, productID uuid.UUID) (float64, error)

	// StockAt returns the stock level at the given point in time.
	StockAt(ctx context.Context, productID uuid.UUID, at time.Time) (float64, error)
}

InventoryQuerier provides read-only inventory queries used by ProductService. Implemented by InventoryRepo in Phase 4; may be nil in Phase 3.

type InventoryRepoer

type InventoryRepoer interface {
	Record(ctx context.Context, entity *model.StockMovement) error
	GetByID(ctx context.Context, id uuid.UUID) (*model.StockMovement, error)
	ListByCompany(
		ctx context.Context,
		companyID uuid.UUID,
		q SupportsPagination,
	) (*dto.PaginationResults[model.StockMovement], error)
	// ListByProduct returns paginated movements for productID, scoped to
	// companyID so a caller cannot read another company's product history.
	ListByProduct(
		ctx context.Context,
		productID, companyID uuid.UUID,
		q SupportsPagination,
	) (*dto.PaginationResults[model.StockMovement], error)
	// CurrentStock returns the signed sum of all deltas for the product.
	// Returns 0 when no movements exist (never ErrInsufficientStock at repo level).
	CurrentStock(ctx context.Context, productID uuid.UUID) (float64, error)
	StockAt(ctx context.Context, productID uuid.UUID, at time.Time) (float64, error)
	// LPP returns the unit_cost of the most recent procurement movement.
	// Returns ErrNoProcurementPrice when no procurement exists.
	LPP(ctx context.Context, productID uuid.UUID) (int64, error)
	// HasMovements reports whether any stock movement exists for the product.
	HasMovements(ctx context.Context, productID uuid.UUID) (bool, error)
	WithTx(ctx context.Context, fn func(InventoryRepoer) error) error
}

InventoryRepoer defines the persistence contract for stock movements. It also satisfies InventoryQuerier (LPP + CurrentStock are present on both).

type OrderFilter

type OrderFilter struct {
	DateFrom  string    // "YYYY-MM-DD" inclusive; "" = no lower bound
	DateTo    string    // "YYYY-MM-DD" inclusive; "" = no upper bound
	Status    string    // model.OrderStatus value; "" = any status
	BranchID  uuid.UUID // uuid.Nil = any branch
	StationID uuid.UUID // uuid.Nil = any station
}

OrderFilter holds optional filter criteria for ListOrdersByCompanyFiltered. Zero values mean "no filter" for that field.

type OrderRepoer

type OrderRepoer interface {
	// CreateOrder persists a new open order. Sets ID, CreatedAt, UpdatedAt.
	CreateOrder(ctx context.Context, entity *model.Order) error

	// GetOrderByID retrieves an order by its ID.
	GetOrderByID(ctx context.Context, id uuid.UUID) (*model.Order, error)

	// UpdateOrder persists mutable order fields (status, total, receipt_number,
	// voided_by, voided_at, updated_at).
	UpdateOrder(ctx context.Context, entity *model.Order) error

	// DeleteOrder removes an order record entirely.
	DeleteOrder(ctx context.Context, id uuid.UUID) error

	// ListOrdersBySession returns paginated orders for a session.
	ListOrdersBySession(
		ctx context.Context,
		sessionID uuid.UUID,
		q SupportsPagination,
	) (*dto.PaginationResults[model.Order], error)

	// ListOrdersByCompany returns paginated orders for a company.
	ListOrdersByCompany(
		ctx context.Context,
		companyID uuid.UUID,
		q SupportsPagination,
	) (*dto.PaginationResults[model.Order], error)

	// ListOrdersByCompanyFiltered returns paginated orders for a company,
	// narrowed by filter. Zero-value fields on filter impose no restriction.
	ListOrdersByCompanyFiltered(
		ctx context.Context,
		companyID uuid.UUID,
		filter *OrderFilter,
		q SupportsPagination,
	) (*dto.PaginationResults[model.Order], error)

	// CountOrdersByCompanyAndDate returns the number of orders created by the
	// company on the given date (format "YYYY-MM-DD"). Used for receipt numbering.
	CountOrdersByCompanyAndDate(
		ctx context.Context,
		companyID uuid.UUID,
		date string,
	) (int64, error)

	// CreateOrderItem persists a new order item. Sets ID.
	CreateOrderItem(ctx context.Context, entity *model.OrderItem) error

	// GetOrderItemByID retrieves an order item by its ID.
	GetOrderItemByID(ctx context.Context, id uuid.UUID) (*model.OrderItem, error)

	// ListOrderItemsByOrder returns all items for an order.
	ListOrderItemsByOrder(ctx context.Context, orderID uuid.UUID) ([]model.OrderItem, error)

	// DeleteOrderItem removes an order item.
	DeleteOrderItem(ctx context.Context, id uuid.UUID) error

	// UpdateOrderItem updates the quantity and subtotal of an existing order item.
	UpdateOrderItem(ctx context.Context, entity *model.OrderItem) error

	// CreatePayment persists a payment leg. Sets ID.
	CreatePayment(ctx context.Context, entity *model.Payment) error

	// ListPaymentsByOrder returns all payment legs for an order.
	ListPaymentsByOrder(ctx context.Context, orderID uuid.UUID) ([]model.Payment, error)

	// SumPaymentsByOrder returns the total of completed payments for an order.
	SumPaymentsByOrder(ctx context.Context, orderID uuid.UUID) (int64, error)

	// CreateOrderReturn persists a return record. Sets ID.
	CreateOrderReturn(ctx context.Context, entity *model.OrderReturn) error

	// GetOrderReturnByID retrieves a return by its ID.
	GetOrderReturnByID(ctx context.Context, id uuid.UUID) (*model.OrderReturn, error)

	// ListOrderReturnsByOrder returns all return records for an order.
	ListOrderReturnsByOrder(ctx context.Context, orderID uuid.UUID) ([]model.OrderReturn, error)

	// CreateOrderReturnItem persists a return item line. Sets ID.
	CreateOrderReturnItem(ctx context.Context, entity *model.OrderReturnItem) error

	// ListOrderReturnItemsByReturn returns all item lines for a return.
	ListOrderReturnItemsByReturn(
		ctx context.Context,
		returnID uuid.UUID,
	) ([]model.OrderReturnItem, error)

	// WithTx runs fn inside a single database transaction, providing transactional
	// views of both the order repo and the inventory repo. Used for Checkout, Void,
	// and Return which must write to orders/payments and stock_movements atomically.
	WithTx(ctx context.Context, fn func(orders OrderRepoer, inv InventoryRepoer) error) error
}

OrderRepoer defines persistence operations for orders, items, payments, and returns.

type POSStationRepoer

type POSStationRepoer interface {
	GetByID(ctx context.Context, id uuid.UUID) (*model.POSStation, error)
	ListByCompany(
		ctx context.Context,
		companyID uuid.UUID,
		q SupportsPagination,
	) (*dto.PaginationResults[model.POSStation], error)
	Create(ctx context.Context, entity *model.POSStation) error
	Update(ctx context.Context, entity *model.POSStation) error
	Delete(ctx context.Context, id uuid.UUID) error
	WithTx(ctx context.Context, fn func(POSStationRepoer) error) error
}

POSStationRepoer defines the persistence contract for POS station records.

type ProductRepoer

type ProductRepoer interface {
	GetByID(ctx context.Context, id uuid.UUID) (*model.Product, error)
	// GetBySKU retrieves a product by its SKU, scoped to companyID. Used by
	// the POS barcode-scan-to-cart flow.
	GetBySKU(ctx context.Context, companyID uuid.UUID, sku string) (*model.Product, error)
	ListByCompany(
		ctx context.Context,
		companyID uuid.UUID,
		search string,
		q SupportsPagination,
	) (*dto.PaginationResults[model.Product], error)
	ListByCompanyAndType(
		ctx context.Context,
		companyID uuid.UUID,
		t model.ProductType,
		search string,
		q SupportsPagination,
	) (*dto.PaginationResults[model.Product], error)
	// ListSellableByCompany returns paginated Simple+Recipe products (the
	// types the POS product grid can add to a cart) as one correctly-ordered
	// and counted set, rather than merging two independently-paginated lists.
	ListSellableByCompany(
		ctx context.Context,
		companyID uuid.UUID,
		search string,
		q SupportsPagination,
	) (*dto.PaginationResults[model.Product], error)
	Create(ctx context.Context, entity *model.Product) error
	Update(ctx context.Context, entity *model.Product) error
	Delete(ctx context.Context, id uuid.UUID) error
	GetRecipeComponents(ctx context.Context, recipeID uuid.UUID) ([]model.RecipeComponent, error)
	SetRecipeComponents(
		ctx context.Context,
		recipeID uuid.UUID,
		components []model.RecipeComponent,
	) error
	GetRecipeOverheads(ctx context.Context, recipeID uuid.UUID) ([]model.RecipeOverhead, error)
	SetRecipeOverheads(
		ctx context.Context,
		recipeID uuid.UUID,
		overheads []model.RecipeOverhead,
	) error
	// WithTx runs fn inside a single database transaction, providing both
	// repos so a product write and a stock movement (e.g. initial stock at
	// creation) can commit atomically — mirrors OrderRepoer.WithTx.
	WithTx(ctx context.Context, fn func(products ProductRepoer, inv InventoryRepoer) error) error
}

ProductRepoer defines the persistence contract for product records, including recipe sub-entities (components and overheads).

type ReportsQuerier

type ReportsQuerier interface {
	SalesTotals(
		ctx context.Context,
		companyID uuid.UUID,
		from, to string,
	) (model.SalesSummary, error)

	SalesByPeriod(
		ctx context.Context,
		companyID uuid.UUID,
		from, to, groupBy string,
	) ([]model.SalesPeriod, error)

	RevenueByPaymentMethod(
		ctx context.Context,
		companyID uuid.UUID,
		from, to string,
	) ([]model.PaymentMethodRevenue, error)

	TopProductsByRevenue(
		ctx context.Context,
		companyID uuid.UUID,
		from, to string,
		topN int,
	) ([]model.TopProduct, error)

	InventorySnapshot(
		ctx context.Context,
		companyID uuid.UUID,
	) ([]model.InventoryLine, error)

	// InventorySnapshotPaged is the paginated, searchable counterpart to
	// InventorySnapshot, used by the web Inventory list page.
	InventorySnapshotPaged(
		ctx context.Context,
		companyID uuid.UUID,
		search string,
		q SupportsPagination,
	) (*dto.PaginationResults[model.InventoryLine], error)

	PLByPeriod(
		ctx context.Context,
		companyID uuid.UUID,
		from, to string,
	) (model.PLSummary, error)
}

ReportsQuerier provides read-only aggregate queries for management reports. All implementations use raw SQL; no sqlc involvement.

type SessionFilter

type SessionFilter struct {
	BranchID uuid.UUID
}

SessionFilter narrows ListOpenByCompanyFiltered. uuid.Nil means "any branch".

type SessionRepoer

type SessionRepoer interface {
	// Create persists a new open session.
	Create(ctx context.Context, entity *model.POSSession) error
	// GetByID retrieves a session by its ID.
	GetByID(ctx context.Context, id uuid.UUID) (*model.POSSession, error)
	// GetOpenByStation retrieves the open session for a station, if any.
	// Returns ErrNotFound if no open session exists.
	GetOpenByStation(ctx context.Context, stationID uuid.UUID) (*model.POSSession, error)
	// GetOpenByUser retrieves the open session opened by userID within
	// companyID, if any. Returns ErrNotFound if no open session exists.
	GetOpenByUser(ctx context.Context, companyID, userID uuid.UUID) (*model.POSSession, error)
	// Close marks a session as closed at the given time.
	Close(ctx context.Context, sessionID uuid.UUID, closedAt time.Time) error
	// ListByCompany returns paginated sessions for a company.
	ListByCompany(
		ctx context.Context,
		companyID uuid.UUID,
		q SupportsPagination,
	) (*dto.PaginationResults[model.POSSession], error)
	// ListOpenByCompanyFiltered returns paginated open sessions for a
	// company, optionally narrowed by filter.BranchID.
	ListOpenByCompanyFiltered(
		ctx context.Context,
		companyID uuid.UUID,
		filter *SessionFilter,
		q SupportsPagination,
	) (*dto.PaginationResults[model.POSSession], error)
	// CreateReconciliation persists a session reconciliation record.
	CreateReconciliation(ctx context.Context, entity *model.SessionReconciliation) error
	// GetReconciliationBySession retrieves the reconciliation for a session.
	GetReconciliationBySession(
		ctx context.Context,
		sessionID uuid.UUID,
	) (*model.SessionReconciliation, error)
	// SumCashPayments returns the total cash-method payments taken in a session.
	// Phase 6 stub: always returns 0 until the payments table exists.
	SumCashPayments(ctx context.Context, sessionID uuid.UUID) (int64, error)
	// HasOpenOrders returns true if the session has any orders in open status.
	// Phase 6 stub: always returns false until the orders table exists.
	HasOpenOrders(ctx context.Context, sessionID uuid.UUID) (bool, error)
	// DeleteOpenOrders hard-deletes every open order for the session
	// (cascading to their items via FK) and returns the number deleted.
	DeleteOpenOrders(ctx context.Context, sessionID uuid.UUID) (int64, error)
}

SessionRepoer defines persistence operations for POS sessions and reconciliations.

type SupplierPaymentRepoer

type SupplierPaymentRepoer interface {
	Create(ctx context.Context, entity *model.SupplierPayment) error
	GetByID(ctx context.Context, id uuid.UUID) (*model.SupplierPayment, error)
	ListByCompany(
		ctx context.Context,
		companyID uuid.UUID,
		q SupportsPagination,
	) (*dto.PaginationResults[model.SupplierPayment], error)
	ListBySupplier(
		ctx context.Context,
		supplierID uuid.UUID,
		q SupportsPagination,
	) (*dto.PaginationResults[model.SupplierPayment], error)
}

SupplierPaymentRepoer defines the persistence contract for supplier payment records.

type SupplierRepoer

type SupplierRepoer interface {
	GetByID(ctx context.Context, id uuid.UUID) (*model.Supplier, error)
	ListByCompany(
		ctx context.Context,
		companyID uuid.UUID,
		search string,
		q SupportsPagination,
	) (*dto.PaginationResults[model.Supplier], error)
	Create(ctx context.Context, entity *model.Supplier) error
	Update(ctx context.Context, entity *model.Supplier) error
	Delete(ctx context.Context, id uuid.UUID) error
	WithTx(ctx context.Context, fn func(SupplierRepoer) error) error
}

SupplierRepoer defines the persistence contract for supplier records.

type SupportsPagination

type SupportsPagination interface {
	Limit() int32
	Offset() int32
}

SupportsPagination is satisfied by any DTO that can describe a page of results.

type TxAware

type TxAware[T any] interface {
	// WithTx executes fn within a database transaction.
	// If fn returns an error the transaction is rolled back; otherwise it is committed.
	WithTx(ctx context.Context, fn func(T) error) error
}

TxAware is a generic interface for repositories that support transactions. T is the repo type passed to the transaction function.

type URLPresigner

type URLPresigner interface {
	PresignGET(ctx context.Context, key string, ttl time.Duration) (string, error)
}

URLPresigner is an optional capability of a FileStorage backend that can mint a time-limited, direct-to-backend download URL (e.g. S3's presigned GET). Backends without a native presign mechanism, like the local filesystem driver, don't implement this — callers type-assert for it and fall back to another download strategy when absent.

type UploadIntent

type UploadIntent string

UploadIntent is a predefined, validated purpose for an uploaded file. It determines the storage key prefix and the upload constraints (allowed MIME types, max size, presigned URL lifetime).

const (
	// IntentAvatar is a user's profile picture.
	IntentAvatar UploadIntent = "avatar"

	IntentCompanyLogo UploadIntent = "company_logo"

	// IntentProductImage is a product's photo, shown on its edit form and
	// in the POS product grid.
	IntentProductImage UploadIntent = "product_image"
)

type UserRepoer

type UserRepoer interface {
	CrudableWithTx[model.User, UserRepoer]
	GetByEmail(ctx context.Context, email string) (*model.User, error)
	CountByCompany(ctx context.Context, companyID uuid.UUID) (int64, error)
	ListByCompany(
		ctx context.Context,
		companyID uuid.UUID,
		q SupportsPagination,
	) (*dto.PaginationResults[model.User], error)
	// InvalidateTokens sets the user's token_valid_after cutoff to now,
	// rejecting any JWT issued before this call (see model.User.TokenValidAfter).
	InvalidateTokens(ctx context.Context, userID uuid.UUID) error
}

UserRepoer defines the interface for interacting with user data storage. Implementations include a SQLite repo (OSS), a pgx/Postgres repo (Pro), and test stubs/mocks in the stubrepo and mockrepo packages.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL