Skip to content

Functional Reactive Purescript Deku/Hyrule PoS System for Cannabis Dispensaries

Notifications You must be signed in to change notification settings

harryprayiv/cheeblr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

478 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Cheeblr: Cannabis Dispensary Management System

A full-stack cannabis dispensary point-of-sale and inventory management system built with PureScript (frontend) and Haskell (backend) on PostgreSQL β€” emphasizing type safety, functional programming, and reproducible builds via Nix.

License

πŸ“š Documentation

🌟 Features

Inventory Management

  • Comprehensive Product Tracking: Detailed cannabis product data including strain lineage, THC/CBD content, terpene profiles, species classification, and Leafly integration
  • Real-Time Inventory Reservations: Items are reserved when added to a transaction cart, preventing overselling during concurrent sessions. Reservations are released on item removal or transaction cancellation, and committed on finalization
  • Role-Based Access Control: Dev-mode auth system with four roles (Customer, Cashier, Manager, Admin) and 15 granular capabilities governing inventory CRUD, transaction processing, register management, and reporting access
  • Flexible Sorting & Filtering: Multi-field priority sorting (quantity, category, species) with configurable sort order and optional out-of-stock hiding
  • Complete CRUD Operations: Create, read, update, and delete inventory items with full strain lineage data

Point-of-Sale System

  • Full Transaction Lifecycle: Create β†’ add items (with reservation) β†’ add payments β†’ finalize (commits inventory) or clear (releases reservations)
  • Parallel Data Loading: The POS page loads inventory, initializes the register, and starts a transaction concurrently using the frontend's parallel/sequential pattern
  • Multiple Payment Methods: Cash, credit, debit, ACH, gift card, stored value, mixed, and custom payment types with change calculation
  • Tax Management: Per-item tax records with category tracking (regular sales, excise, cannabis, local, medical)
  • Discount Support: Percentage-based, fixed amount, BOGO, and custom discount types with approval tracking
  • Automatic Total Recalculation: Server-side recalculation of subtotals, taxes, discounts, and totals on item/payment changes

Financial Operations

  • Cash Register Management: Open registers with starting cash, close with counted cash and automatic variance calculation
  • Register Persistence: Register IDs stored in localStorage, auto-recovered on page load via get-or-create pattern
  • Transaction Modifications: Void (marks existing transaction) and refund (creates inverse transaction with negated amounts) operations with reason tracking
  • Payment Status Tracking: Transaction status auto-updates based on payment coverage (payments β‰₯ total β†’ Completed)

Compliance Infrastructure

  • Customer Verification Types: Age verification, medical card, ID scan, visual inspection, patient registration, purchase limit check
  • Compliance Records: Per-transaction compliance tracking with verification status, state reporting status, and reference IDs
  • Reporting Stubs: Compliance and daily financial report endpoints defined with types β€” implementation pending

πŸ”§ Technology Stack

Frontend

Concern Technology
Language PureScript β€” strongly-typed FP compiling to JavaScript
UI Deku β€” declarative, hooks-based rendering with Nut as the renderable type
State FRP.Poll β€” reactive streams with create/push for mutable cells
Routing Routing.Duplex + Routing.Hash β€” hash-based client-side routing
HTTP purescript-fetch with Yoga.JSON for serialization
Money Data.Finance.Money β€” Discrete USD (integer cents) with formatting
Async Effect.Aff with run helper, parSequence_, killFiber for route-driven loading
Parallelism Control.Parallel β€” concurrent data fetching within a single route

Backend

Concern Technology
Language Haskell
API Servant β€” type-level REST API definitions
Database postgresql-simple with sql quasiquoter, resource-pool for connection management
Server Warp
JSON Aeson (derived + manual instances)
Auth Dev-mode X-User-Id header lookup with role-based capabilities

Infrastructure

Concern Technology
Database PostgreSQL with reservation-based inventory, cascading deletes, parameterized queries
Dev Environment Nix flakes for reproducible builds
Build (Haskell) Cabal
Build (PureScript) Spago
Database Service NixOS systemd integration

πŸš€ Getting Started

Prerequisites

Development Setup

git clone https://github.com/harryprayiv/cheeblr.git
cd cheeblr
nix develop
deploy

This launches the full development stack: PostgreSQL service, backend API server (port 8080), and frontend dev server (port 5174).

API Overview

Inventory

Method Endpoint Description
GET /inventory All items with available quantities and user capabilities
POST /inventory Create item (Manager+)
PUT /inventory Update item (Cashier+)
DELETE /inventory/:sku Delete item (Manager+)
GET /inventory/available/:sku Real-time availability (total, reserved, actual)
POST /inventory/reserve Reserve inventory for a transaction
DELETE /inventory/release/:id Release a reservation

Transactions

Method Endpoint Description
GET /transaction List all transactions
GET /transaction/:id Get transaction with items and payments
POST /transaction Create transaction
PUT /transaction/:id Update transaction
POST /transaction/void/:id Void with reason
POST /transaction/refund/:id Create inverse refund transaction
POST /transaction/item Add item (checks availability, creates reservation)
DELETE /transaction/item/:id Remove item (releases reservation)
POST /transaction/payment Add payment
DELETE /transaction/payment/:id Remove payment
POST /transaction/finalize/:id Finalize (commits inventory, completes reservations)
POST /transaction/clear/:id Clear all items/payments, release reservations

Registers

Method Endpoint Description
GET /register List registers
GET /register/:id Get register
POST /register Create register
POST /register/open/:id Open with starting cash
POST /register/close/:id Close with counted cash, returns variance

πŸ— Architecture

Frontend Architecture

