Skip to content

Claude/alshuyukh accounting saas uf09e2 - #26269

Closed
nwfynnaa99-cpu wants to merge 10 commits into
docker:mainfrom
nwfynnaa99-cpu:claude/alshuyukh-accounting-saas-uf09e2
Closed

nwfynnaa99-cpu wants to merge 10 commits into
docker:mainfrom
nwfynnaa99-cpu:claude/alshuyukh-accounting-saas-uf09e2

Conversation

@nwfynnaa99-cpu

Copy link
Copy Markdown

Description

Related issues or tickets

Reviews

  • Technical review
  • Editorial review
  • Product review

claude added 10 commits October 3, 2026 18:53
Foundation for a Saudi multi-tenant accounting SaaS, built in a separate
alshuyukh-accounting/ folder so the existing docs site is untouched.

- PostgreSQL schema with migrations: tenants, settings, users,
  memberships, sessions, roles, permissions, companies, branches,
  warehouses, append-only audit log
- Tenant isolation in three layers: app-level tenant filters,
  Row-Level Security under a non-privileged DB role, and composite
  (id, tenant_id) foreign keys
- Auth: argon2id, short-lived JWT, rotating refresh token in an
  HttpOnly cookie with reuse detection, account lockout, CSRF header
- RBAC catalog with 45 permissions and 9 system roles, custom roles,
  and privilege-escalation checks
- Arabic RTL React frontend for the Phase 1 screens
- 54 integration tests against a real database

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiHbDZ5HpzN6NRCMJmydEq
- Schema: fiscal years and periods (no overlaps), account groups,
  hierarchical chart of accounts, cost centers, journal entries and
  lines, gap-free numbering per fiscal year
- Ledger rules enforced in the database as well as the API: balanced
  posting, open-period posting, postable active same-company accounts,
  posted entries immutable except for being marked reversed, no deletes
- Engine: draft, post, reverse with linked correcting entry, year-end
  closing to retained earnings; works inside the caller's transaction
  so later documents (invoices, payments) post atomically
- Default Saudi chart and current fiscal year created for every company;
  the engine finds accounts by system key, not code
- Trial balance with opening, period, and closing columns
- Arabic RTL screens: journal list, entry form with live balance,
  entry detail with post and reverse, chart, fiscal years, trial balance
- Fixes found while testing: premature red borders on required inputs,
  error box crash on structured error details, save-and-post sending
  a draft
- 40 new tests (94 total)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiHbDZ5HpzN6NRCMJmydEq
- Customers and suppliers share one implementation with separate
  tables, permissions, numbering, and control accounts
- Saudi national address fields (ZATCA format) enforced in the database
- Party balances come only from journal lines tagged with customer_id
  or supplier_id; the journal form offers a party picker on receivable
  and payable lines, which also covers opening balances
- Products and services with units (UN/ECE codes), nested categories,
  4-decimal unit prices, ZATCA VAT category, and optional account
  overrides checked by type; services can never track stock
- Gap-free per-company document numbering, reused by invoices later
- Accountant role can now manage customers and suppliers
- Arabic screens for customers, suppliers, products, units, categories
- 29 new tests (123 total)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiHbDZ5HpzN6NRCMJmydEq
- Six commercial documents share one implementation: sales quotes,
  invoices, returns (credit notes); purchase orders, invoices, returns
  (debit notes). Legal documents are numbered gap-free at issue
- Each invoice and return posts its journal entry in the same
  transaction (AR/AP tagged with the party, revenue or inventory and
  expense per line, VAT output or input)
- Server-side calculation module: line rounding, document VAT rounded
  once per category (ZATCA-consistent), VAT-inclusive prices, line
  discounts; the form previews totals through a calculate endpoint
- Tax rates are data with effective dates; the current standard rate is
  seeded and can be changed without code
- Returns are prorated from the original lines; the last return takes
  exactly what is left, so a full return nets the invoice to zero
