> Documentation index: https://stilldeeppos.com/llms.txt # Vibe-code your point of sale, the engine is built > StillDeep is a headless point of sale with business logic, security, reports and communication built. Vibe-code the screen with Claude, Codex or Cursor. Source: https://stilldeeppos.com/ ## Vibe-code your POS in minutes. The rest is built. Business logic, security, reports and communication are done. Describe your screen to Claude, Codex or Cursor: your agent reads our docs, plugs into the gRPC contract and ships a register that sells, even offline. Still waters run deep. A simple surface your agent codes in minutes, and a deep foundation already built underneath: StillDeep handles everything a register needs, so your team only designs the screen your business deserves. ## Already done for you ### Business logic Sales, Canadian sales taxes, discounts, split payments, refunds, reservations, ticketing with seats, rentals, appointments and shifts. The engine re-checks every sale, whatever the screen sends. ### Security Registers never touch the database, the server validates every input, receipts and tickets carry signed codes checked offline, and permissions follow each role. Hybrid post-quantum is in progress. ### Reports The Report web app shows sales by day and period, shifts, taxes, top products, inventory and employees, with a transaction audit. Shift summaries, sales by payment method and tips also come over gRPC for your own dashboards. ### Communication Offline first: each register keeps an outbox and syncs with the business server when the network comes back. Live events, chat between registers and an optional local AI assistant. ## Who it is for ### Developers and vibe coders A serious point-of-sale engine behind your agent: no taxes, offline sync or printing to rebuild once more. ### Recreation and tourism Parks, sugar shacks, ski hills, mini-golf, escape rooms, cinemas and shows, self-service kiosks. ### Retail Stores with inventory, barcodes, lots and expiry dates, products sold by weight. ### Services by appointment Grooming salons, hair salons, workshops, with qualified staff and an agenda. ## How it works ### Install the server One server per business: a PostgreSQL database, the Admin web app to configure everything and the Report web app for the numbers. ### Give StillDeep to your agent Paste the prompt above, or connect the read-only docs MCP server. Your agent reads the guide, the skill and the `.proto` files, then writes the screen in the language you choose. ### Sell Run the screen on the register: it syncs with the server and keeps selling on its own when it has to. ## What is ready today StillDeep is in development (version 0) and no customer is deployed yet. ### Built and tested The sales engine, offline synchronization, the database proxy, receipts and printing, the receipt designer, extensions and the Admin. ### In progress Hybrid post-quantum security. ### Planned Docker packaging and signed per-register license activation. The [architecture page](/architecture) tells exactly what is delivered and what is not. ## Ready to vibe-code your register? Create your account now: it takes one minute and lets you buy your licenses when you are ready. [Create an account](/signup) or [read the documentation](/docs). --- > Documentation index: https://stilldeeppos.com/llms.txt # Features of the StillDeep point of sale > Sales, taxes, offline mode, ticketing, retail, rentals, appointments, reservations, receipts and printing: what the StillDeep engine does for every register. Source: https://stilldeeppos.com/features Every feature lives in the engine, not in the screen. A kiosk, a touch register and a web shop share the same rules, the same taxes and the same receipts. ## Selling - One sales engine for every register: cart, discounts, fees, payments, refunds and shift closing follow the same path whether the screen runs in the same process or over gRPC. - The server checks every sale again: prices, taxes and totals sent by a screen are never trusted as is. - Split payments, even shares, quick cash amounts, gift receipts, duplicates of past invoices. - Shifts with pauses, transfer to another register, blind cash counts and closing from any register with the right permission. - Canadian sales taxes (GST, QST, HST) computed per invoice with the official rounding rules. Canadian cash rounding is available as an extension. - Money is always stored as integer cents, never as floating point numbers: no penny lost to rounding. ## Offline by design - Each register keeps a local SQLite copy of the catalog, taxes and members, and an outbox of sales. - When the server cannot be reached, sales continue from the local copy; the outbox is drained first when the server comes back, before any update. - Printed numbers (receipts, tickets, reservations) never collide between registers, even offline. - Receipts and tickets carry a signed QR code that a register can verify without the Internet. ## Trades and modules ### Ticketing Scheduled events, seats and capacities held while the cart is open, tickets printed with their seat and code. ### Retail Inventory ledger, retail and case barcodes, scale labels, prices by kilogram or pound, lots and expiry dates, shelf labels. ### Rentals and locations Rental agreements with return dates and deposits, rented locations that carry their customer. ### Services by appointment Agenda, services that require a qualified staff group, appointments taken with a deposit. ### Reservations A sale put aside under an RV number, resumed by scan or from the customer file, paid in several steps. ### Cards and loyalty Customer cards, coupons issued and sealed by the server, badges for employees and customers. Restaurant and bar modules are planned. Modules are activated per business today; activation per register, sold as a license, is planned. ## Receipts and printing - Thermal printers (ESC/POS over network, USB or serial) and regular printers through the system driver. - A drag-and-drop designer in the Admin for receipts, tickets, cards (CR80) and employee badges, with conditions and loops. - PDF and image output, barcodes and QR codes, French and English templates chosen from the customer's language. - Print destinations declared in the Admin, actual printer chosen at each register. ## Scanning Barcode readers as keyboard (HID) or serial port, several per register. Each screen declares what it accepts: products, customers, employees, receipts, coupons. Codes that cannot come from a reader are refused. ## Administration and reports - Admin web app on the local network: catalog, taxes, employees and roles, registers, payment methods, printers, receipt layouts, extensions. - Report web app for the numbers, reachable from the local network and, if you choose, from the Internet. - French and English everywhere, with the language of each customer remembered. ## Extensions .NET extensions add steps before and after every sale action, sections in Admin forms and their own pages. The host validates everything an extension writes. Read [the extensions guide](/docs/extensions). --- > Documentation index: https://stilldeeppos.com/llms.txt # StillDeep architecture: server, registers and screens > How StillDeep is built: one server per business, registers that sell offline, a gRPC contract for every screen, and what is delivered or still in progress. Source: https://stilldeeppos.com/architecture Three layers that never mix: the business server, the register engine and the screen. Business rules live in libraries, services only host them. ## The business server Each business runs one server on its local network: - **ServerDB:** a PostgreSQL 19 database, the single source of truth. - **Server.Service:** the gRPC gateway of the registers. Registers never connect to the database directly: every operation goes through this proxy, which checks it and records it. - **Admin:** the web app to configure the business, on the local network. - **Report:** the web app for reports, on the local network and optionally on the Internet. The Internet is only used for optional cloud sync, card payments (from the terminal straight to the processor) and software updates. ## The register A register is one container (or one native program) that holds: - **The screen:** any client, in any language, speaking gRPC on the register itself. - **Intelligence:** the sales engine, business modules and extensions. - **Communication:** the local SQLite copy, the outbox and the sync with the server. On a Windows register that drives a thermal printer or a cash drawer, the program can link the libraries in-process: one process, no local network hop, same rules. ## Offline first At startup, a register drains its outbox to the server before anything else, so that an update never overwrites unsent sales. When the server cannot be reached, the register sells from its local copy. Some checks need the server: stock levels and limited seats are only guaranteed online. ## The contract Screens use the `stilldeep.v1` gRPC contract: sales, catalog, members, cards, devices, events, receipts, reservations, appointments, rentals, inventory, shifts and more. Version 1 never receives a breaking change; a version 2 would live in its own namespace. Amounts are integer cents, percentages are basis points, quantities are thousandths. ## Technology .NET 11 and C#, PostgreSQL 19, SQLite, Blazor for the web apps, gRPC over HTTP/2, MCP for the AI tools, OpenTelemetry for logs, metrics and traces. Every component runs on Windows, Linux and macOS and follows the twelve-factor rules (configuration by environment, logs on standard output, health checks, graceful shutdown). ## Delivered and in progress | Area | State | |---|---| | Database, sales engine, offline sync and outbox | Delivered | | Database proxy for registers | Delivered; TLS hardening and real enrollment in progress | | gRPC contract and example clients | Delivered | | Admin and Report web apps | Delivered | | Receipts, printing, receipt designer, signed offline codes | Delivered | | Extensions and extension registry | Delivered; package signing in progress | | Reservations, appointments, rentals, limited resources | Delivered | | StillDeep AI (local) | Delivered | | Hybrid post-quantum cryptography | In progress | | Docker packaging and automatic updates | Planned | | Per-register licensing, restaurant and bar modules | Planned | StillDeep is version 0: no customer is deployed yet. --- > Documentation index: https://stilldeeppos.com/llms.txt # Build your point-of-sale screen on StillDeep > Generate a StillDeep client from the gRPC contract in TypeScript, Python, Go, .NET, Java or Rust, or link the .NET libraries in-process. Source: https://stilldeeppos.com/developers StillDeep does the hard part of a point of sale. You build the screen, in the stack your team already knows. ## Two ways to connect ### Over gRPC The register exposes the `stilldeep.v1` contract on the register itself. Generate a client from the `.proto` files in any gRPC language and call the sales, catalog, member and event services. The StillDeep source code is private; its client contract is public: [download the `.proto` files](/downloads/stilldeep-contracts.zip). ### In-process (.NET) A .NET register can link the business libraries directly: one process, no local network hop. This is how the examples that drive thermal printers and cash drawers work. ## What a client does 1. Open a shift for the employee (by badge or password). 2. Open a cart, add items by scan or search, attach a customer. 3. Choose a payment method, tender, finalize. 4. Print the receipt and the attached documents (tickets, cards, contracts). 5. Listen to events: availability changes, chat messages, server refusals. The server re-checks every sale. Your screen never needs to compute taxes or protect totals: it shows what the engine returns. ## Example clients - Windows Forms examples for a simple store, a shop, a cinema and a ticket office. - A WPF pet shop and grooming salon register, with a skin contract for your own branding. - A self-service kiosk over gRPC. - Web examples in Node.js (cinema) and Go (ticketing). Reference clients are meant to be published as open source (MIT or Apache 2.0). The StillDeep core is proprietary. ## Contract rules - Package `stilldeep.v1`; version 1 never receives a breaking change. - Money in integer cents, percentages in basis points, quantities in thousandths. No floating point anywhere. - Timestamps in UTC; errors as `google.rpc.Status` with a stable code. ## Next steps - [Build a register screen](/docs/build-a-client): the full path from `.proto` files to a first sale. - [Extensions](/docs/extensions): add rules and screens without touching the core. - The generated [gRPC API reference](/fr/docs/reference/grpc) and the [language guides](/fr/docs/reference/sdk) are in French. --- > Documentation index: https://stilldeeppos.com/llms.txt # Security of the StillDeep point of sale > Registers that never touch the database, a server that re-checks every sale, signed offline codes, cards kept out of reach, post-quantum in progress. Source: https://stilldeeppos.com/security A point of sale handles money in a shop open to the public. StillDeep trusts no screen, no register and no extension: everything is checked by the code that applies it. ## Nothing from a screen is trusted Every input is validated by the code that applies it, never only by the screen: the sales engine re-checks quantities and prices, the server re-checks totals, taxes and shift rules, and the database constraints remain the last line of defense. An open-source client cannot bypass a rule by sending a forged request. ## Registers never touch the database Registers do not hold a database password. Every operation goes through a gRPC proxy on the business server, which knows each register, checks its permissions and records the operation. Each register has its own identity; there is no shared master account. ## Card payments stay out of StillDeep Card payments go from the payment terminal straight to the processor with point-to-point encryption. Card numbers never go through StillDeep or the business server. ## Signed codes, verifiable offline Receipts and tickets carry a QR code signed with ECDSA P-256 and encrypted with AES-256-GCM. A register can verify a ticket at the gate without the Internet. Employee badges and coupons are sealed by the server alone; registers only hold the public keys to verify them. Revoking a register revokes the keys it held. ## Extensions are contained Everything an extension writes or returns is validated by the host. An extension that fails, times out or writes invalid data is stopped, its registrations are removed and the sale continues. Extensions are installed from a registry with SHA-256 checksums; package signing is in progress. ## Secrets and memory No connection string or credential in configuration files: secrets are encrypted at rest and injected at startup. Keys in memory are scattered and locked in RAM, and on Linux and macOS the process cannot be dumped. Passwords are hashed with bcrypt. ## Post-quantum, in progress The target is hybrid cryptography, classical plus post-quantum (ML-KEM, FIPS 203, and ML-DSA, FIPS 204), for register enrollment, extension signatures, AI tool tokens and the audit log. No communication will depend on post-quantum algorithms alone. This work is in progress, not delivered. ## Report a vulnerability If you find a security issue on this site or in StillDeep, write to the security contact published in `/.well-known/security.txt`. Do not test on systems you do not own. --- > Documentation index: https://stilldeeppos.com/llms.txt # StillDeep AI: a local assistant for your business > An optional AI assistant on your own network: it sets up a new business, answers staff, drives the Admin and helps at the register, on local models. Source: https://stilldeeppos.com/ai StillDeep AI is optional and runs on your own hardware. Your sales, customers and catalog never leave your network to reach an AI provider. ## What it does ### Sets up a new business Import a menu, a price list or a product file, create taxes and employees. The assistant plans the work, runs it through the Admin tools and sums up what it did. ### Answers staff questions How to add a product, close a shift, print a duplicate. Answers come from the StillDeep documentation and from your own configuration. ### Helps at the register Product, stock, service availability and events: read-only answers from your store data, with products shown as tiles the cashier can add. ### Cleans product photos Background removal, brightness and framing on any image field of the Admin, with the original always kept. ## How it runs - Language and vision models run locally (llama.cpp), sized to the hardware: a modest graphics card is enough. - The assistant acts through the same Admin tools as a person (MCP), with the same permissions. - At the register, it only reads. It never changes a sale, a price or a schedule. - Web search, when enabled, sends search queries to the web; it can be turned off per register. ## On this website The chat button on this site appears only when the StillDeep AI service is running. This public assistant is separate: it answers questions about StillDeep from public information, has no tools and no access to any account or business data. Do not share personal or payment information with it. --- > Documentation index: https://stilldeeppos.com/llms.txt # StillDeep pricing > StillDeep licenses per register for 1, 2 or 3 years: the point of sale and its modules, paid by card. Live catalog prices, before taxes. Source: https://stilldeeppos.com/pricing ## How licenses work - A license covers one register for 1, 2 or 3 years. The **Point of sale** license opens the register; each module (Retail, Ticketing, Bar and restaurant, Locations, Appointments, Cards and loyalty, Commercial fees) adds to it. - After payment, your licenses wait in your account. You name your registers, then assign each license to one of them; the assignment is final. - The term starts on the day of the assignment, not the day of the purchase. A license assigned early to a register that already has one of the same module starts the day after the previous one ends: no day is lost. - Every license includes the sales engine, offline mode, the Admin and Reports apps, the gRPC contract and version 1 updates, never a breaking change. ## Frequently asked questions ### Is my card charged today? No. Online payment opens in January 2027: nothing can be paid on the site yet. Once it opens, the site starts in test mode, where no card is charged. Do not enter a real card number. ### Do prices include taxes? No. Prices are shown before taxes, for one register. GST and QST, or HST, are added at checkout according to the StillDeep catalog. ### When does my license start? On the day you assign it to a register from your account. You can buy ahead, for an upcoming register or a renewal, without losing any license time. ### Can I move a license to another register? Not from your account: the assignment is final. If you made a mistake, write to us; our team can correct it. ### Does StillDeep need the Internet to sell? No. Each register keeps selling when the network or the server goes down, and syncs when it comes back. The Internet is used for card payments, updates and the optional cloud sync. ### Can I build my own screen? Yes. Every license includes the gRPC contract: build your screen in TypeScript, Python, Go, .NET or any gRPC language, or start from an example client. --- > Documentation index: https://stilldeeppos.com/llms.txt # StillDeep documentation > Guides to understand StillDeep, build a register screen, write extensions and run a business server, plus the gRPC API reference. Source: https://stilldeeppos.com/docs ## Guides ### [Core concepts](/docs/concepts) Registers, shifts, carts, the outbox, printed numbers and the proxy: the vocabulary of StillDeep. ### [Build a register screen](/docs/build-a-client) From the `.proto` files to a first finalized sale, in any gRPC language. ### [Extensions](/docs/extensions) Add rules before and after sale actions, Admin sections and pages, without touching the core. ### [Install and operate](/docs/self-hosting) What runs on the business server and the registers, the configuration and the health checks. ## API reference The reference is generated from the contract and written in French: - [gRPC API reference](/fr/docs/reference/grpc): every service, RPC, message and enumeration of `stilldeep.v1`. - [Generate a client](/fr/docs/reference/sdk), then the guides for the [TypeScript client](/fr/docs/reference/sdk/typescript), the [Python client](/fr/docs/reference/sdk/python) and the [Go client](/fr/docs/reference/sdk/go). ## For AI agents Every page of this site is also available in Markdown: add `.md` to its address, or ask for `text/markdown`. The index is [llms.txt](/llms.txt) and the full text is [llms-full.txt](/llms-full.txt). --- > Documentation index: https://stilldeeppos.com/llms.txt # About StillDeep > StillDeep is a point of sale built in Quebec, Canada, for businesses that cannot stop selling and teams that want to own their screens. Source: https://stilldeeppos.com/about ## The name "Still waters run deep." A calm surface for the cashier and the customer, a deep foundation underneath. The project was first known by its code name, WaxPOS. The logo draws the same idea: [what the logo means](/logo). ## Why another point of sale Most point-of-sale systems sell a screen and rent you a cloud. When the Internet goes down, the line stops. When the screen does not fit the business, there is nothing to do. StillDeep takes the opposite path: the business keeps its server and its data, the register keeps selling offline, and the screen belongs to whoever builds it. ## Where we are StillDeep is in development, version 0. No customer is deployed yet. The engine, the offline synchronization, the Admin, receipts and extensions are built and tested on Windows, Linux and macOS; the [architecture page](/architecture) lists what is delivered and what is still in progress. ## Where it comes from StillDeep is designed and built in Quebec, Canada. Everything is available in French and in English, and Canadian sales taxes are handled from day one. --- > Documentation index: https://stilldeeppos.com/llms.txt # The StillDeep logo and what it means > What each part of the StillDeep logo stands for: the code and sale sign, the wave on the surface, the four depths below and the AI wave. Source: https://stilldeeppos.com/logo Still waters run deep: a calm surface, and a lot of depth underneath. The logo draws exactly that. ## The name StillDeep comes from the English saying *still waters run deep*: a calm surface hides depth. That is the project. The whole depth (communication, database, offline synchronization, security, extensions) is built; what remains is the visible part, the screen, and that part is yours. ## What each part says | Part | Meaning | |---|---| | `<$>` | Code and sale together: a point of sale you program | | The blue wave | The surface: the development library, the only thing a developer touches | | First wave below | Administration | | Second wave | Security | | Third wave | Database | | Fourth wave | Marketing | | Fifth wave (very dark violet) | Artificial intelligence, in the AI version only | The deeper a wave, the wider and darker it is. ## The AI version The fifth wave appears only when we talk about AI: the register assistant, the photo agent, the AI tools of the Admin. Everywhere else the logo keeps four waves. With the name, it reads "StillDeep **AI**", with "AI" in the color of that wave. ## How it is built - A 160 by 160 grid. The `<$>` sign is centered above the wave. - The wave starts at mid-height, dips, rises in a crest under the sign, then mirrors itself to the other side. - The waves below are half circles sharing one center, each 14 units wider than the one above. - At 32 pixels and less, two waves instead of four and thicker strokes; the `$` stays. ## Light and dark The logo has no background. A light version sits on light backgrounds and a dark version on dark ones; this site shows the one that matches your theme. A one-color version is used on thermal receipts. --- > Documentation index: https://stilldeeppos.com/llms.txt # StillDeep core concepts > The vocabulary of StillDeep: business server, registers, shifts, carts, sales, the outbox, printed numbers, the proxy and modules. Source: https://stilldeeppos.com/docs/concepts ## Business server One server per business, on its local network. It holds the PostgreSQL database (the single source of truth), the gRPC gateway of the registers (Server.Service) and the Admin and Report web apps. Each business owns its server and its data. ## Register A point of sale: a touch register, a kiosk, a tablet or a web shop. A register has its own identity, its own permissions and its own local SQLite copy of the reference data (catalog, taxes, members). It never connects to the database directly: every operation goes through the proxy on the business server. ## Screen What the cashier or the customer sees. The screen is a client of the register engine, over the gRPC contract or in-process for .NET. It holds no business rule: it shows what the engine returns. ## Shift An employee's work period on registers: opened by badge or password, paused and resumed, possibly moved to another register, then closed with a cash count. Every payment counts in the shift that took it. ## Cart and sale A cart collects items, customer, discounts, fees and payments. The sales engine applies the same rules on every register. When the cart is finalized, the sale is written locally and sent to the server, which checks prices, taxes and totals again. ## Outbox The local table of sales and operations not yet sent to the server. A background worker drains it, and a register always drains it first at startup, before any update, so that an update never erases unsent sales. ## Offline mode When the server cannot be reached, the register sells from its local copy. Card payments still work if the terminal reaches its processor. Stock levels and limited seats are only guaranteed online; sales replayed from the outbox are never refused. ## Printed numbers Receipts, tickets, reservations and shifts carry a short readable number: two letters, the register, then a sequence (for example `RE5000123`). Two registers never print the same number, even offline. ## Modules and extensions Business modules (ticketing, retail, rentals, services, reservations, cards) are compiled in the engine and activated per business. Extensions are separate .NET packages that add rules, Admin sections and pages; they are installed from the Admin and distributed to the registers by the business server. ## Money and quantities Amounts are integer cents, percentages are basis points, fractional quantities are decimals. StillDeep never uses floating point numbers for money, taxes or quantities. --- > Documentation index: https://stilldeeppos.com/llms.txt # Build a register screen on StillDeep > From the stilldeep.v1 .proto files to a first finalized sale: generate the client, open a shift, fill a cart, take a payment and listen to events. Source: https://stilldeeppos.com/docs/build-a-client ## With a coding agent Claude Code, Codex, Cursor and other agents read this documentation as is: - [llms.txt](/llms.txt) lists every page in Markdown; add `.md` to any address for its Markdown version. - The read-only MCP server at `/mcp` searches and reads the docs and the contract (`search_docs`, `read_page`, `list_pages`, `get_contract`). Claude Code: `claude mcp add --transport http stilldeep /mcp`. - The skill `/.well-known/agent-skills/stilldeep-pos-screen/SKILL.md` gives the agent the steps below. - Each `.proto` file is served in plain text at `/contracts/.proto`. Describe your business and the screen you want; the agent follows the steps below and the engine checks every sale. ## Get the contract The `.proto` files of the `stilldeep.v1` package describe every service of the register: sales, catalog, members, cards, devices, events, receipts, reservations, appointments, rentals, inventory, shifts and configuration. .NET clients use the `StillDeep.Intelligence.Contracts` package; other languages generate their code from the same files. ## Generate the client Use the gRPC tools of your language: - **TypeScript and Node.js:** `@grpc/grpc-js` with `ts-proto` or `protoc-gen-ts`. - **Python:** `grpcio-tools`. - **Go:** `protoc-gen-go` and `protoc-gen-go-grpc`. - **.NET, Java, Kotlin, Rust, C++:** the official gRPC generators. Step-by-step guides with commands are in the reference (French): [generate a client](/fr/docs/reference/sdk), [TypeScript client](/fr/docs/reference/sdk/typescript), [Python client](/fr/docs/reference/sdk/python), [Go client](/fr/docs/reference/sdk/go). ## Connect to the register The register engine listens on the register itself (HTTP/2, port 50051 by default). The screen never talks to the business server: the register handles the proxy, the outbox and offline mode for it. ## Make a first sale ### Open a shift Sign the employee in by badge or password and open a shift. Each following call carries the shift identifier. ### Open a cart and add items Add items by barcode scan or catalog search, with quantities (decimals for weighed goods). Attach a customer if the sale needs one. ### Take the payment List the enabled payment methods, choose one, tender the amount. Several payments can share a sale. ### Finalize Finalize the sale: the engine writes it locally, sends it through the outbox and returns the receipt to print. ## Handle refusals Every refusal comes as a `google.rpc.Status` with a stable code (for example `shift_paused` or `stock_short`). Show a message to the cashier from the code; never retry blindly. The server re-checks every sale, so a refusal can come after the screen thought everything was fine. ## Listen to events The event service streams what happens on the register: availability of limited resources, chat messages, server decisions. A screen subscribes once and updates itself. ## Start from an example The example clients cover a simple store, a shop, a cinema, a ticket office, a self-service kiosk, a pet shop with grooming, and web clients in Node.js and Go. Start from the one closest to your business and replace its screen. ## Contract rules - Version 1 never receives a breaking change; a version 2 would be a separate package. - Money as `int64` cents, percentages as basis points, quantities in thousandths. - Timestamps in UTC. - Never trust the screen: the engine and the server validate everything, so keep business rules out of the client. --- > Documentation index: https://stilldeeppos.com/llms.txt # Extend StillDeep with extensions > Write .NET extensions that hook into sale actions, add Admin sections and pages, ship catalog items, and get installed from the extension registry. Source: https://stilldeeppos.com/docs/extensions ## What an extension can do - **Hook into sale actions.** Run before an action (add an item, choose a payment method, finalize) to let it continue, refuse it, cancel it or ask the cashier a question; run after it to react to the result. - **Add Admin sections and pages.** Extra fields on Admin forms, menu entries, reports and scheduled tasks on the server. - **Ship catalog items.** An extension can add its own items to the catalog, kept in line at each startup and hidden from manual editing. - **Keep its own data up to date.** Data migrations run once per version, under a lock, for every server host at once. The Canadian cash rounding extension is a complete example: it adds a rounding line when cash is chosen in Canadian dollars and handles refunds. ## The host trusts nothing Everything an extension writes or returns is validated by the host. An extension that throws, exceeds its time limit or writes invalid data is stopped, its registrations are removed, the failure is logged and the sale continues with the next one. ## Two sides - **Register side:** a class that implements `IStillDeepPlugin` registers its sale hooks and interaction handlers when it starts. - **Server side:** a class that implements `IServerPlugin` registers Admin sections, menus, reports, tasks and entity hooks, and updates its data. The public abstractions (`StillDeep.Intelligence.Plugins.Abstractions`, `StillDeep.Server.Plugins.Abstractions`, `StillDeep.Extensions.Abstractions`) are all an extension references. ## Installing and distributing Extensions are installed from the Admin, on the Extensions page, from a public catalog: dependencies are activated together, the SHA-256 checksum from the catalog is verified, and the server prepares a package for the registers. Each register fetches the active extensions after draining its outbox, and keeps what it has when offline. A package can also be added by hand. Package signing and per-register licensing are in progress. ## Hardware drivers Drivers for devices and optional third-party integrations are extensions too. Card payments always go from the terminal to the processor, never through an extension that would see card numbers. --- > Documentation index: https://stilldeeppos.com/llms.txt # Install and operate a StillDeep server > What runs on the business server and on each register, how StillDeep is configured, where secrets live and how health is checked. Source: https://stilldeeppos.com/docs/self-hosting ## On the business server | Component | Role | Reach | |---|---|---| | PostgreSQL 19 | Database, single source of truth | Server only | | Server.Service | gRPC gateway of the registers, proxy, hub | Local network | | Admin | Configuration web app | Local network | | Report | Reports web app | Local network, optionally Internet | | AI service (optional) | StillDeep AI, local models | Server or a GPU machine | PostgreSQL 19 is the minimum version. Services connect with dedicated database users, never the superuser, and registers never connect to the database at all. ## On each register One container or one native program with the screen, the register engine and the local SQLite copy. Registers that drive Windows hardware (thermal printers, cash drawers) can run natively and link the libraries in-process. ## Configuration StillDeep follows the twelve-factor rules: - Configuration by environment variables, never connection strings in configuration files. Secrets are kept encrypted and injected at startup; without them, the Admin opens its setup page. - Logs on standard output, with OpenTelemetry for metrics and traces. - A `/healthz` health check on every service. - Graceful shutdown on SIGTERM or Ctrl+C. ## Operating systems Every service runs on Windows, Linux and macOS. Docker packaging and automatic updates are planned; until then, services run natively. ## Updates and offline registers A register always drains its outbox before an update, so no sale is lost. Registers keep selling while the server is updated, and catch up when it comes back. ## Backups The business server holds all the data: back up its PostgreSQL database with the usual tools. Registers only hold a copy and their outbox. --- > Index de la documentation : https://stilldeeppos.com/fr/llms.txt # StillDeep — API gRPC Reference **Generated:** 2026-10-15T04:29:45+00:00 **Source:** `src/public/StillDeep.Intelligence.Contracts/protos/` (21 fichiers) **Endpoint:** `localhost:50051` (HTTP/2, package `stilldeep.v1`) Documentation generee automatiquement par `scripts/generate-grpc-docs.ps1`. Ne pas editer manuellement — modifier les .proto + relancer le script. ## Sommaire - [ageverification](#ageverification) - [appointment](#appointment) - [card](#card) - [catalog](#catalog) - [common](#common) - [config](#config) - [device](#device) - [events](#events) - [extensions](#extensions) - [inventory](#inventory) - [language](#language) - [member](#member) - [pos_proxy](#pos_proxy) - [receipt](#receipt) - [rental](#rental) - [report](#report) - [sales](#sales) - [scheduling](#scheduling) - [shift](#shift) - [sync](#sync) - [user](#user) ## ageverification Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/ageverification.proto` > E005-S16 - AgeVerificationService : verification de l'age legal pour > les produits restreints (alcool, tabac, cannabis dans les juridictions > applicables). > > Le service s'appuie sur : > * Member.custom_fields (ex : "date_of_birth") si client identifie. > * Saisie manuelle DOB par caissier si client anonyme. > * Plugin externe (ID scanner permis de conduire) qui injecte un DOB > via SourceKind.PLUGIN_SCANNER. > > Le service NE STOCKE PAS le DOB pour les clients anonymes - juste le > resultat (passed/failed) avec hash anonyme pour audit. > ### Services #### `AgeVerificationService` AgeVerificationService - verification d'age legal. Codes d'erreur : INVALID_ARGUMENT (aucune source DOB fournie ou format invalide), FAILED_PRECONDITION (verification passed=false), NOT_FOUND (product_id), PERMISSION_DENIED (manager_auth_token invalide). Le serveur logue toute verification dans system_audit_log avec hash anonymise pour conformite legale. | RPC | Request | Response | Streaming | |---|---|---|---| | `VerifyAge` | `VerifyAgeRequest` | `VerifyAgeResponse` | - | | `GetMinAgeForProduct` | `GetMinAgeForProductRequest` | `GetMinAgeForProductResponse` | - | ### Messages - `AgeVerificationResult` - `GetMinAgeForProductRequest` - `GetMinAgeForProductResponse` - `VerifyAgeRequest` - `VerifyAgeResponse` ### Enums - `VerificationSourceKind` --- ## appointment Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/appointment.proto` > AppointmentService : rendez-vous de service (toilettage, coupe de griffes, soins). > > Un rendez-vous occupe un employe qualifie pendant la duree du service plus son battement. > La disponibilite croise les quarts planifies (user_schedule), les groupes de competence et les > rendez-vous deja pris. L'encaissement passe par SalesService.AddItem(service_appointment_id). > ### Services #### `AppointmentService` | RPC | Request | Response | Streaming | |---|---|---|---| | `ListAppointments` | `ListAppointmentsRequest` | `ListAppointmentsResponse` | - | | `GetAvailability` | `GetAvailabilityRequest` | `GetAvailabilityResponse` | - | | `CreateAppointment` | `CreateAppointmentRequest` | `AppointmentResponse` | - | | `UpdateAppointment` | `UpdateAppointmentRequest` | `AppointmentResponse` | - | ### Messages - `Appointment` - `AppointmentResponse` - `AvailableSlot` - `CreateAppointmentRequest` - `GetAvailabilityRequest` - `GetAvailabilityResponse` - `ListAppointmentsRequest` - `ListAppointmentsResponse` - `StaffDay` - `TimeRange` - `UpdateAppointmentRequest` ### Enums - `AppointmentStatus` --- ## card Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/card.proto` > CardService - cartes physiques / virtuelles : carte cadeau, carte fidelite, > carte de rabais, carte employe, membership card. > > Une carte peut etre attachee a 0 ou 1 member. Le solde / operations / > passes sont realises par le plugin Cartes (E015). Ce service expose juste > la lecture / lookup pour le POSClient et SalesService.AttachCard. > ### Services #### `CardService` CardService - lecture des cartes physiques / virtuelles. Appele par : POSClient (scan / saisie carte), SalesService.AttachCard en interne, MemberService (lister cartes d'un member). Pas de mutation ici - emission, recharge, blocage passent par ServerAdmin + plugin Cartes (E015). Codes d'erreur : NOT_FOUND, INVALID_ARGUMENT, FAILED_PRECONDITION (carte LOST/REVOKED/EXPIRED selon contexte d'usage). | RPC | Request | Response | Streaming | |---|---|---|---| | `GetCard` | `GetCardRequest` | `Card` | - | | `ListCards` | `ListCardsRequest` | `ListCardsResponse` | - | ### Messages - `Card` - `GetCardRequest` - `ListCardsRequest` - `ListCardsResponse` ### Enums - `CardKind` - `CardStatus` --- ## catalog Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/catalog.proto` > E005-S03 - CatalogService : produits, categories, taxes. > > Lecture seule depuis POSClient. La modification du catalogue passe par > ServerAdmin (E007), pas par ce service. Les donnees sont synchronisees > depuis ServerDB vers SQLite local du poste (Bootstrap data + delta sync). > ### Services #### `CatalogService` ----- Service ----- CatalogService - lecture seule du catalogue produits / categories / taxes. Appele par : POSClient (recherche produit, autocomplete, scan barcode), et indirectement par SalesService.AddItem (resolution interne). Ne fait jamais d'ecriture - les modifications passent par ServerAdmin (E007) qui ecrit dans ServerDB (Postgres) et la sync se propage aux postes via Communication.Lib (bootstrap + delta). Erreurs typiques : NOT_FOUND si produit / categorie / tax inexistant ; INVALID_ARGUMENT si requete vide ou parametres incoherents. | RPC | Request | Response | Streaming | |---|---|---|---| | `GetProductBySku` | `GetProductRequest` | `Product` | - | | `GetProductByBarcode` | `GetProductByBarcodeRequest` | `Product` | - | | `GetItem` | `GetItemRequest` | `Product` | - | | `GetItems` | `GetItemsRequest` | `GetItemsResponse` | - | | `SearchProducts` | `SearchProductsRequest` | `SearchProductsResponse` | - | | `Autocomplete` | `AutocompleteRequest` | `AutocompleteResponse` | - | | `ListCategories` | `ListCategoriesRequest` | `ListCategoriesResponse` | - | | `GetActiveTaxes` | `GetTaxesRequest` | `GetTaxesResponse` | - | | `ListPriceTierLists` | `ListPriceTierListsRequest` | `ListPriceTierListsResponse` | - | | `ListPriceTierEntries` | `ListPriceTierEntriesRequest` | `ListPriceTierEntriesResponse` | - | | `GetMedia` | `GetMediaRequest` | `MediaResponse` | - | ### Messages - `AutocompleteHit` - `AutocompleteRequest` - `AutocompleteResponse` - `Category` - `GetItemRequest` - `GetItemsRequest` - `GetItemsResponse` - `GetMediaRequest` - `GetProductByBarcodeRequest` - `GetProductRequest` - `GetTaxesRequest` - `GetTaxesResponse` - `ListCategoriesRequest` - `ListCategoriesResponse` - `ListPriceTierEntriesRequest` - `ListPriceTierEntriesResponse` - `ListPriceTierListsRequest` - `ListPriceTierListsResponse` - `MediaResponse` - `PriceOption` - `PriceTierEntry` - `PriceTierEntryWindow` - `PriceTierList` - `Product` - `ProductCustomFieldValue` - `SearchProductsRequest` - `SearchProductsResponse` - `Tax` ### Enums - `PricingKind` --- ## common Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/common.proto` > E005-S01 - Types fondamentaux partages par tous les services StillDeep. > > Ces messages sont importes par tous les autres .proto. Ils definissent les > conventions numeriques (R14 : aucun double / float, decimal partout) et les > briques d'enveloppe : Money, Identifier, Pagination, ErrorDetail, > PluginExtensions, etc. > > R14 : montants en cents int64 (jamais double/float). > Versioning : namespace stilldeep.v1.* - v2 sera un namespace separe. > Convention : snake_case pour les fields, PascalCase pour les messages. > ### Messages - `ActionResponse` - `CustomFieldValue` - `ErrorDetail` - `Identifier` - `Money` - `PageInfo` - `Pagination` - `Percentage` - `PluginExtensions` - `Quantity` --- ## config Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/config.proto` > E005-S14 - ConfigService : configuration runtime du poste + diagnostics. > > Permet au caissier / manager de : > * lire la config courante (printer assignee, idle_timeout, branding). > * modifier les preferences user (language persist, theme). > * recuperer les logs recents pour debug (limite a 1h). > * declencher un restart propre du POSClient (apres update plugin). > > La modification de la config commerce-wide (ex : tax_rates, business_hours) > passe par ServerAdmin (E007), pas par ce service. > ### Services #### `ConfigService` ConfigService - configuration runtime + diagnostics. Codes d'erreur : NOT_FOUND, PERMISSION_DENIED, FAILED_PRECONDITION (restart avec paniers ouverts). | RPC | Request | Response | Streaming | |---|---|---|---| | `GetPostConfig` | `GetPostConfigRequest` | `PostConfig` | - | | `GetUserPreferences` | `GetUserPreferencesRequest` | `UserPreferences` | - | | `UpdateUserPreferences` | `UpdateUserPreferencesRequest` | `UserPreferences` | - | | `GetClientLogs` | `GetClientLogsRequest` | `GetClientLogsResponse` | - | | `RestartClient` | `RestartClientRequest` | `RestartClientResponse` | - | ### Messages - `GetClientLogsRequest` - `GetClientLogsResponse` - `GetPostConfigRequest` - `GetUserPreferencesRequest` - `LogEntry` - `PaymentMethodInfo` - `PostConfig` - `RestartClientRequest` - `RestartClientResponse` - `StoreInfo` - `UpdateUserPreferencesRequest` - `UserHotkey` - `UserPreferences` ### Enums - `LogLevel` --- ## device Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/device.proto` > E005-S05 - DeviceService : etat / controle des peripheriques POS. > > Implementations concretes via plugins drivers (E011) - Epson ESC/POS, > Moneris P2PE, etc. Ce service expose un controle uniforme cote UI. > ### Services #### `DeviceService` ----- Service ----- DeviceService - controle / lecture des peripheriques POS. Appele par : POSClient (status pour iconographie UI, ouverture tiroir manuelle, test peripheriques en config), SalesService (impression auto au Finalize via ReceiptService -> DeviceService). Implementations : routees vers les plugins drivers via la chain IDeviceChain dans Intelligence.Lib. Chaque DeviceType a son driver specifique. Codes d'erreur : NOT_FOUND (device_id), FAILED_PRECONDITION (device pas READY), UNAVAILABLE (plugin driver absent), PERMISSION_DENIED. Dependances : EventService (publication DeviceStatusChangedEvent, DrawerOpenedEvent, ReceiptPrintedEvent). | RPC | Request | Response | Streaming | |---|---|---|---| | `ListDevices` | `ListDevicesRequest` | `ListDevicesResponse` | - | | `GetDeviceStatus` | `GetDeviceStatusRequest` | `GetDeviceStatusResponse` | - | | `OpenCashDrawer` | `OpenCashDrawerRequest` | `ActionResponse` | - | | `PrintReceipt` | `PrintReceiptRequest` | `ActionResponse` | - | | `TestDevice` | `TestDeviceRequest` | `TestResponse` | - | ### Messages - `Device` - `GetDeviceStatusRequest` - `GetDeviceStatusResponse` - `ListDevicesRequest` - `ListDevicesResponse` - `OpenCashDrawerRequest` - `PrintReceiptRequest` - `TestDeviceRequest` - `TestResponse` ### Enums - `DeviceStatus` - `DeviceType` --- ## events Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/events.proto` > E005-S06 - EventService : streaming temps reel cote POSClient. > > Permet a plusieurs UIs simultanees (caisse, customer display, kitchen > display, second ecran) de voir le meme panier en direct. Le UI souscrit > via Subscribe -> stream Event ; le serveur push toute mutation pertinente. > > Note : le bus interne aux plugins (in-process AssemblyLoadContext) est une > abstraction C# distincte (IPluginEventBus) - cf > StillDeep.Intelligence.Plugins.Abstractions. Ce service gRPC ne dessert que > les CLIENTS UI distants ou multi-poste. > ### Services #### `EventService` ----- Service ----- EventService - flux temps reel pour synchronisation multi-UI. Appele par : POSClient principal (caisse), customer display, kitchen display, second ecran admin, plugins out-of-process. Patterns d'usage : * Customer display : Subscribe(kinds=[CART, PAYMENT], cart_id_filter=) -> affiche items + total en live. * Kitchen display : Subscribe(kinds=[CART], post_id_filter=) -> filtre cote client les Cart avec product_kind="restaurant_item". * Scanner externe : Publish(ScanReceivedEvent) - le systeme route au consommateur qui avait emis ScanRequestedEvent. Codes d'erreur : INVALID_ARGUMENT (subscriber_id vide), UNAUTHENTICATED. | RPC | Request | Response | Streaming | |---|---|---|---| | `Subscribe` | `SubscribeRequest` | `Event` | server | | `Publish` | `PublishEventRequest` | `ActionResponse` | - | | `Heartbeat` | `HeartbeatRequest` | `HeartbeatResponse` | bidi | ### Messages - `BalanceUpdatedEvent` - `CartCardAttachedEvent` - `CartItemAddedEvent` - `CartItemRemovedEvent` - `CartLocationAttachedEvent` - `CartMemberAttachedEvent` - `CartUpdatedEvent` - `DeviceStatusChangedEvent` - `DrawerOpenedEvent` - `Event` - `HeartbeatRequest` - `HeartbeatResponse` - `PaymentCompletedEvent` - `PaymentInitiatedEvent` - `PaymentMethodChangedEvent` - `PublishEventRequest` - `ReceiptPrintedEvent` - `RefundIssuedEvent` - `ScanReceivedEvent` - `ScanRequestedEvent` - `ShiftClosedEvent` - `ShiftOpenedEvent` - `ShiftPausedEvent` - `ShiftResumedEvent` - `SubscribeRequest` - `TransactionFinalizedEvent` ### Enums - `EventKindFilter` --- ## extensions Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/extensions.proto` > E030 S14 - Documents d'extensions et sections des ecrans generiques. > > Un document est une fiche d'extension sans table (un animal, une race, le reglage d'un > produit) : valeurs en objet JSON validees par le schema de son type. Un poste lit tous les > types ; il n'ecrit que ce que le type lui ouvre (post_access) et, si le type l'exige, > avec la permission de l'employe du quart ouvert (post_permission). > ### Services #### `DocumentService` DocumentService - extension documents at a post. Writes run as the employee of the post's open shift. Errors: NOT_FOUND, PERMISSION_DENIED (type closed to posts, permission missing), FAILED_PRECONDITION (invalid values, no open shift, still referenced), with the reason code in the x-failure-code trailer. | RPC | Request | Response | Streaming | |---|---|---|---| | `GetDocument` | `GetDocumentRequest` | `DocumentResponse` | - | | `ListDocuments` | `ListDocumentsRequest` | `ListDocumentsResponse` | - | | `SaveDocument` | `SaveDocumentRequest` | `DocumentResponse` | - | | `ChangeDocument` | `ChangeDocumentRequest` | `DocumentResponse` | - | #### `UiExtensionService` UiExtensionService - sections declared by the extensions loaded on this post. | RPC | Request | Response | Streaming | |---|---|---|---| | `ListUiExtensions` | `ListUiExtensionsRequest` | `ListUiExtensionsResponse` | - | ### Messages - `ChangeDocumentRequest` - `Document` - `DocumentResponse` - `GetDocumentRequest` - `ListDocumentsRequest` - `ListDocumentsResponse` - `ListUiExtensionsRequest` - `ListUiExtensionsResponse` - `SaveDocumentRequest` - `UiSection` ### Enums - `DocumentAction` - `DocumentPostAccess` - `UiSectionKind` --- ## inventory Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/inventory.proto` > E005-S11 - InventoryService : reception, transferts, ajustements, comptage, > historique mouvements. Le stock disponible est calcule en sommation des > product_inventory_movement (+/-). Aucun "compteur denormalise" — convention > StillDeep, voir feedback_inventory_ledger memory. > > Lecture du stock courant : Product.stock_quantity (CatalogService) calcule > par le serveur a la demande. Pour un detail des mouvements, GetStockHistory. > > Appele par : ServerAdmin (reception, transfert, ajustement), POSClient > (count en magasin, restock manuel), plugins (consommation auto via recettes > product_component). > ### Services #### `InventoryService` InventoryService - gestion de l'inventaire (ledger append-only). Codes d'erreur : INVALID_ARGUMENT (quantite negative pour Receive, kind invalide), NOT_FOUND, FAILED_PRECONDITION (stock insuffisant pour transfer si oversell_policy=block), PERMISSION_DENIED. Dependances : EventService publie StockMovementRecorded (a ajouter dans events.proto V2 si besoin live). | RPC | Request | Response | Streaming | |---|---|---|---| | `ReceiveStock` | `ReceiveStockRequest` | `ReceiveStockResponse` | - | | `TransferStock` | `TransferStockRequest` | `TransferStockResponse` | - | | `AdjustStock` | `AdjustStockRequest` | `AdjustStockResponse` | - | | `CountInventory` | `CountInventoryRequest` | `CountInventoryResponse` | - | | `GetStockLevel` | `GetStockLevelRequest` | `StockLevel` | - | | `ListStockLevels` | `ListStockLevelsRequest` | `ListStockLevelsResponse` | - | | `GetStockHistory` | `GetStockHistoryRequest` | `GetStockHistoryResponse` | - | ### Messages - `AdjustStockRequest` - `AdjustStockResponse` - `CountInventoryRequest` - `CountInventoryResponse` - `GetStockHistoryRequest` - `GetStockHistoryResponse` - `GetStockLevelRequest` - `ListStockLevelsRequest` - `ListStockLevelsResponse` - `ReceiveStockRequest` - `ReceiveStockResponse` - `StockLevel` - `StockMovement` - `TransferStockRequest` - `TransferStockResponse` ### Enums - `InventoryMovementKind` --- ## language Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/language.proto` > E027 - LanguageService : selection + resolution de langue d'affichage. > > Permet au caissier / kiosque / client de : > * Lister les langues actives (system_language is_active=true). > * Resoudre la langue effective pour un contexte (poste, employe, client). > * Forcer ponctuellement une langue sur un cart_id (override volatil). > * Effacer l'override volatil. > > L'override est stocke en memoire dans Intelligence.Service (perdu au restart) — > c'est intentionnel (cf. CLAUDE.md E027). Pour changer durablement la langue > d'un poste ou d'un employe, passer par Server.Admin (E007). > ### Services #### `LanguageService` ----- Service ----- Codes d'erreur : * NOT_FOUND : locale demandee absente ou inactive dans system_language. * INVALID_ARGUMENT : cart_id mal forme. | RPC | Request | Response | Streaming | |---|---|---|---| | `ListLanguages` | `ListLanguagesRequest` | `ListLanguagesResponse` | - | | `GetEffectiveLocale` | `GetEffectiveLocaleRequest` | `GetEffectiveLocaleResponse` | - | | `SetCartLocaleOverride` | `SetCartLocaleOverrideRequest` | `SetCartLocaleOverrideResponse` | - | | `ClearCartLocaleOverride` | `ClearCartLocaleOverrideRequest` | `ClearCartLocaleOverrideResponse` | - | ### Messages - `ClearCartLocaleOverrideRequest` - `ClearCartLocaleOverrideResponse` - `GetEffectiveLocaleRequest` - `GetEffectiveLocaleResponse` - `Language` - `ListLanguagesRequest` - `ListLanguagesResponse` - `SetCartLocaleOverrideRequest` - `SetCartLocaleOverrideResponse` --- ## member Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/member.proto` > E005-S04 - MemberService : recherche / lecture / creation / mise a jour > des members (clients enregistres dans le programme). > > Note : wallets / passes / programmes fidelite vivent dans le plugin Cartes > (E015). GetWalletBalance retourne plugin_loaded=false si absent. Pour > scanner / attacher une carte au panier, utiliser SalesService.AttachCard. > ### Services #### `MemberService` ----- Service ----- MemberService - gestion des members (clients enrolles). Appele par : POSClient (recherche / creation rapide / association panier), ServerAdmin (CRUD complet). Codes d'erreur : NOT_FOUND, INVALID_ARGUMENT, ALREADY_EXISTS, PERMISSION_DENIED (status BARRED sans manager role), FAILED_PRECONDITION. Dependances : plugin Cartes pour GetWalletBalance. | RPC | Request | Response | Streaming | |---|---|---|---| | `GetMemberByNumber` | `GetMemberRequest` | `Member` | - | | `SearchMembers` | `SearchMembersRequest` | `SearchMembersResponse` | - | | `CreateMember` | `CreateMemberRequest` | `Member` | - | | `UpdateMember` | `UpdateMemberRequest` | `Member` | - | | `ValidateMembership` | `ValidateMembershipRequest` | `ValidateMembershipResponse` | - | | `GetWalletBalance` | `GetWalletBalanceRequest` | `GetWalletBalanceResponse` | - | | `AssignCard` | `AssignCardRequest` | `MemberCard` | - | ### Messages - `AssignCardRequest` - `CommunicationPreferences` - `CreateMemberRequest` - `GetMemberRequest` - `GetWalletBalanceRequest` - `GetWalletBalanceResponse` - `Member` - `MemberAddress` - `MemberCard` - `Membership` - `MemberStats` - `SearchMembersRequest` - `SearchMembersResponse` - `UpdateMemberRequest` - `ValidateMembershipRequest` - `ValidateMembershipResponse` - `WalletBalance` ### Enums - `CommunicationChannel` - `MemberStatus` --- ## pos_proxy Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/pos_proxy.proto` > E025-S01 - Contrat gRPC du proxy DB POSCommunicationSvc <-> Server.Service. > > Tous les acces BD depuis les postes passent par ce stream bidi long-lived > chiffre (4 piliers crypto D19 : mTLS + ML-DSA + ML-KEM + PSK). > Apres handshake, le poste envoie des ExecuteRequest avec un oneof typee > par operation metier (D14 plan B retenu apres spike S00). > > Aucune evaluation d'expression arbitraire cote serveur. Surface d'attaque > applicative definie par les variants du oneof, executes par des handlers > typed sous identite Postgres pos_user (D13 - vraie frontiere securite). > > Versioning : namespace stilldeep.proxy.v1.* - v2 sera un namespace separe. > ### Services #### `POSProxy` =========================================================================== Service principal - stream bidi long-lived chiffre =========================================================================== | RPC | Request | Response | Streaming | |---|---|---|---| | `Connect` | `ClientEnvelope` | `ServerEnvelope` | bidi | ### Messages - `AuthenticateUserOp` - `BootstrapData` - `BootstrapRequest` - `CancelReservationOp` - `ChangeDocumentOp` - `ChangedResource` - `ChangePasswordOp` - `ChatAskAiOp` - `ChatCancelAiOp` - `ChatGetHistoryOp` - `ChatGoOfflineOp` - `ChatGoOnlineOp` - `ChatListContactsOp` - `ChatPushCmd` - `ChatSendOp` - `ClientEnvelope` - `CloseShiftOp` - `CommandAck` - `CommandPush` - `ConfirmMemberEmailOp` - `CreateAppointmentOp` - `CreateRentalOp` - `DebitCardOp` - `DeleteSavedCartOp` - `DescribeDocumentsOp` - `Error` - `ExecuteRequest` - `ExecuteResponse` - `ExtensionDirective` - `ExtensionPackageChunk` - `ForceLogoffCmd` - `GetCatalogOp` - `GetCouponOp` - `GetDiscountsOp` - `GetDocumentOp` - `GetEventSchedulesOp` - `GetEventTicketTypesOp` - `GetExtensionPackageOp` - `GetMediaOp` - `GetMemberAccountOp` - `GetMemberByIdOp` - `GetMemberCardsOp` - `GetMemberProfileOp` - `GetPaymentMethodsOp` - `GetPostInfoOp` - `GetPrintDocumentsOp` - `GetProductOp` - `GetSavedCartOp` - `GetServiceAvailabilityOp` - `GetSettingsOp` - `GetShiftOp` - `GetShiftSummaryOp` - `GetStockLevelsOp` - `GetTaxesOp` - `GetTransactionOp` - `GetUserAccessOp` - `Handshake` - `HandshakeAck` - `HoldCartResourcesOp` - `InsertAuditLogOp` - `InsertFieldMesureOp` - `InsertFieldTextOp` - `InsertInventoryMovementOp` - `InvalidateCatalogCacheCmd` - `IssueCardOp` - `IssueCouponsOp` - `ListAccountDocumentsOp` - `ListAppointmentsOp` - `ListCategoriesOp` - `ListDocumentsOp` - `ListEventsOp` - `ListOccupiedLocationsOp` - `ListPostInputDevicesOp` - `ListPostPrintersOp` - `ListPostUsersOp` - `ListRentalsOp` - `ListSavedCartsOp` - `ListSeatLocationsOp` - `ListShiftsOp` - `LockInventoryOp` - `MediaResult` - `OpenShiftOp` - `PauseShiftOp` - `Ping` - `Pong` - `PostExtension` - `ReadAvailabilityOp` - `RechargeCardOp` - `RecordCloseDepositOp` - `RecordTaskRunOp` - `RefundTransactionOp` - `RegisterMemberAccountOp` - `ReleaseReservationOp` - `RequestMemberPasswordResetOp` - `ResetMemberPasswordOp` - `ResourcesChangedCmd` - `ResumeReservationOp` - `ResumeShiftOp` - `ReturnRentalOp` - `SaveAccountDocumentOp` - `SaveCartOp` - `SaveDocumentOp` - `SavePostInputDevicesOp` - `SavePostPrintBindingOp` - `SchemaRecoveryData` - `SchemaRecoveryRequest` - `SearchMembersOp` - `SearchProductsOp` - `SearchTransactionsOp` - `ServerEnvelope` - `SignInMemberOp` - `SignOutMemberOp` - `SubmitTransactionOp` - `SyncExtensionsOp` - `SyncExtensionsResult` - `SyncOfflineKeysOp` - `SyncOfflineKeysResult` - `UnlockInventoryOp` - `UpdateAppointmentOp` - `UpdatePostHeartbeatOp` - `UpdatePostVersionOp` - `UpdateReservationOp` - `UpsertMemberOp` - `VoidTransactionOp` - `WrappedOfflineKey` ### Enums - `ErrorCode` - `ExecuteStatus` - `ExtensionAction` - `OfflineKeyStatus` --- ## receipt Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/receipt.proto` > ReceiptService - delivrer / reimprimer / renvoyer un recu. > > Tout le rendu (PDF / ESC-POS / HTML email) est fait cote POSIntelligenceSvc. > Le POSClient ne fait que demander : pour la transaction X, format Y, canal Z. > L'Intelligence se charge de : > - rendre le contenu (i18n, taxes detaillees, branding) > - envoyer au peripherique (imprimante via DeviceService E011) > - poster dans une queue email/SMS pour les canaux differes > > Cette separation permet aux POSClient open-source (Web, Mobile, Kiosque > fork) de ne pas reimplementer le templating + drivers d'imprimante. > ### Services #### `ReceiptService` ReceiptService - emission et recherche de recus. Appele par : POSClient (apres Finalize si pas auto-emis, ecran reimpression, envoi email apres-coup), Kiosk (recu cadeau). Implementation : routee vers le pipeline de rendu interne (templates) + DeviceService (imprimante) + plugin SMTP/SMS pour les canaux differes. Codes d'erreur : NOT_FOUND (transaction), INVALID_ARGUMENT (destination manquante pour EMAIL/SMS), FAILED_PRECONDITION (imprimante pas READY), UNAVAILABLE (plugin SMTP/SMS manquant). Dependances : Transaction (SalesService), Member (CommunicationPreferences), Device (impression), EventService (publication ReceiptPrintedEvent). | RPC | Request | Response | Streaming | |---|---|---|---| | `EmitReceipt` | `EmitReceiptRequest` | `ReceiptRenderResult` | - | | `FindReceipts` | `FindReceiptsRequest` | `FindReceiptsResponse` | - | ### Messages - `EmitReceiptRequest` - `FindReceiptsRequest` - `FindReceiptsResponse` - `ReceiptRenderResult` - `ReceiptSummary` ### Enums - `ReceiptChannel` - `ReceiptFormat` --- ## rental Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/rental.proto` > RentalService : contrats de location d'articles (sortie, echeance, retour, depot). > > Une location vendue au comptoir s'ouvre a la finalisation (SalesService.AddItem avec > rental_due_at). CreateRental ouvre un contrat hors vente (reservation a venir, pret). > ### Services #### `RentalService` | RPC | Request | Response | Streaming | |---|---|---|---| | `ListRentals` | `ListRentalsRequest` | `ListRentalsResponse` | - | | `CreateRental` | `CreateRentalRequest` | `RentalResponse` | - | | `ReturnRental` | `ReturnRentalRequest` | `RentalResponse` | - | ### Messages - `CreateRentalRequest` - `ListRentalsRequest` - `ListRentalsResponse` - `Rental` - `RentalResponse` - `ReturnRentalRequest` ### Enums - `RentalScope` --- ## report Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/report.proto` > E005-S12 - ReportService : rapports operationnels in-POS. > > Pour les rapports analytiques avances (BI, dashboards complexes), utiliser > ServerReport (E008) qui consomme directement la BD. Ce service expose juste > les donnees temps-reel necessaires au caissier / manager pendant un quart. > > Aucune mutation - read-only pure. Permissions : `report.shift_summary` / > `report.top_products` / `report.cashier_productivity` (manager). > ### Services #### `ReportService` ReportService - rapports temps-reel pour le caissier / manager. Codes d'erreur : NOT_FOUND, PERMISSION_DENIED. | RPC | Request | Response | Streaming | |---|---|---|---| | `GetShiftSummary` | `GetShiftSummaryRequest` | `ShiftSummary` | - | | `GetTopProducts` | `GetTopProductsRequest` | `GetTopProductsResponse` | - | | `GetSalesByMethod` | `GetSalesByMethodRequest` | `GetSalesByMethodResponse` | - | | `GetTipSummary` | `GetTipSummaryRequest` | `TipSummary` | - | | `GetCashierProductivity` | `GetCashierProductivityRequest` | `GetCashierProductivityResponse` | - | ### Messages - `CashierProductivityEntry` - `CashierTipEntry` - `GetCashierProductivityRequest` - `GetCashierProductivityResponse` - `GetSalesByMethodRequest` - `GetSalesByMethodResponse` - `GetShiftSummaryRequest` - `GetTipSummaryRequest` - `GetTopProductsRequest` - `GetTopProductsResponse` - `PaymentMethodSummary` - `ProductSalesEntry` - `ShiftSummary` - `TipSummary` --- ## sales Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/sales.proto` > E005-S02 - SalesService : panier, paiement, finalisation. > > Service principal expose par POSIntelligenceSvc, consomme par tous les > POSClient (Reference Windows, web, kiosque, mobile). C'est le coeur du > flux vente : creation de panier -> ajout / retrait de lignes -> rabais -> > paiement -> finalisation -> recu. > > Idempotency : toute mutation expose un idempotency_key. Re-emission avec > la meme cle => meme reponse, sans effet de bord. Le serveur conserve les > cles 24h cote SQLite local. > ### Services #### `SalesService` ----- Service ----- SalesService - service principal du POS. Toutes les operations de panier, paiement et finalisation passent ici. Appele par : POSClient (Reference Windows, web, kiosque, mobile) en gRPC sur localhost (pipe HTTP/2). Aucun appel externe au LAN du client. Pre-conditions communes : un shift OPEN doit exister sur le poste pour le cashier_user_id. Sinon PERMISSION_DENIED. Les permissions par RPC sont checkees via interceptor (voir ShiftService.CheckPermission pour pre-check UI). Codes d'erreur principaux : INVALID_ARGUMENT - parametres incoherents (ex : product_id et sku tous deux vides). NOT_FOUND - cart / produit / member / transaction inexistant. FAILED_PRECONDITION - cart status incompatible (ex : Finalize sur cart VOIDED). PERMISSION_DENIED - pas de shift open, ou role insuffisant pour discount/refund. UNAUTHENTICATED - manager_auth_token invalide ou expire. ALREADY_EXISTS - re-emission detecte par idempotency_key, retour idempotent. Patterns d'usage (extraits) : * Vente cash standard : CreateCart -> AddItem* -> ProcessPayment(cash) -> FinalizeTransaction. * Split payment : CreateCart -> AddItem* -> ProcessPayment(card_p2pe partial) -> ProcessPayment(cash for rest) -> FinalizeTransaction. * Refus carte avec fallback : ProcessPayment(card) -> refus -> ResolvePaymentRefusal (FALLBACK_TO_CASH) -> ProcessPayment(cash) -> FinalizeTransaction. * Pause / reprise : SaveCart -> [client occupe autre cart] -> GetSavedCart -> ... * Reservation : AddItem* -> AssociateMember (or a rented location) -> ProcessPayment (deposit, optional) -> ReserveCart ; later ResumeReservation -> AddItem (fees) -> ProcessPayment -> ReserveCart or FinalizeTransaction ; or PreviewReservationCancellation -> CancelReservation(expected_refund). Dependances : CatalogService (resolution produit dans AddItem), MemberService (AssociateMember), CardService (AttachCard), DeviceService (impression via FinalizeTransaction), EventService (publication evenements panier). | RPC | Request | Response | Streaming | |---|---|---|---| | `CreateCart` | `CreateCartRequest` | `CartResponse` | - | | `GetCart` | `GetCartRequest` | `CartResponse` | - | | `AddItem` | `AddItemRequest` | `CartResponse` | - | | `RemoveLine` | `RemoveLineRequest` | `CartResponse` | - | | `UpdateQuantity` | `UpdateQuantityRequest` | `CartResponse` | - | | `UpdateLineNote` | `UpdateLineNoteRequest` | `CartResponse` | - | | `ListDiscounts` | `ListDiscountsRequest` | `ListDiscountsResponse` | - | | `ApplyDiscount` | `ApplyDiscountRequest` | `CartResponse` | - | | `RemoveDiscount` | `RemoveDiscountRequest` | `CartResponse` | - | | `AssociateMember` | `AssociateMemberRequest` | `CartResponse` | - | | `AttachCard` | `AttachCardRequest` | `CartResponse` | - | | `DetachCard` | `DetachCardRequest` | `CartResponse` | - | | `AttachLocation` | `AttachLocationRequest` | `CartResponse` | - | | `DetachLocation` | `DetachLocationRequest` | `CartResponse` | - | | `BeginPayment` | `BeginPaymentRequest` | `CartResponse` | - | | `ResolveInteraction` | `ResolveInteractionRequest` | `CartResponse` | - | | `SetLineMember` | `SetLineMemberRequest` | `CartResponse` | - | | `SetSubject` | `SetSubjectRequest` | `CartResponse` | - | | `SetExtensions` | `SetExtensionsRequest` | `CartResponse` | - | | `SelectPaymentMethod` | `SelectPaymentMethodRequest` | `CartResponse` | - | | `CancelPayment` | `GetCartRequest` | `CartResponse` | - | | `ProcessPayment` | `ProcessPaymentRequest` | `PaymentResponse` | - | | `ResolvePaymentRefusal` | `ResolvePaymentRefusalRequest` | `PaymentResponse` | - | | `ClearPayments` | `GetCartRequest` | `CartResponse` | - | | `FinalizeTransaction` | `FinalizeRequest` | `TransactionResponse` | - | | `CancelCart` | `GetCartRequest` | `ActionResponse` | - | | `SendToKitchen` | `SendToKitchenRequest` | `ActionResponse` | - | | `SaveCart` | `SaveCartRequest` | `SaveCartResponse` | - | | `ListSavedCarts` | `ListSavedCartsRequest` | `ListSavedCartsResponse` | - | | `GetSavedCart` | `GetSavedCartRequest` | `CartResponse` | - | | `DeleteSavedCart` | `DeleteSavedCartRequest` | `ActionResponse` | - | | `SearchTransactions` | `SearchTransactionsRequest` | `SearchTransactionsResponse` | - | | `GetTransaction` | `GetTransactionRequest` | `TransactionResponse` | - | | `RefundTransaction` | `RefundTransactionRequest` | `TransactionResponse` | - | | `ReserveCart` | `ReserveCartRequest` | `ReserveCartResponse` | - | | `ListReservations` | `ListReservationsRequest` | `ListReservationsResponse` | - | | `ResumeReservation` | `ResumeReservationRequest` | `CartResponse` | - | | `ReleaseReservation` | `ReleaseReservationRequest` | `ActionResponse` | - | | `PreviewReservationCancellation` | `CancelReservationRequest` | `ReservationCancellationResponse` | - | | `CancelReservation` | `CancelReservationRequest` | `ReservationCancellationResponse` | - | ### Messages - `AddItemRequest` - `AppliedDiscount` - `AppliedTax` - `ApplyDiscountRequest` - `AssociateMemberRequest` - `AttachCardRequest` - `AttachLocationRequest` - `BeginPaymentRequest` - `CancelReservationRequest` - `Cart` - `CartLine` - `CartReservation` - `CartResponse` - `CreateCartRequest` - `DeleteSavedCartRequest` - `DetachCardRequest` - `DetachLocationRequest` - `DiscountCatalogEntry` - `FinalizeRequest` - `GetCartRequest` - `GetSavedCartRequest` - `GetTransactionRequest` - `Interaction` - `InteractionChoice` - `ListDiscountsRequest` - `ListDiscountsResponse` - `ListReservationsRequest` - `ListReservationsResponse` - `ListSavedCartsRequest` - `ListSavedCartsResponse` - `Notice` - `Payment` - `PaymentRefusalGuide` - `PaymentResponse` - `ProcessPaymentRequest` - `RefundLineSelection` - `RefundSeat` - `RefundTransactionRequest` - `ReleaseReservationRequest` - `RemoveDiscountRequest` - `RemoveLineRequest` - `Reservation` - `ReservationCancellationResponse` - `ReservationKeptLine` - `ReservationRefund` - `ReserveCartRequest` - `ReserveCartResponse` - `ResolveInteractionRequest` - `ResolvePaymentRefusalRequest` - `ResumeReservationRequest` - `SaveCartRequest` - `SaveCartResponse` - `SavedCart` - `SearchTransactionsRequest` - `SearchTransactionsResponse` - `SelectPaymentMethodRequest` - `SendToKitchenRequest` - `SetExtensionsRequest` - `SetLineMemberRequest` - `SetSubjectRequest` - `Transaction` - `TransactionLine` - `TransactionResponse` - `TransactionSummary` - `UpdateLineNoteRequest` - `UpdateQuantityRequest` ### Enums - `CartStatus` - `DiscountKind` - `DiscountSource` - `DiscountTiming` - `InteractionKind` - `InteractionTargetKind` - `NoticeLevel` - `PaymentStatus` - `RefusalAction` --- ## scheduling Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/scheduling.proto` > SchedulingService: scheduled ticketing (cinema, theatre, conference). > > ScheduledEvent ("Dune Part 3") -> EventSchedule (showing "Friday 7 pm, hall 4") > -> EventTicketType ("Adult", "Student", "VIP"). > A seat is a seat location (product_location.location_kind = 'seat'); seat_id is its product id. > The client draws the hall itself. > ### Services #### `SchedulingService` ----- Service ----- SchedulingService - scheduled ticketing: events, showings, ticket types, seats. Seats and capacities are the server's. HoldSeat holds a seat on the server for an open SalesService cart until expires_at (renewed while the cart lives), ReleaseSeat or a cancelled cart gives it back. Other posts' changes are not pushed: read GetSeatMap / GetSchedules again. SalesService.AddItem carries no showing nor seats yet: a held seat is not sold here. Errors: NOT_FOUND (cart_not_found, hold_not_found), FAILED_PRECONDITION (seat_taken, resource_invalid), INVALID_ARGUMENT. | RPC | Request | Response | Streaming | |---|---|---|---| | `ListEvents` | `ListEventsRequest` | `ListEventsResponse` | - | | `GetSchedules` | `GetSchedulesRequest` | `GetSchedulesResponse` | - | | `GetTicketTypes` | `GetTicketTypesRequest` | `GetTicketTypesResponse` | - | | `GetSeatMap` | `GetSeatMapRequest` | `GetSeatMapResponse` | - | | `HoldSeat` | `HoldSeatRequest` | `HoldSeatResponse` | - | | `ReleaseSeat` | `ReleaseSeatRequest` | `ActionResponse` | - | ### Messages - `EventSchedule` - `EventTicketType` - `GetSchedulesRequest` - `GetSchedulesResponse` - `GetSeatMapRequest` - `GetSeatMapResponse` - `GetTicketTypesRequest` - `GetTicketTypesResponse` - `HoldSeatRequest` - `HoldSeatResponse` - `ListEventsRequest` - `ListEventsResponse` - `ReleaseSeatRequest` - `ScheduledEvent` - `Seat` ### Enums - `SeatStatus` --- ## shift Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/shift.proto` > ShiftService - cycle de vie d'un quart de travail. > > Etats : open -> paused -> open -> ... -> closed -> reconciled. > Invariants : > * 1 user = 1 shift open max (cross-poste). Tentative double-open = FAILED_PRECONDITION. > * 1 poste = 1 shift open max. > * Cashier-less posts (default_user_id + is_always_open or post_type.has_shift=false): the server opens > the shift on demand as default_user_id and rolls it at business_day_cutoff. The UI never calls Open/Close. > > Fermeture : on declare un montant depose pour chaque payment_method dont > deposit_at_close=true (cash typique). Si aucune vente -> close direct sans > dialog (no-op deposit). > ### Services #### `ShiftService` ShiftService - gestion du quart de travail. Appele par : POSClient (open au login, close au logout), tous les services SalesService/Device/etc. via interceptor pour validation permissions, et UI pour pre-validation de boutons. Patterns d'usage : * Login : UserService.Authenticate -> OpenShift. * Pause repas : PauseShift -> ResumeShift. * Fin de journee : CloseShift avec declared_deposits par methode. Codes d'erreur : NOT_FOUND, FAILED_PRECONDITION (deja open / not open), PERMISSION_DENIED, ALREADY_EXISTS (idempotency). Dependances : UserService (auth), publication ShiftOpenedEvent / ShiftPausedEvent / ShiftResumedEvent / ShiftClosedEvent via EventService. | RPC | Request | Response | Streaming | |---|---|---|---| | `OpenShift` | `OpenShiftRequest` | `OpenShiftResponse` | - | | `PauseShift` | `PauseShiftRequest` | `Shift` | - | | `ResumeShift` | `ResumeShiftRequest` | `Shift` | - | | `CloseShift` | `CloseShiftRequest` | `CloseShiftResponse` | - | | `GetCurrentShift` | `GetCurrentShiftRequest` | `Shift` | - | | `ListShifts` | `ListShiftsRequest` | `ListShiftsResponse` | - | | `CheckPermission` | `CheckPermissionRequest` | `CheckPermissionResponse` | - | ### Messages - `CheckPermissionRequest` - `CheckPermissionResponse` - `CloseShiftRequest` - `CloseShiftResponse` - `DeclaredDeposit` - `GetCurrentShiftRequest` - `ListShiftsRequest` - `ListShiftsResponse` - `OpenShiftRequest` - `OpenShiftResponse` - `PauseShiftRequest` - `ResumeShiftRequest` - `Shift` - `ShiftDeposit` - `ShiftPause` ### Enums - `ShiftStatus` --- ## sync Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/sync.proto` > E005-S13 - SyncService : synchronisation outbox + sante reseau du poste. > > Le poste maintient une SQLite locale + une outbox des mutations. Quand > la connexion vers ServerDB Postgres est restauree, le worker drain > l'outbox. Ce service permet au UI de : > * voir l'etat de la sync (online/degraded/offline + outbox count) > * forcer un drain manuel (ex : caissier qui voit 200 messages en attente) > * monitorer la sante reseau (latence vers ServerDB) > ### Services #### `SyncService` SyncService - lecture / pilotage de la sync. Appele par : POSClient (indicateur connexion + bouton "Force resync"), ServerAdmin (vue dashboard postes en ligne). Codes d'erreur : PERMISSION_DENIED (force_drain), UNAVAILABLE (worker sync arrete - cas degenere). | RPC | Request | Response | Streaming | |---|---|---|---| | `GetSyncStatus` | `GetSyncStatusRequest` | `SyncStatus` | - | | `GetOutboxCount` | `GetOutboxCountRequest` | `GetOutboxCountResponse` | - | | `ForceDrain` | `ForceDrainRequest` | `ForceDrainResponse` | - | ### Messages - `ForceDrainRequest` - `ForceDrainResponse` - `GetOutboxCountRequest` - `GetOutboxCountResponse` - `GetSyncStatusRequest` - `SyncStatus` ### Enums - `SyncState` --- ## user Fichier source : `src/public/StillDeep.Intelligence.Contracts/protos/user.proto` > UserService - authentification (mode password ou scan id) + lecture > post auth modes acceptes + idle timeout. > > Plugins (RFID, magstripe, scanner exotique) ne s'integrent PAS dans cet > API : ils injectent localement un "barcode" ou "credential string" via > l'event bus du POSClient (ScanReceivedEvent), et ce dernier appelle > Authenticate avec le mode "barcode" + le credential. Le service ne sait > pas d'ou vient le code - il sait juste qu'il a recu un identifier a > resoudre. > ### Services #### `UserService` UserService - authentification et lookup users. Appele par : POSClient (login screen, dropdown selection user), tous les RPC qui acceptent un manager_auth_token (override discount, refund, etc.). Codes d'erreur : INVALID_ARGUMENT (mode non accepte par le poste, login vide), UNAUTHENTICATED (credentials invalides), PERMISSION_DENIED (user suspended/locked/deactivated), NOT_FOUND (post_id inconnu). Dependances : ServerDB pour stockage users (Postgres), publication ShiftOpenedEvent indirectement via OpenShift. | RPC | Request | Response | Streaming | |---|---|---|---| | `ListUsersForPost` | `ListUsersForPostRequest` | `ListUsersForPostResponse` | - | | `GetPostAuthConfig` | `GetPostAuthConfigRequest` | `PostAuthConfig` | - | | `Authenticate` | `AuthenticateRequest` | `AuthenticateResponse` | - | | `ResetPasswordEmail` | `ResetPasswordEmailRequest` | `ResetPasswordEmailResponse` | - | | `ResetPasswordAutoGenerate` | `ResetPasswordAutoGenerateRequest` | `ResetPasswordAutoGenerateResponse` | - | | `ChangePassword` | `ChangePasswordRequest` | `ChangePasswordResponse` | - | ### Messages - `AuthenticateRequest` - `AuthenticateResponse` - `ChangePasswordRequest` - `ChangePasswordResponse` - `GetPostAuthConfigRequest` - `ListUsersForPostRequest` - `ListUsersForPostResponse` - `PostAuthConfig` - `ResetPasswordAutoGenerateRequest` - `ResetPasswordAutoGenerateResponse` - `ResetPasswordEmailRequest` - `ResetPasswordEmailResponse` - `UserSummary` ### Enums - `AuthMode` --- ## Comment appeler ```bash # Lister les services via reflection grpcurl -plaintext localhost:50051 list # Lister les RPCs d'un service grpcurl -plaintext localhost:50051 list stilldeep.v1.CatalogService # Decrire un message grpcurl -plaintext localhost:50051 describe stilldeep.v1.Cart # Appeler un RPC grpcurl -plaintext -d '{"query":"kind:boutique"}' localhost:50051 stilldeep.v1.CatalogService/SearchProducts ``` ## Endpoints REST associes | URL | Description | |---|---| | `http://localhost:5050/healthz` | Healthcheck Docker (HTTP/1.1) | | `http://localhost:5051/grpc-info` | Manifeste JSON dynamique des services + RPCs | | `http://localhost:5051/swagger` | Swagger UI (description seule en V1, transcoding live attendra .NET 11 GA) | | `http://localhost:5051/swagger/v1/swagger.json` | OpenAPI JSON minimal | Source: https://stilldeeppos.com/fr/docs/reference/grpc --- > Index de la documentation : https://stilldeeppos.com/fr/llms.txt # SDK StillDeep — Generer un POSClient dans n'importe quel langage > **E005 livre les contrats `.proto`. Ce guide explique comment generer un client.** > Pour la reference WinForms .NET, voir `docs/client-reference.md`. ## Vue d'ensemble Tout client UI POS dialogue avec `POSIntelligenceSvc` via **gRPC HTTP/2 sur `localhost:50051`** (defaut). L'API publique stable est composee de cinq services : | Service | Description | .proto | |---------|-------------|--------| | `SalesService` | panier, paiement, finalisation | `sales.proto` | | `CatalogService` | produits, categories, taxes | `catalog.proto` | | `MemberService` | members, memberships, wallets | `member.proto` | | `DeviceService` | imprimantes, scanners, terminaux | `device.proto` | | `EventService` | streaming temps reel des events de vente | `events.proto` | Tous partagent les types definis dans `common.proto` (Money, Quantity, Percentage, Pagination, ...). ### Conventions imposees - Namespace `stilldeep.v1.*` — un eventuel V2 sera un namespace separe (jamais de breaking change V1). - Montants : **`Money` avec `int64 cents`** (jamais `double` / `float`, regle R14). - Pourcentages : **`Percentage` en basis points** (1/1_000_000). - Quantites fractionnaires : **`Quantity` en milli_units** (1 unite = 1000). - Timestamps : `google.protobuf.Timestamp` (UTC). - Erreurs : `google.rpc.Status` avec `ErrorDetail` dans `details[]`. ## Recuperer les `.proto` Le code de StillDeep est prive ; le contrat des clients est public et versionne. Le site officiel publie ses `.proto` (`stilldeep.v1`, tous sauf `pos_proxy.proto`, reserve aux postes et a Server.Service) en une archive : `/downloads/stilldeep-contracts.zip`. Les clients .NET prennent le NuGet `StillDeep.Intelligence.Contracts`. ```bash curl -fsSLO https:///downloads/stilldeep-contracts.zip unzip stilldeep-contracts.zip && cp -r stilldeep-contracts/protos ./protos ``` ## Guides par langage | Langage | Guide | |---------|-------| | TypeScript / Node.js | [`typescript.md`](typescript.md) | | Python 3 | [`python.md`](python.md) | | Go | [`go.md`](go.md) | | .NET | utiliser le NuGet `StillDeep.Intelligence.Contracts` directement | Les autres langages supportes par gRPC officiel (Java, Kotlin, C++, Rust, Ruby, PHP, Dart, Swift) suivent le meme pattern : `protoc --proto_path=./protos --_out=./generated protos/*.proto`. ## Versioning - **Pas de breaking change V1.** Tout nouveau champ est ajoute en `optional` proto3. - Un champ ne sera **jamais retire** avant 2 versions majeures en mode deprecated. - Si vous avez besoin d'une rupture, c'est un `stilldeep.v2.*` separe. Voir [`E005`](../epics/E005-grpc-contracts.md) pour le contrat complet. Source: https://stilldeeppos.com/fr/docs/reference/sdk --- > Index de la documentation : https://stilldeeppos.com/fr/llms.txt # SDK StillDeep — Client TypeScript / Node.js ## Prerequis - Node.js 22 LTS+ - `protoc` 25+ - Plugin `protoc-gen-ts` (`npm i -D ts-proto`) ## Setup ```bash mkdir my-pos-client && cd my-pos-client npm init -y npm i @grpc/grpc-js @grpc/proto-loader npm i -D typescript ts-proto @types/node cp -r ../waxpos/src/public/StillDeep.Intelligence.Contracts/protos ./protos mkdir -p src/generated protoc \ --plugin=./node_modules/.bin/protoc-gen-ts_proto \ --ts_proto_out=./src/generated \ --ts_proto_opt=outputServices=grpc-js,esModuleInterop=true \ --proto_path=./protos \ protos/common.proto protos/sales.proto protos/catalog.proto \ protos/member.proto protos/device.proto protos/events.proto ``` ## Exemple : ouvrir un panier + ajouter un produit ```ts import { credentials, ChannelCredentials } from '@grpc/grpc-js'; import { SalesServiceClient } from './generated/sales'; const client = new SalesServiceClient( 'localhost:50051', credentials.createInsecure(), ); const cart = await new Promise((resolve, reject) => client.createCart( { postId: 'post-1', cashierUserId: 'user-1', idempotencyKey: crypto.randomUUID() }, (err, res) => err ? reject(err) : resolve(res), ), ); console.log('Cart:', cart); ``` ## Stream des events ```ts import { EventServiceClient } from './generated/events'; const events = new EventServiceClient('localhost:50051', credentials.createInsecure()); const stream = events.subscribe({ subscriberId: 'tablet-1', kinds: [], postIdFilter: 'post-1' }); stream.on('data', (ev) => console.log('event', ev)); stream.on('error', (e) => console.error(e)); ``` ## Limitations connues V1 - Pas de TLS par defaut (insecure local). Sur reseau, ajouter un cert. - Pas de retry policy automatique cote client — au consommateur de l'implementer. - `EventService.Heartbeat` (bidi streaming) est supporte mais peu utilise — preferer `Subscribe` pour la plupart des cas. Source: https://stilldeeppos.com/fr/docs/reference/sdk/typescript --- > Index de la documentation : https://stilldeeppos.com/fr/llms.txt # SDK StillDeep — Client Python ## Prerequis - Python 3.11+ - `pip install grpcio grpcio-tools` ## Setup ```bash mkdir my-pos-client && cd my-pos-client python -m venv .venv && source .venv/bin/activate # Windows : .venv\Scripts\activate pip install grpcio grpcio-tools cp -r ../waxpos/src/public/StillDeep.Intelligence.Contracts/protos ./protos mkdir generated python -m grpc_tools.protoc \ -I./protos \ --python_out=./generated \ --grpc_python_out=./generated \ ./protos/common.proto ./protos/sales.proto ./protos/catalog.proto \ ./protos/member.proto ./protos/device.proto ./protos/events.proto ``` ## Exemple ```python import uuid import grpc import sys; sys.path.insert(0, './generated') import sales_pb2, sales_pb2_grpc with grpc.insecure_channel('localhost:50051') as channel: stub = sales_pb2_grpc.SalesServiceStub(channel) resp = stub.CreateCart(sales_pb2.CreateCartRequest( post_id='post-1', cashier_user_id='user-1', idempotency_key=str(uuid.uuid4()), )) print(resp) ``` ## Stream des events ```python import events_pb2, events_pb2_grpc with grpc.insecure_channel('localhost:50051') as channel: stub = events_pb2_grpc.EventServiceStub(channel) for ev in stub.Subscribe(events_pb2.SubscribeRequest(subscriber_id='kiosk-1')): print(ev.WhichOneof('payload'), ev) ``` Source: https://stilldeeppos.com/fr/docs/reference/sdk/python --- > Index de la documentation : https://stilldeeppos.com/fr/llms.txt # SDK StillDeep — Client Go ## Prerequis - Go 1.23+ - `protoc` 25+ - Plugins : `protoc-gen-go`, `protoc-gen-go-grpc` ```bash go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest ``` ## Setup ```bash mkdir my-pos-client && cd my-pos-client go mod init example.com/my-pos-client go get google.golang.org/grpc google.golang.org/protobuf cp -r ../waxpos/src/public/StillDeep.Intelligence.Contracts/protos ./protos mkdir -p generated protoc \ --proto_path=./protos \ --go_out=./generated \ --go_opt=paths=source_relative \ --go-grpc_out=./generated \ --go-grpc_opt=paths=source_relative \ ./protos/common.proto ./protos/sales.proto ./protos/catalog.proto \ ./protos/member.proto ./protos/device.proto ./protos/events.proto ``` ## Exemple ```go package main import ( "context" "log" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" pb "example.com/my-pos-client/generated" ) func main() { conn, err := grpc.NewClient("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Fatal(err) } defer conn.Close() client := pb.NewSalesServiceClient(conn) cart, err := client.CreateCart(context.Background(), &pb.CreateCartRequest{ PostId: "post-1", CashierUserId: "user-1", IdempotencyKey: "key-1", }) if err != nil { log.Fatal(err) } log.Printf("%+v", cart) } ``` Source: https://stilldeeppos.com/fr/docs/reference/sdk/go