Back to Projects

Tasyir Pro

A multi-tenant retail SaaS that takes a shop from supplier purchase to legal invoice — catalogue, stock, point of sale and payments, in French, Arabic and English.

Current2026

Duration

May 2026 – Present

Contributors

3 contributors

Technologies

10+ tech

Tasyir Pro

Project Overview

Small retailers in Morocco often run on spreadsheets, paper receipt books and a separate invoicing tool. Tasyir Pro replaces all three with one application covering the whole cycle: supplier purchases set cost and sell prices, the point of sale scans barcodes and enforces stock and discount rules, payments cover cash, card, transfer, cheques and customer credit, and validated sales become delivery notes, invoices and credit notes in an unbroken legal sequence. One installation hosts many shops, and isolation is enforced in the data layer — every query is scoped to the current shop and the database itself rejects links across shops — instead of relying on each query to filter correctly. The current version is a full rebuild of the first release, shaped by a client's day-to-day requirements: configurable pricing strategies, a discount cap a cashier can't exceed but a manager can override, decimal quantities and no negative stock. Each resource is declared once, and its lists, search, forms and printed documents are generated from that declaration. Available in French, Arabic (right-to-left) and English.

Features

  • ✓Multi-tenant by construction — shop data goes through a tenant-scoped Prisma client that adds the shop to every query, and composite keys make the database reject links across shops
  • ✓Catalogue with variants and codes — every variant is a full sellable product, with several QR or EAN codes per product and SKUs generated from a configurable pattern
  • ✓Purchasing — supplier purchases with HT/TTC lines, supplier discounts, weighted average cost and configurable pricing strategies that set the sell price
  • ✓Sales and POS — barcode scanning (including a phone used as a wireless scanner), a capped customer discount with logged manager override, and stock that can never go negative
  • ✓Payments — cash, card, transfer, cheque and customer credit, with allocations, per-customer credit limits and reminders for cheques coming due
  • ✓Legal invoicing — delivery notes, invoices and credit notes numbered from an unbroken per-series yearly sequence, grouped invoices, and frozen legal mentions (ICE, IF, RC, Patente)
  • ✓Resource framework — one declaration per resource drives paginated lists, simple and advanced search, full-page forms, internal comments with attachments and printed fields
  • ✓French, Arabic (RTL) and English across the app and its PDF documents

Challenges

  • •Guaranteeing that one shop can never read or link another shop's data, even through a forgotten filter
  • •Keeping invoice numbers in an unbroken legal sequence while still allowing backdated sales and concurrent validations
  • •Handling money and decimal quantities without floating-point drift across purchases, discounts, taxes and totals
  • •Rebuilding the application from a prototype without stalling delivery to a client already waiting to run their shop on it

Solution

Moved tenancy out of individual queries into the data layer: repositories only ever receive a Prisma client scoped to the current shop, the unscoped client refuses tenant models, and lint rules stop the rest of the code from importing the database at all. Invoice, delivery note and credit note numbers come from an atomic per-shop sequence per series and year, and validation refuses any date earlier than the last validated document in the series. All money goes through decimal.js with explicit scales and rounding — never floating point. The v2 rebuild was split into small, client-validated steps (resource framework, catalogue, purchasing, sales, legal documents), reusing the proven parts of v1 such as the tax helpers, scan de-duplication and PDF components.

Architecture

A Next.js App Router application organised in feature modules: route handlers and server actions call a module's service, the service holds business rules, permissions and transactions, and only its repository talks to Prisma. Repositories receive a tenant-scoped client that injects the shop into every query, backed by composite (shopId, id) keys in PostgreSQL. Each resource is declared once in a fields file from which validation schemas, search, lists and print layouts are derived. Documents are rendered to PDF in French, Arabic and English, files are stored in Vercel Blob, and rate limiting runs on Upstash Redis.

Results & Impact

  • ✓Live at tasyirpro.com, shaped by the day-to-day requirements of a real client shop
  • ✓Rebuilt from the first release in small, client-validated steps on a modular, tenant-safe architecture
  • ✓Invoicing built for Moroccan shops — unbroken yearly numbering, credit notes, and ICE, IF, RC and Patente frozen on every invoice
Technologies

Frontend

Next.jsReactTypeScriptTailwind CSSRadix UInext-intl

Backend

Next.js Route HandlersServer ActionsPrismaZodReact PDF

Database

PostgreSQLUpstash RedisVercel Blob

Tools

VitestDockerGitHub ActionsVerceldecimal.js
License
Proprietary

All rights reserved. Not open source.

Project Tags
Next.jsReactTypeScriptPostgreSQLPrismaTailwind CSSnext-intlMulti-tenantSaaSVercel

More Projects

ngx-auth-client
2026Current
A published npm package that exposes Angular authentication as signals instead of getters, ships a Keycloak adapter behind a provider-agnostic port, and keeps tokens out of localStorage entirely.
AngularTypeScriptKeycloak+6
ngx-api-client
2026Current
A published npm package extracted from the same api.service.ts I had copied across four Angular projects — configurable versioning, RFC 9457 error normalization, retry with backoff, and zero UI dependencies.
AngularTypeScriptRxJS+5