- Payments with configurable methods, allocation across invoices,
  advances, refunds, and voiding; settlement drives invoice status
- Credit limit check, party snapshot, invoice kind (standard/simplified),
  cancellation by reversal, quote and PO conversion
- Issued documents, their lines, and payments are protected by triggers
- Fixes found while testing: decimal.js isPositive() is true for zero,
  pg DATE values shifted by the server time zone, section tabs resolving
  against the full URL, product form picking the wrong default unit
- 46 new tests (169 total)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiHbDZ5HpzN6NRCMJmydEq
- Stock changes only through append-only stock movements; balances per
  product and warehouse are updated under a row lock in the same
  transaction, and can never go negative or hold value without quantity
- Weighted-average cost per warehouse behind a costing interface (FIFO
  can be added as another implementation); the last unit out takes the
  exact remaining value, so values stay to the halala
- Invoices, returns and purchases move stock as they are issued:
  sales add Dr COGS / Cr Inventory to the invoice entry, sales returns
  come back at the cost they left at, purchase returns leave at average
  cost with the price difference to COGS, stocked purchases always post
  to Inventory
- Cancelling a document reverses its movements at the same costs; value
  left in an emptied warehouse is expensed with its own entry
- Transfers between warehouses (no entry), adjustments and stock counts
  against an offset account (capital for opening stock), stock card,
  balances, and a valuation report reconciled with the Inventory account
- Products show on-hand quantity; type, tracking and deletion lock once
  a product has stock history
- Fixes found while testing: forms rendering before their option lists
  loaded picked wrong defaults (transfer destination); warehouse lists
  now put the main warehouse first
- 19 new tests (188 total)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiHbDZ5HpzN6NRCMJmydEq
- Expense vouchers (EXP-) with categories linked to expense accounts and a
  default VAT treatment; cash/bank expenses post Dr expense + Dr VAT input /
  Cr payment method, credit expenses post to the supplier's payable and are
  settled by supplier payments allocated to the expense.
- Drafts are editable; posted expenses are immutable and cancelled through a
  reversing entry. Cancellation is refused while payments are allocated.
- Append-only tax_transactions ledger written by invoices, returns, purchase
  invoices and expenses, with negated rows on cancellation.
- VAT return report (ZATCA boxes 1-16) reconciled against the VAT output and
  input accounts; unsupported boxes are reported as zero and listed.
- Tax rate management in settings, expense pages, VAT return page, and
  expense allocation in supplier payments.
- 15 new integration tests (203 total).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiHbDZ5HpzN6NRCMJmydEq
- Financial statements from posted journal lines: income statement,
  balance sheet with unclosed earnings, direct-method cash flow that
  reconciles opening + net = closing, general ledger with running balance,
  and journal report. Year-closing entries are excluded from income
  figures; reversals inherit their original's document type.
- Receivables/payables aging reconciled per party to the ledger, with
  unapplied credits shown separately; customer and supplier statements.
- Sales and purchase reports by party, product, month or document (net of
  returns, cost and gross profit from stock movements); expense report
  from expense accounts.
- Dashboard KPIs and a 12-month series from the ledger, with SVG charts,
  hover tooltips and a table view.
- New financial_report.view permission separates financial statements from
  operational reports held by sales, purchase and warehouse managers.
- Reports UI with date presets, print styles and CSV export.
- 17 new integration tests (220 total).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiHbDZ5HpzN6NRCMJmydEq
- EGS units per company or branch: secp256k1 key pair encrypted at rest
  (AES-256-GCM), PKCS#10 CSR with ZATCA's certificate template and SAN
  fields, compliance CSID via OTP, compliance checks for every document
  type, production CSID.
- UBL 2.1 invoices in the KSA profile (standard/simplified invoices and
  credit notes; debit-note XML for compliance checks), invoice hash over
  C14N without signature and QR, ECDSA signature, XAdES block, phase-2 QR
  (tags 1-9).