The frontend follows a centralized async loading pattern inspired by purescript-deku-realworld:

  • Main.purs owns all async data fetching, route matching, and fiber lifecycle management
  • Pages are pure renderers: Poll Status β†’ Nut β€” no side effects, no launchAff_, no Poll.create
  • Route changes cancel in-flight loading via killFiber on the previous fiber
  • parSequence_ runs multiple loaders in parallel per route
  • Status ADTs per page (Loading | Ready data | Error msg) provide type-safe loading states
  • pure Loading <|> poll ensures pages always start with a loading state
Main.purs (orchestration)
  β”œβ”€β”€ Route matcher β†’ killFiber prev β†’ parSequence_ loaders β†’ build page Nut
  β”œβ”€β”€ Loading functions: loadInventoryStatus, loadEditItem, loadDeleteItem, loadTxPageData
  └── Callback-to-Aff wrappers (makeAff) for RegisterService integration

Pages/ (pure renderers)
  β”œβ”€β”€ LiveView:           Poll InventoryLoadStatus β†’ Nut
  β”œβ”€β”€ EditItem:           Poll EditItemStatus β†’ Nut
  β”œβ”€β”€ DeleteItem:         Poll DeleteItemStatus β†’ Nut
  β”œβ”€β”€ CreateTransaction:  Poll TxPageStatus β†’ Nut (parallel: inventory + register + tx)
  β”œβ”€β”€ CreateItem:         UserId β†’ String β†’ Nut (no async needed)
  └── TransactionHistory: Nut (placeholder)

Backend Architecture

App.hs (bootstrap, CORS, middleware)
  β”œβ”€β”€ Server.hs (inventory handlers with capability checks)
  β”œβ”€β”€ Server/Transaction.hs (POS: transactions, registers, ledger, compliance)
  β”œβ”€β”€ Auth/Simple.hs (dev auth: X-User-Id β†’ role β†’ capabilities)
  β”œβ”€β”€ DB/Database.hs (inventory CRUD, connection pooling)
  β”œβ”€β”€ DB/Transaction.hs (transactions, reservations, registers, payments)
  └── Types/ (domain models with Aeson + postgresql-simple instances)

Data Flow

  1. Item Selection: User adds item β†’ backend checks quantity - reserved β†’ creates reservation β†’ returns item
  2. Cart Management: Items tracked via transaction items table β†’ server recalculates totals on each change
  3. Payment Processing: Payments added β†’ server checks if payments β‰₯ total β†’ auto-updates status
  4. Finalization: menu_items.quantity decremented β†’ reservations marked Completed β†’ transaction COMPLETED
  5. Cancellation: POST /transaction/clear/:id β†’ reservations Released β†’ items/payments deleted β†’ totals zeroed

Database Schema

Table Purpose
menu_items Product catalog with stock quantities
strain_lineage Cannabis-specific attributes (THC, terpenes, lineage) β€” FK to menu_items
transaction Transaction records with status, totals, void/refund tracking
transaction_item Line items β€” FK to transaction with CASCADE
transaction_tax Per-item tax records β€” FK to transaction_item with CASCADE
discount Discounts on items or transactions β€” FK with CASCADE
payment_transaction Payment records β€” FK to transaction with CASCADE
inventory_reservation Reservation tracking (Reserved β†’ Completed/Released)
register Cash register state and history

πŸ” Security

  • Parameterized queries throughout β€” no string interpolation in SQL
  • Type safety across the full stack β€” shared domain types between PureScript and Haskell
  • Role-based capabilities β€” 15 granular permissions mapped to 4 roles, enforced on inventory writes
  • Input validation β€” frontend (ValidationRule combinators) and backend (type-level constraints via Servant)
  • Audit trail β€” transactions track void/refund reasons, reference transactions, and modification timestamps

Current limitation: Authentication is dev-mode only (X-User-Id header with fixed users). See Security Recommendations for the planned upgrade path.

🚧 Development Status

Implemented

  • βœ… Full inventory CRUD with strain lineage
  • βœ… Inventory reservation system (reserve on cart add, release on remove, commit on finalize)
  • βœ… Complete transaction lifecycle (create β†’ items β†’ payments β†’ finalize/void/refund/clear)
  • βœ… Multiple payment methods with change calculation
  • βœ… Cash register open/close with variance tracking
  • βœ… Tax and discount record management
  • βœ… Role-based capability system (4 roles, 15 capabilities)
  • βœ… Dev auth with X-User-Id header and user switcher widget
  • βœ… Centralized async loading with fiber cancellation on route change
  • βœ… Parallel data loading for POS page (inventory + register + transaction)
  • βœ… InventoryResponse includes user capabilities for frontend UI gating

In Progress

  • πŸ”„ Daily financial reporting (endpoints exist, implementation pending)
  • πŸ”„ Compliance verification system (types and stubs defined)

Planned

  • πŸ“‹ Real authentication (JWT or session-based, replacing dev X-User-Id header)
  • πŸ“‹ Capability enforcement on transaction/register endpoints
  • πŸ“‹ Inventory reservation expiry (cleanup of abandoned reservations)
  • πŸ“‹ Transaction history page (currently a placeholder)
  • πŸ“‹ Advanced reporting and analytics
  • πŸ“‹ Multi-location support
  • πŸ“‹ Third-party integrations (Metrc, Leafly)
  • πŸ“‹ Auto-refresh/polling for live inventory view

πŸ“œ License

This project is licensed under the MIT License β€” see the LICENSE file for details.

🀝 Contributing

Contributions are welcome. Please feel free to submit a Pull Request.

About

Functional Reactive Purescript Deku/Hyrule PoS System for Cannabis Dispensaries

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors