Skip to main content
Inventory lives in apps/inventory and runs locally through Portless at https://inventory.tuturuuu.localhost. Production is intended for https://inventory.tuturuuu.com. The app is a registered Tuturuuu satellite app. It uses Tuturuuu app-session auth for targetApp: 'inventory', exposes local /verify-token and /api/auth/verify-app-token handoff routes, and forwards fallback /api/* traffic to centralized apps/web APIs. Keep protected inventory, payment, Stripe Connect, checkout, and audit mutations behind apps/web so provider secrets, bot protection, request logging, and Observability stay centralized. Workspace-scoped Inventory APIs in apps/web must authorize through authorizeInventoryWorkspace, which accepts the Inventory app-session cookie and then performs workspace membership and permission checks. Authenticated dashboard and workspace API access is permission-driven; do not hide these routes behind the ENABLE_INVENTORY workspace config. Keep public storefront delivery separate, since published storefront behavior may still apply storefront-specific rollout gates. Do not use resolveAuthenticatedSessionUser, supabase.auth.getUser(), or request-scoped Supabase clients as the primary auth gate for these routes, because the satellite clears local Supabase cookies and forwards app-session cookies instead. The operator console uses the same collapsible Tuturuuu satellite workspace structure as the Tasks, Finance, Calendar, and CMS apps: dashboard layouts should keep server work to auth/workspace gating, then render client-side views backed by TanStack Query and @tuturuuu/internal-api. Do not reintroduce a separate Inventory-only app shell or direct client Supabase reads for protected workspace data. The local token verifier must call the central Web verifier with verificationBaseUrl: WEB_APP_URL; Inventory protected routes require both the host-only Inventory app-session cookie and the Web-issued app-session cookie used by rewritten apps/web API requests. Local-only token validation will create a redirect loop back to platform login. Current-user bootstrap APIs such as /api/v1/users/me/default-workspace and /api/v1/users/me/profile must keep inventory in their app-session audience allowlist, or /dashboard will accept the local handoff cookies and then bounce back to Web auth after the bootstrap request returns 401. Public storefront routes live at /store/[storeSlug] inside apps/inventory and are intentionally exempt from the operator auth proxy. They should only read published storefront data through apps/web public APIs and should create checkout reservations through the central apps/web RPC wrapper. Do not add storefront CRUD, reservation writes, invoice finalization, or settlement writes directly to apps/inventory.

Local Development

Use:
bun dev:inventory
The package dev script runs Portless. For direct port debugging, run apps/inventory with bun dev:app, which falls back to port 7815.

Product Boundary

Inventory starts with workspace-scoped surfaces for:
  • product catalog categorization by type, owner, manufacturer, talent, supplier, channel, and fulfillment policy
  • stock movement and reservation ledgers
  • bundle and promotion availability controls
  • checkout fee visibility for processing fees, Tuturuuu platform fees, conversion fees, settlement estimates, and net payout
  • payment and inventory audit streams
  • Stripe Connect readiness for B2B2C sellers who link their own Stripe account
The commerce storefront extension adds:
  • operator routes for overview, catalog, stock, bundles, storefronts, checkouts, sales, setup readiness, and audits
  • public routes for /store/[storeSlug], /store/[storeSlug]/products/[listingId], cart, checkout, and order status
  • private-schema tables for storefronts, listings, bundles, checkout sessions, checkout lines, reservations, and settlement ledger entries
  • service-role-only RPCs for creating reservations, releasing or expiring reservations, and linking a completed checkout to a finance_invoice
New commerce tables belong in the private schema, not public. Public and satellite clients must go through apps/web APIs plus @tuturuuu/internal-api; direct Supabase client access to these tables is not part of the contract. Protected workspace routes must authenticate and normalize the workspace with the request-scoped client before any private-table read or write, then use server-only database access or service-role RPCs behind apps/web. Core stock and setup data lives in private inventory tables: private.inventory_products, private.inventory_units, private.inventory_warehouses, private.inventory_suppliers, private.inventory_batches, private.inventory_batch_products, private.inventory_owners, private.inventory_audit_logs, and private.inventory_manufacturers. Dashboard pages and APIs should access them through server-owned apps/web routes. Prefer private-schema RPCs for product catalog, low-stock, and other repeated join-heavy reads; call them with createAdminClient().schema('private').rpc(...) from server code. Manufacturers are a normalized workspace setup entity matching the supplier-style management model. Products store only workspace_products.manufacturer_id; API responses may still include manufacturer as a display name for older clients. Legacy imports that send package/product manufacturer text should upsert the trimmed name into private.inventory_manufacturers, assign the resulting manufacturer_id, and avoid writing manufacturer text back to workspace_products. Bundle components are a workspace-scoped stock contract. When creating or updating a bundle, every component’s product, unit, warehouse, and stock row must belong to the same workspace as the bundle. The database trigger on private.inventory_bundle_components enforces that invariant for direct writes, and the checkout reservation RPC re-checks the same workspace before locking stock. Do not trust stored bundle component UUIDs as already authorized input. Do not hardcode Stripe fee schedules as durable truth. The checkout estimator is for quoting and operator review; production reconciliation should persist the estimate shown to the seller and then reconcile it against actual Stripe balance transaction fee rows after settlement.

Deployment

Inventory has dedicated Vercel workflows:
  • .github/workflows/vercel-preview-inventory.yaml
  • .github/workflows/vercel-production-inventory.yaml
These workflows use VERCEL_INVENTORY_PROJECT_ID. Add that secret before enabling hosted deployments for inventory.tuturuuu.com.