backbone_pos/integration.rs
1//! Stable integration surface for composing services.
2//!
3//! This module is the **deliberate, published API** a consumer depends on. It re-exports exactly
4//! the types and functions a composing service (e.g. `serpa-posman-service`) needs to mount POS,
5//! implement the outbound ports, and drive recognition — gathered under one namespace so that the
6//! crate's internal DDD layer tree (`application::service::...`, `presentation::http::...`) is free
7//! to move on regeneration without breaking consumers.
8//!
9//! **Consumers should depend only on `backbone_pos::integration::{...}`.** The deep paths are
10//! internal; reaching into them couples you to the layer structure (council 2026-07-26, Contract
11//! Seat — `docs/council/2026-07-26-module-backbone-pos-maturity.md`).
12//!
13//! ## Stability promise
14//! - **Additive** changes (new re-exports, new items) are non-breaking.
15//! - **Removals or renames** of items already exported here require a semver bump.
16//! - The internals behind these aliases are NOT promised stable — they may change anytime.
17//!
18//! ## What a consumer wires
19//! ```ignore
20//! use backbone_pos::integration::*;
21//!
22//! let pos = PosModule::builder().with_database(pool.clone()).build()?;
23//! // implement the outbound ports over your real tax/billing/payment/inventory
24//! let tax: Arc<dyn PosTaxComputePort> = /* your adapter over the tax module */;
25//! let billing: Arc<dyn BillingPort> = /* your adapter */;
26//! let payment: Arc<dyn PaymentPort> = /* your adapter */;
27//! let variance: Arc<dyn PosCashVariancePort> = /* your adapter over accounting */;
28//! let inventory: Option<Arc<dyn InventoryPort>> = /* your adapter */;
29//! // subscribe to tenders → drive recognition exactly once
30//! let sink = RecognitionSink::new(pool.clone(), billing, payment, inventory);
31//! // mount the guarded surface — bare of auth; wrap it in YOUR org scope middleware
32//! // (org_auth + the tenant router) so the request-dedicated connection fences it
33//! let router = create_guarded_pos_routes_with_outbox(
34//! &pos, pool, sink, tax, variance, billing, payment, schema,
35//! );
36//! ```
37
38// --- The module + builder -----------------------------------------------------
39pub use crate::PosModule;
40pub use crate::PosModuleBuilder;
41
42// --- Guarded HTTP surface (route composers) -----------------------------------
43// Read + validated writes; the production surface. NO generic CRUD (that's `PosModule::all_crud_routes`).
44pub use crate::presentation::http::{
45 create_guarded_pos_routes, create_guarded_pos_routes_with_outbox,
46 create_guarded_pos_priced_route, create_guarded_pos_priced_route_with_outbox,
47};
48
49// --- Tenant / company auth re-exports -------------------------------------------
50// The guarded surface itself ships bare and reads `OrgContext` (ADR-0029 org-composed shape); these
51// re-exports stay for composing services that still run their own company lane on module routes.
52// `Company*` are the canonical names (ADR-0005). `Tenant*` are deprecated aliases kept for back-compat.
53pub use crate::presentation::http::{company_auth, CompanyClaims, CompanyContext, CompanyVerifier};
54#[allow(deprecated)]
55pub use crate::presentation::http::{tenant_auth, TenantClaims, TenantContext, TenantVerifier};
56
57// --- Outbound ports: the wire contract a consumer implements ------------------
58// POS posts no GL — it drives billing (revenue) + payment (settlement) + inventory (stock issue)
59// through these traits. The shipped library has ZERO normal Cargo edges to those modules.
60pub use crate::application::service::{
61 BillingPort, PaymentPort, PosRejected,
62 // billing leg
63 SaleInvoiceRequest, SaleLine, InvoiceAck, CreditNoteRequest, ReversalAck,
64 // payment leg
65 SettlementRequest, SettlementAck, RefundRequest,
66};
67pub use crate::application::service::pos_ports::{InventoryPort, StockIssueRequest, StockIssueAck};
68
69// --- Document-grade tax + session-close variance ports -------------------------
70// `PosTaxComputePort` resolves per-line tax for EVERY ring (implement over the tax module's
71// `calculate_document`); `PosCashVariancePort` books the GL correction when a close counts a drawer
72// difference (idempotent on `opening_entry_id` — a session closes exactly once).
73pub use crate::application::service::{
74 PosTaxComputePort, PosTaxComputeRequest, PosTaxLineIn, PosTaxDocumentType,
75 PosTaxComputeResult, PosTaxComponent,
76 PosCashVariancePort, CashVarianceRequest, CashVarianceAck, CashVarianceDirection,
77};
78
79// --- Server-authoritative cart pricing (promo) port ---------------------------
80pub use crate::application::service::{
81 CartPricingPort, CartPriceRequest, CartPriceLine, CartPricingError,
82 PricedCart, PricedCartLine, PricedRewardLine,
83};
84
85// --- The write service: open / ring / sync / tender / recognize / return / drawer / pins
86pub use crate::application::service::PosWriteService;
87// Vocabulary a consumer passes in / receives (kept here so callers don't reach into the service tree).
88pub use crate::application::service::{
89 NewSession, NewSale, NewSaleLine, NewCartSale, CartSaleLine, NewClose, ManagerAuth,
90 TenderOutcome, RecognizeOutcome, ReturnOutcome, CloseOutcome, MethodRecon, PosError,
91 VarianceBooking, PinPolicy,
92};
93// Offline replay (`sync_from_ui`): identity by `client_uuid`, client totals discarded, server
94// recomputes; a refund replay is privileged (manager PIN verified server-side).
95pub use crate::application::service::{
96 NewSyncSale, SyncSaleLine, SyncTender, SyncAction, SyncOutcome, TicketTotals,
97};
98// Manager-PIN credentials: argon2-hashed server-side; the raw PIN never leaves the request.
99pub use crate::application::service::pos_manager_pin::SetPin;
100
101// --- Events + the sink a consumer subscribes to drive recognition -------------
102// `PosTenderCompleted` is the recognition trigger: a composing service subscribes and calls
103// `PosWriteService::recognize_sale` on it. The library does NOT call recognize internally.
104pub use crate::application::service::{
105 PosEvent, PosEventSink, LoggingSink,
106 PosInvoicePaid, PosInvoiceReturned, PosSessionClosed, PosSessionOpened,
107};
108pub use crate::application::service::pos_events::PosTenderCompleted;