- Generation inside the issuing transaction: the unit row is locked, the
  document gets the next ICV and the previous hash; missing seller/buyer
  data or exemption codes reject the issue before anything is posted.
  The hash chain cannot fork (unique previous hash per unit).
- Reporting and clearance with recorded submissions and validation
  messages, exponential backoff on transport failures, cleared XML kept,
  background submitter. E-invoiced documents can only be corrected with a
  credit note unless ZATCA rejected them.
- Company national address, product exemption codes, e-invoicing page,
  e-invoice status on invoices, printable tax invoice with QR, phase-1 QR
  when no unit is active.
- Tests use a stand-in gateway that issues real certificates via openssl
  and verifies every hash and signature. Not yet run against ZATCA's
  developer portal, simulation or production gateways.
- 22 new tests (242 total).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiHbDZ5HpzN6NRCMJmydEq
- Plans with prices, trial and grace days and limits stored as data
  (edited by the platform administrator); a zero-price trial plan is the
  default for sign-ups. Subscriptions keep a price snapshot in items, and
  every change is an append-only billing event.
- Subscription state derived from dates: TRIALING/ACTIVE, GRACE (full
  access), EXPIRED (read-only: writes refused with 402, sign-in and the
  subscription page stay available).
- Limits enforced at creation of users, companies, branches, warehouses,
  products and at invoice issue, under a lock on the subscription row so
  concurrent requests cannot overshoot; monthly API calls metered in memory
  and flushed to usage_records.
- /admin for platform administrators: overview and system health,
  organizations (create with temporary password, suspend/activate, change
  plan, record payment, extend, cancel, limit and feature overrides),
  users, subscriptions, plans, revenue and MRR, usage, platform and tenant
  audit logs, server errors, feature flags.
- Cross-tenant reads through a read-only RLS policy active only when the
  admin guard sets app.platform_admin after re-checking the user flag;
  admin writes run in the target tenant's context. Admin actions are
  logged; 500 errors are recorded in system_errors.
- Tenant subscription page and expiry/trial banners; CLI to grant
  platform access.
- 16 new tests (258 total).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiHbDZ5HpzN6NRCMJmydEq
Security review fixes:
- Trust X-Forwarded-For only from configured proxies (TRUST_PROXY)
- Existing users join an organization only after accepting an invitation;
  the inviter cannot see their details before that
- Sign-in lockout per user and IP, with the same 401 as a wrong password
- Spreadsheet formula injection guard in CSV exports
- Plan user limit enforced on reactivation and invitation acceptance
- Managers cannot disable or edit members with more access than they hold
- Separate RLS read/write policies for subscription and billing tables,
  triggers guarding tenant status and platform admin access
- Statement timeout, 5-year report range limit, numeric overflow -> 400
- Cross-tab refresh coordination with the Web Locks API
- Expense categories cannot point at cash, bank or control accounts

Performance: general ledger and statements join document numbers once
instead of a per-row subquery (2.3 s -> 53 ms on 20k ledger lines);
lazy-loaded sections cut the initial bundle from 529 KB to 394 KB;
self-hosted Arabic font. Load-test script in apps/api/scripts/perf.ts.

Production: multi-stage non-root Docker images, docker-compose.prod.yml
with a migration job and nginx (strict CSP, security headers),
/api/ready readiness probe, backup and restore scripts, CI workflow,
browser smoke test (npm run e2e) and an Arabic deployment guide.

Tests: 272 API tests (91% statements), web unit tests, e2e smoke.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiHbDZ5HpzN6NRCMJmydEq
@netlify

netlify Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for docsdocker ready!

Name Link
🔨 Latest commit 4f08761
🔍 Latest deploy log https://app.netlify.com/projects/docsdocker/deploys/6ac2ae3274f32000087598d9
😎 Deploy Preview https://deploy-preview-26269--docsdocker.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@dvdksn dvdksn closed this Oct 5, 2026
@docker docker locked as spam and limited conversation to collaborators Oct 5, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants