Data Model & System Design Notes — Laundry Management System¶
Document Information¶
| Field | Value |
|---|---|
| Project | Laundry Management System |
| Version | 1.0 |
| Language | English |
| Tech Stack | ASP.NET Core + Angular + PostgreSQL (central) / SQLite (offline branches) |
| Document Type | Technical Design Notes |
Table of Contents¶
- Entity Overview
- Core Entities & Relationships
- Chart of Accounts & General Ledger
- Accounting Rules Engine
- Accounting Flows by Transaction Type
- UUID Strategy & Offline Sync
- Reporting API Contract Pattern
- Carpet Settlement Models
- Tailor Payout Models
- Pricing Strategy Configuration
- Soft Delete & Audit Trail
- Technology Library References
1. Entity Overview¶
The system is divided into four layers of entities:
| Layer | Purpose | Examples |
|---|---|---|
| Master Data | Configuration, rarely changes | Users, Branches, Chart of Accounts, Currencies, Price Lists, Garment Types, Service Types, Classifications, Carpet Types |
| Operational Data | Day-to-day business transactions | Invoices, InvoiceItems, CarpetReceipts, CarpetReceiptItems, CarpetInvoices, TailoringOrders, TailoringTasks, InventoryTransactions |
| Financial Data | Accounting records (never directly edited) | JournalEntries, JournalEntryLines (General Ledger), Payments |
| Supporting Data | Tracking, logging | CustomerCredits, BarcodeTags, ShiftSessions, AuditLogs, SyncBatches |
2. Core Entities & Relationships¶
2.1 Master Data Entities¶
branches (id uuid PK, code, name, mode [online|offline], default_currency_id, status)
users (id uuid PK, username, password_hash, role, branch_id FK, status)
roles (id uuid PK, name)
role_permissions (role_id FK, module, action, is_allowed)
customers (id uuid PK, name, phone, classification_id FK, branch_id FK, credit_limit, status, is_transient)
customer_classifications (id uuid PK, name, default_price_list_id FK, default_discount_pct, allow_deferred_payment, is_default)
garment_types (id uuid PK, code, name_en, name_ar, category, status)
service_types (id uuid PK, code, name_en, name_ar, status)
garment_service_links (garment_type_id FK, service_type_id FK) — which services apply to which garments
price_lists (id uuid PK, name, currency_id FK, status)
price_list_entries (id uuid PK, price_list_id FK, garment_type_id FK, service_type_id FK, base_price numeric(18,4), effective_from, effective_to)
currencies (id uuid PK, code, name, symbol, decimal_places)
currency_rates (id uuid PK, from_currency_id FK, to_currency_id FK, rate numeric(18,6), effective_date)
fiscal_years (id uuid PK, name, start_date, end_date, is_closed)
tax_settings (id uuid PK, is_enabled bool, tax_name, tax_rate numeric(8,4), is_inclusive bool, tax_account_code)
carpet_types (id uuid PK, code, name_en, name_ar)
carpet_companies (id uuid PK, name, contact, phone, address, settlement_model [accrual|cash|prepayment], status)
carpet_company_prices (id uuid PK, company_id FK, carpet_type_id FK, price_per_sqm numeric(18,4), price_per_piece numeric(18,4), effective_date)
tailors (id uuid PK, name, phone, payout_model [periodic|peritem|salary_commission], base_salary numeric(18,4), status)
inventory_items (id uuid PK, code, name_en, name_ar, category, uom, selling_price numeric(18,4), cost_price numeric(18,4), current_quantity numeric(18,4), reorder_level numeric(18,4), branch_id FK, status)
2.2 Operational Entities¶
invoices (id uuid PK, invoice_number, customer_id FK nullable, branch_id FK, date, due_date, operational_status [draft|confirmed|in_progress|ready|delivered], financial_status [unpaid|partially_paid|paid|deferred], subtotal numeric(18,4), discount_amount numeric(18,4), tax_amount numeric(18,4), grand_total numeric(18,4), paid_amount numeric(18,4), remaining_amount numeric(18,4), notes, created_by_user_id FK, currency_id FK)
invoice_items (id uuid PK, invoice_id FK, garment_type_id FK, service_type_id FK, quantity int, unit_price numeric(18,4), line_total numeric(18,4), discount_amount numeric(18,4), is_tailoring bool, tailor_id FK nullable, tailor_cost numeric(18,4), line_status [active|damaged|lost], compensation_amount numeric(18,4))
barcode_tags (id uuid PK, tag_code, invoice_id FK, invoice_item_id FK, garment_type_id FK, printed_at, scanned_at_delivery)
carpet_receipts (id uuid PK, receipt_number, customer_id FK, branch_id FK, date, advance_amount numeric(18,4), advance_method, notes, status [received|assigned_to_company|returned|ready|delivered], external_company_id FK nullable)
carpet_receipt_items (id uuid PK, receipt_id FK, carpet_type_id FK, quantity int, estimated_size, notes_damages)
carpet_final_invoices (id uuid PK, invoice_number, linked_receipt_id FK UNIQUE, customer_id FK, branch_id FK, date, operational_status, financial_status, subtotal numeric(18,4), discount_amount numeric(18,4), tax_amount numeric(18,4), grand_total numeric(18,4), advance_deduction numeric(18,4), paid_amount numeric(18,4), remaining_amount numeric(18,4), notes)
carpet_final_invoice_items (id uuid PK, final_invoice_id FK, carpet_type_id FK, pricing_strategy [per_sqm|per_piece|cost_plus], actual_area_sqm numeric(18,4) nullable, quantity int, unit_rate numeric(18,4), company_cost numeric(18,4), markup_pct numeric(8,4), line_total numeric(18,4))
tailoring_orders (id uuid PK, order_number, customer_id FK, linked_invoice_id FK nullable, branch_id FK, date, operational_status, financial_status)
tailoring_tasks (id uuid PK, order_id FK, service_description, garment_type_id FK, quantity int, unit_price numeric(18,4), assigned_tailor_id FK, tailor_cost numeric(18,4), task_status [pending|in_progress|completed])
inventory_transactions (id uuid PK, item_id FK, branch_id FK, transaction_type [sale|sale_cancellation|stock_receipt|adjustment], quantity_change numeric(18,4), reference_type, reference_id, date)
2.3 Financial Entities¶
chart_of_accounts (id uuid PK, account_code, account_name_en, account_name_ar, account_type [asset|liability|equity|income|expense], parent_id FK nullable, is_active, is_contra)
journal_entries (id uuid PK, entry_number, date, reference_type, reference_id, narration, branch_id FK, fiscal_year_id FK, is_manual bool, created_by_user_id FK, status [draft|posted|reversed])
journal_entry_lines (id uuid PK, journal_entry_id FK, account_code FK, debit numeric(18,4), credit numeric(18,4), branch_id FK, customer_id FK nullable, supplier_id FK nullable, tailor_id FK nullable, currency_id FK, narration)
payments (id uuid PK, payment_number, invoice_id FK nullable, carpet_final_invoice_id FK nullable, customer_id FK, branch_id FK, date, amount numeric(18,4), method [cash|card|bank_transfer|customer_credit|other], reference_no, notes, shift_id FK, status)
supplier_payments (id uuid PK, payment_number, supplier_type [carpet_company|tailor], supplier_id, branch_id FK, date, amount numeric(18,4), method, reference_no, notes)
customer_credits (id uuid PK, customer_id FK, branch_id FK, amount numeric(18,4), source_type, source_id, date, notes, remaining_amount numeric(18,4))
2.4 Supporting Entities¶
shift_sessions (id uuid PK, user_id FK, branch_id FK, open_time, close_time, opening_float numeric(18,4), expected_cash numeric(18,4), actual_cash numeric(18,4), discrepancy numeric(18,4), notes)
audit_logs (id uuid PK, entity_type, entity_id, action, user_id FK, timestamp, old_value jsonb, new_value jsonb, branch_id FK)
sync_batches (id uuid PK, source_branch_id FK, target_branch_id FK nullable, export_date, import_date, total_rows, status [pending|imported|validated|rejected], file_path, validation_errors text)
system_settings (key text PK, value text)
3. Chart of Accounts & General Ledger¶
3.1 Chart of Accounts Structure¶
The Chart of Accounts (CoA) is a hierarchical tree structure. Each account belongs to one of the five major types:
| Type | Code Range | Examples |
|---|---|---|
| Assets (1XXX) | 1000-1999 | Cash (1000), Bank (1010), Accounts Receivable (1200), Inventory (1300), Prepaid Expenses (1400) |
| Liabilities (2XXX) | 2000-2999 | Accounts Payable (2000), Accrued Tailor Payable (2100), Tax Payable (2200), Customer Deposits / Unearned Revenue (2300) |
| Equity (3XXX) | 3000-3999 | Owner's Capital (3000), Retained Earnings (3100) |
| Income (4XXX) | 4000-4999 | Laundry Income (4000), Carpet Income (4010), Tailoring Income (4020), Product Sales Income (4030) |
| Expenses (5XXX) | 5000-5999 | Laundry Supplies (5000), Carpet Cleaning Expense (5010), Tailoring COGS (5020), Product COGS (5030), Salaries (5040), Damage/Loss Expense (5050), Refund Expense (5060) |
Rule: Sub-accounts inherit the type of their parent. The hierarchical code reflects the tree (e.g., 1200 = Accounts Receivable, 1201 = AR - Individuals, 1202 = AR - Companies).
3.2 General Ledger Table¶
The journal_entry_lines table IS the General Ledger. Every row is one side of a double-entry posting.
Core constraints:
- For every Journal Entry: SUM(debit) == SUM(credit). Enforced at the application level before posting.
- Once posted, a journal entry cannot be modified. Corrections create a reversing entry.
- Every line carries branch_id for branch-level reporting.
- Every line optionally carries customer_id, supplier_id, or tailor_id for sub-ledger reconciliation.
3.3 Balance Calculation¶
Customer/Supplier/Tailor balances are NEVER stored in a balance column on those entities. They are always calculated:
-- Customer balance (Accounts Receivable)
SELECT COALESCE(SUM(debit), 0) - COALESCE(SUM(credit), 0) AS balance
FROM journal_entry_lines
WHERE account_code LIKE '120%' -- All AR sub-accounts
AND customer_id = 'CUST-UUID';
For performance, a customer_balances materialized table can be maintained, but it is rebuilt from the GL on demand and never treated as the source of truth.
4. Accounting Rules Engine¶
4.1 Concept¶
Instead of hard-coding accounting logic for every transaction type, the system uses an Accounting Rules table. Each rule defines:
| Field | Description |
|---|---|
| Rule ID | UUID |
| Rule Code | Short identifier (e.g., "PAID_LAUNDRY_INVOICE") |
| Event | The business event that triggers this rule |
| Debit Account Code | |
| Credit Account Code | |
| Condition | Optional JSON filter (e.g., only for specific payment method) |
| Priority | Order of execution if multiple rules match |
4.2 How It Works¶
When a business event occurs (e.g., InvoiceConfirmed, PaymentReceived, CarpetReturned), the system:
- Looks up all rules matching the event.
- For each rule, evaluates the condition.
- Generates Journal Entry Lines (Debit X, Credit Y) for the matched accounts.
- Wraps everything in a single database transaction with the operational data changes.
4.3 Why a Rules Engine?¶
- The shop owner can add a new settlement model for carpet companies by adding a row to
accounting_rules, without code changes. - The accountant can adjust GL mappings without redeploying the application.
- Multi-currency expansion: add rules for currency conversion entries.
5. Accounting Flows by Transaction Type¶
5.1 Paid Laundry Invoice (Cash at Receipt)¶
| # | Account | Debit | Credit |
|---|---|---|---|
| 1 | Cash / Bank (1000) | Grand Total | |
| 2 | Laundry Income (4000) | Grand Total |
If tax is enabled: | 3 | Cash (1000) | Tax Amount | | | 4 | Tax Payable (2200) | | Tax Amount |
5.2 Deferred Laundry Invoice¶
| # | Account | Debit | Credit |
|---|---|---|---|
| 1 | Accounts Receivable - Customer (120X) | Grand Total | |
| 2 | Laundry Income (4000) | Grand Total |
When payment is received later: | 3 | Cash (1000) | Paid Amount | | | 4 | Accounts Receivable - Customer (120X) | | Paid Amount |
5.3 Partial Payment¶
Partial payments debit Cash and credit Accounts Receivable for the paid portion only.
5.4 Invoice Contains Inventory Items¶
| # | Account | Debit | Credit |
|---|---|---|---|
| 1 | Cash / AR (1000/1200) | Full Total | |
| 2 | Laundry Income (4000) | Service Portion | |
| 3 | Product Sales Income (4030) | Product Portion | |
| 4 | Product COGS (5030) | Product Cost | |
| 5 | Inventory Asset (1300) | Product Cost |
5.5 Prepayment / Advance (Carpet)¶
| # | Account | Debit | Credit |
|---|---|---|---|
| 1 | Cash (1000) | Advance Amount | |
| 2 | Customer Deposits - Unearned Revenue (2300) | Advance Amount |
When final carpet invoice is created: | 3 | Customer Deposits (2300) | Advance Amount | | | 4 | Carpet Income (4010) | | Final Total | | 5 | If Advance > Final: Customer Deposits (2300) | Excess | | | 6 | If Advance > Final: Customer Credit Payable (23XX) | | Excess | | 7 | If Final > Advance: AR - Customer (120X) | Shortfall | | | 8 | If Final > Advance: Carpet Income (4010) | | Shortfall |
5.6 Carpet Company — Accrual Model¶
When carpet is returned from company: | 1 | Carpet Cleaning Expense (5010) | Company Cost | | | 2 | Accounts Payable - Company X (200X) | | Company Cost |
When payment is made to company: | 3 | Accounts Payable - Company X (200X) | Paid Amount | | | 4 | Cash (1000) | | Paid Amount |
5.7 Carpet Company — Cash Model¶
When payment is made to company: | 1 | Carpet Cleaning Expense (5010) | Paid Amount | | | 2 | Cash (1000) | | Paid Amount |
5.8 Carpet Company — Prepayment Model¶
When advance is paid to company: | 1 | Prepaid Expense - Company X (140X) | Advance | | | 2 | Cash (1000) | | Advance |
When carpet is returned: | 3 | Carpet Cleaning Expense (5010) | Company Cost | | | 4 | Prepaid Expense - Company X (140X) | | Company Cost |
5.9 Tailor — Periodic / Per-Item Model¶
When tailoring task is completed: | 1 | Tailoring COGS (5020) | Tailor Cost | | | 2 | Accrued Tailor Payable - Tailor X (210X) | | Tailor Cost |
When payment is made to tailor: | 3 | Accrued Tailor Payable - Tailor X (210X) | Paid Amount | | | 4 | Cash (1000) | | Paid Amount |
5.10 Tailor — Salary + Commission Model¶
Monthly salary (auto-generated by Quartz job): | 1 | Salaries Expense (5040) | Base Salary | | | 2 | Accrued Tailor Payable - Tailor X (210X) | | Base Salary |
Commission for completed items: | 3 | Tailoring Bonus Expense (5045) | Commission Amount | | | 4 | Accrued Tailor Payable - Tailor X (210X) | | Commission Amount |
5.11 Damage / Loss Compensation¶
| # | Account | Debit | Credit |
|---|---|---|---|
| 1 | Damage/Loss Expense (5050) | Compensation Value | |
| 2 | Customer Credit Payable (23XX) | Compensation Value |
Or if refunded in cash: | 1 | Damage/Loss Expense (5050) | Compensation Value | | | 2 | Cash (1000) | | Compensation Value |
5.12 Refund (Paid Invoice)¶
| # | Account | Debit | Credit |
|---|---|---|---|
| 1 | Refund Expense / Income Contra (5060) | Refund Amount | |
| 2 | Cash / Customer Credit (1000 / 23XX) | Refund Amount |
5.13 Invoice Cancellation (Unpaid)¶
The original entry is REVERSED: | # | Account | Debit | Credit | |---|---------|-------|--------| | 1 | Laundry Income (4000) | Original Amount | | | 2 | Accounts Receivable (120X) | | Original Amount |
6. UUID Strategy & Offline Sync¶
6.1 Why UUIDs¶
All primary keys are UUIDs generated client-side (C# Guid.NewGuid()). This prevents ID collisions when merging data from offline branches into the central server.
6.2 UUID Generation Rule¶
- UUIDs are generated in the application layer (ASP.NET Core), not by the database.
- The frontend never generates UUIDs — it sends POST requests without IDs, and the backend generates the UUID.
- This ensures a single point of UUID creation.
6.3 Offline Branch Data Model¶
Offline branches use SQLite with an identical table structure. SQLite supports:
- TEXT for UUIDs (stored as 36-character strings).
- NUMERIC for decimal amounts.
- SQLite triggers or application logic enforce the same SUM(debit) == SUM(credit) rule.
6.4 Sync Batch Structure¶
Each row in the offline database has sync_status = 'local' | 'pending' | 'synced'.
Export Package (JSON format):
{
"batch_id": "uuid",
"source_branch_id": "uuid",
"source_branch_code": "CAIRO-01",
"export_date": "2026-05-09T18:00:00Z",
"tables": {
"journal_entry_lines": [
{ "id": "uuid", "journal_entry_id": "uuid", ... }
],
"invoices": [ ... ],
"payments": [ ... ],
"customers": [ ... ],
...
}
}
6.5 Import and Merge Logic¶
1. Load export JSON file.
2. Validate branch_id matches expected source.
3. Validate SUM(debit) == SUM(credit) within the batch.
4. Validate all account_code references exist in central CoA.
5. For each table, iterate rows:
- If row.id does NOT exist centrally → INSERT.
- If row.id exists centrally (re-import) → UPSERT (update if source newer).
6. Record the sync_batch with status 'imported' or 'validated'.
7. Update source rows (if accessible) to sync_status = 'synced'.
6.6 Conflict Resolution¶
- Customer phone collision: If a customer with the same phone number already exists centrally, the import process flags it. The Admin chooses:
- Link (associate offline customer to existing central customer).
- Keep separate (the import creates a new customer entry).
- Invoice number collision: Invoice numbers are prefixed with branch code, so this should not happen. If it does, the import is rejected.
- Duplicate sync: Since all keys are UUIDs, re-importing the same file is safe (upsert by id).
7. Reporting API Contract Pattern¶
7.1 Standard Response Format¶
Every report API endpoint returns this envelope:
{
"meta": {
"reportName": "string",
"generatedAt": "ISO8601",
"branchId": "uuid | 'all'",
"currency": "EGP",
"filters": {
"dateFrom": "YYYY-MM-DD",
"dateTo": "YYYY-MM-DD"
}
},
"summary": {
"totalRevenue": 12500.00,
"totalInvoices": 45,
...
},
"details": [
{ /* pre-calculated row */ }
],
"pagination": {
"page": 1,
"pageSize": 50,
"totalCount": 450
}
}
7.2 Key Principles¶
| Principle | Rule |
|---|---|
| All calculations in SQL | Running balances, SUM, AVG, grouping, filtering — all done in the database. |
| Frontend never calculates money | The balance, total, remaining fields are pre-computed. Frontend only formats and renders. |
| Pagination for large datasets | The backend paginates. Frontend uses lazy loading on PrimeNG tables. |
| Summary endpoint separate | Dashboards call /report/daily-sales/summary (aggregates only). Drill-down calls /report/daily-sales/details (full rows). |
| Authorization at the API level | The backend returns only data the requesting user is allowed to see (branch filter, role filter). |
| Date range limits | Reports default to 30 days. Maximum 1 year without Admin override. |
7.3 Report API Endpoints (Reference)¶
GET /api/reports/daily-sales ?branchId=&dateFrom=&dateTo=
GET /api/reports/shift-closing ?shiftId=
GET /api/reports/customer-statement ?customerId=&dateFrom=&dateTo=
GET /api/reports/general-ledger ?accountCode=&dateFrom=&dateTo=&page=&pageSize=
GET /api/reports/trial-balance ?dateFrom=&dateTo=
GET /api/reports/income-statement ?branchId=&dateFrom=&dateTo=
GET /api/reports/balance-sheet ?date=
GET /api/reports/tailor-payout ?tailorId=&dateFrom=&dateTo=
GET /api/reports/company-payables ?companyId=&dateFrom=&dateTo=
GET /api/reports/inventory-levels ?branchId=&category=
GET /api/reports/best-selling ?dateFrom=&dateTo=&limit=
GET /api/reports/corporate-summary ?customerId=&year=&month=
GET /api/reports/damage-report ?dateFrom=&dateTo=
GET /api/reports/discounts-overrides ?dateFrom=&dateTo=&userId=
GET /api/reports/branch-comparison ?dateFrom=&dateTo=
GET /api/reports/audit-log ?entityType=&entityId=&userId=&dateFrom=&dateTo=
8. Carpet Settlement Models (Configurable Per Company)¶
| Model | When Carpet Returns From Company | When You Pay The Company |
|---|---|---|
| Accrual | Debit Expense, Credit A/P | Debit A/P, Credit Cash |
| Cash | Nothing | Debit Expense, Credit Cash |
| Prepayment | Debit Expense, Credit Prepaid | Debit Prepaid (advance), Credit Cash; Balance auto-calculated |
Each carpet_company has a settlement_model field that can be overridden per transaction if needed.
9. Tailor Payout Models (Configurable Per Tailor)¶
| Model | When Task Completed | When Paid |
|---|---|---|
| Periodic | Debit Tailoring COGS, Credit Accrued Payable | Debit Accrued Payable, Credit Cash |
| Per-Item | Debit Tailoring COGS, Credit Accrued Payable (instant) | Debit Accrued Payable, Credit Cash (any time) |
| Salary + Commission | Salary: Quartz job posts monthly debit Salary Expense, credit Accrued Payable. Commission: Same as Periodic for bonus items. | Same as others |
Each tailor has a payout_model field. The accounting engine reads it and applies the matching rule.
10. Pricing Strategy Configuration¶
10.1 Carpet Pricing Strategies¶
| Strategy | Parameters | Price Calculation |
|---|---|---|
| Per Square Meter | actual_area_sqm, selling_rate_per_sqm |
actual_area_sqm × selling_rate_per_sqm |
| Per Piece | quantity, fixed_price_per_piece |
quantity × fixed_price_per_piece |
| Cost-Plus Markup | company_cost, markup_pct |
company_cost × (1 + markup_pct / 100) |
Each carpet_type record specifies which strategies are allowed (allowed_strategies JSON field: ["per_sqm", "per_piece", "cost_plus"]).
10.2 Flexible Price List Architecture¶
CustomerClassification
│
▼
PriceList (selected per classification)
│
▼
PriceListEntry (garment_type + service_type → base_price)
│
▼ (optional override with reason)
InvoiceItem (frozen price at time of invoice confirmation)
Multiple price lists can be active simultaneously. Changing a price list does not affect historical invoices.
11. Soft Delete & Audit Trail¶
11.1 No Hard Deletes for Financial Data¶
- Invoices, payments, journal entries, and receipts are never physically deleted.
- "Cancellation" creates a status change + a reversing journal entry.
- Only Draft invoices (unconfirmed, no financial impact) can be removed.
11.2 Audit Log Table¶
CREATE TABLE audit_logs (
id UUID PRIMARY KEY,
entity_type VARCHAR(50) NOT NULL, -- 'Invoice', 'Payment', 'Customer', etc.
entity_id UUID NOT NULL,
action VARCHAR(20) NOT NULL, -- 'CREATE', 'UPDATE', 'DELETE', 'STATUS_CHANGE'
user_id UUID NOT NULL,
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
old_value JSONB, -- NULL for CREATE
new_value JSONB, -- NULL for DELETE
branch_id UUID NOT NULL
);
11.3 What Triggers an Audit Entry¶
- Any API call that modifies Master Data, Operational Data, or Financial Data.
- Status changes (e.g., Invoice from "Ready" to "Delivered").
- Price overrides and manual discounts (old price, new price, reason).
- Permission changes.
12. Technology Library References¶
12.1 Backend (ASP.NET Core)¶
| Library | NuGet Package | Purpose |
|---|---|---|
| Entity Framework Core | Microsoft.EntityFrameworkCore |
ORM |
| Npgsql EF Core Provider | Npgsql.EntityFrameworkCore.PostgreSQL |
PostgreSQL driver |
| Dapper | Dapper |
High-performance raw SQL for reports & ledger queries |
| MediatR | MediatR |
CQRS pattern (commands for writes, queries for reads) |
| FluentValidation | FluentValidation.AspNetCore |
Input validation |
| AutoMapper | AutoMapper |
DTO mapping |
| Serilog | Serilog.AspNetCore |
Structured logging |
| Serilog Npgsql Sink | Serilog.Sinks.PostgreSQL |
Log to database |
| Quartz.NET | Quartz.Extensions.Hosting |
Background jobs (payout generation, nightly sync) |
| BCrypt.Net | BCrypt.Net-Next |
Password hashing |
| Microsoft Identity / JWT | Microsoft.AspNetCore.Authentication.JwtBearer |
Auth |
12.2 Frontend (Angular)¶
| Library | npm Package | Purpose |
|---|---|---|
| PrimeNG | primeng |
UI components (confirmed by client) |
| PrimeFlex | primeflex |
CSS utilities |
| PrimeIcons | primeicons |
Icons |
| ngx-translate | @ngx-translate/core |
AR/EN translations |
| SheetJS | xlsx |
Excel export |
| html2canvas | html2canvas |
Render HTML to canvas |
| jspdf | jspdf |
PDF generation |
| jsbarcode | jsbarcode |
Barcode generation |
| RxJS | rxjs |
Reactive state |
12.3 Database¶
| Technology | Role |
|---|---|
| PostgreSQL 16+ | Central database |
| SQLite 3 | Offline branch database |
| Npgsql | .NET driver for PostgreSQL |
| Microsoft.Data.Sqlite | .NET driver for SQLite |
Appendix A: State Transition Diagrams¶
A.1 Invoice Operational Status¶
stateDiagram-v2
[*] --> Draft
Draft --> Confirmed : Confirm
Confirmed --> InProgress : Start Processing
InProgress --> Ready : All Items Ready
Ready --> Delivered : Customer Pickup
Draft --> [*] : Remove
Confirmed --> [*] : Cancel (if unpaid)
Ready --> DamagedLost : Mark Damaged/Lost
A.2 Invoice Financial Status¶
stateDiagram-v2
[*] --> Unpaid
Unpaid --> PartiallyPaid : Partial Payment
PartiallyPaid --> Paid : Remaining Paid
Unpaid --> Deferred : Deferred Payment Terms
Deferred --> PartiallyPaid : Partial Payment
Deferred --> Paid : Full Payment
Paid --> Refunded : Refund Processed
A.3 Carpet Receipt → Final Invoice¶
stateDiagram-v2
[*] --> Received : Receive Carpet (Receipt Created)
Received --> Assigned : Assign to Company
Assigned --> Returned : Carpet Returned (Measure Area)
Returned --> FinalInvoice : Create Final Invoice (1-to-1 linked)
FinalInvoice --> Deducted : Advance Auto-Deducted
Deducted --> PaidRemainder : Advance < Final → Pay Remainder
Deducted --> CreditCreated : Advance > Final → Customer Credit
PaidRemainder --> [*]
CreditCreated --> [*]
Appendix B: Quick Reference — Accounting Account Codes¶
| Code | Account Name | Type |
|---|---|---|
| 1000 | Cash | Asset |
| 1010 | Bank | Asset |
| 1200 | Accounts Receivable | Asset |
| 1300 | Inventory | Asset |
| 1400 | Prepaid Expenses | Asset |
| 2000 | Accounts Payable | Liability |
| 2100 | Accrued Tailor Payable | Liability |
| 2200 | Tax Payable | Liability |
| 2300 | Customer Deposits / Unearned Revenue | Liability |
| 3000 | Owner's Capital | Equity |
| 3100 | Retained Earnings | Equity |
| 4000 | Laundry Income | Income |
| 4010 | Carpet Income | Income |
| 4020 | Tailoring Income | Income |
| 4030 | Product Sales Income | Income |
| 5000 | Laundry Supplies Expense | Expense |
| 5010 | Carpet Cleaning Expense | Expense |
| 5020 | Tailoring COGS | Expense |
| 5030 | Product COGS | Expense |
| 5040 | Salaries Expense | Expense |
| 5045 | Tailoring Bonus Expense | Expense |
| 5050 | Damage/Loss Expense | Expense |
| 5060 | Refund Expense / Income Contra | Expense |