ae5c750d3401cfc4193af78c8c90264eb2a5a8d3
222 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ae5c750d34 |
fix(notifications): don't lose live alerts until a page refresh
CI/CD / CI · API (dotnet build + test) (push) Successful in 44s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m6s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 2m50s
The SignalR connection used the default auto-reconnect, which gives up after ~30s and, even when it did reconnect, never re-ran JoinCafe — so the client dropped out of the café group and silently stopped receiving notifications until a manual refresh. Now it retries forever (capped backoff), re-joins the group on reconnect (and catches up via invalidate), and re-establishes the connection when the network returns or the tab is refocused. As a safety net, the unread/bell and tab-badge polls now run in background tabs too (refetchIntervalInBackground). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
f985deb233 |
fix(offline): stop the sync queue badge getting stuck above zero
Two bugs made "N در صف" persist even when online: - The badge counted poisoned ops (failed after 5 retries, never removed), so it never returned to 0. Now the badge counts only retryable (active) ops; poisoned ops are tracked separately as failedCount and surfaced as a red "N failed — clear" chip the user can tap to discard them. - The manual-retry click drained the LEGACY order_queue, not the real outbox the app actually uses — so clicking did nothing for stuck items. It now drains the outbox (drainOutbox), invalidates queries on success, and recounts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
27ca80fd54 |
fix(orders): block cancelling an order once the kitchen has started it
CI/CD / CI · API (dotnet build + test) (push) Successful in 52s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m8s
CI/CD / CI · Admin Web (tsc) (push) Successful in 39s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 1m40s
Anti-fraud / integrity: a cashier could fire an order to the kitchen, take cash without recording a payment, then cancel (soft-delete) the unpaid order to erase it. CancelOrderAsync now only allows cancelling a still-Pending order; once the kitchen has acted on it (Confirmed/Preparing/Ready) it returns ORDER_IN_PREPARATION and a started order can no longer be removed — it must be completed (and refunded through the audited refund flow if needed). Delivered → ORDER_NOT_OPEN; paid → ORDER_HAS_PAYMENTS (unchanged). Orders are never hard-deleted and every cancel is already audited with the actor. Applies to all roles, independent of permissions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
b162335b48 |
feat(notifications): proactively ask the browser for popup permission
CI/CD / CI · API (dotnet build + test) (push) Successful in 1m1s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m11s
CI/CD / CI · Admin Web (tsc) (push) Successful in 39s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 2m52s
Previously desktop popups had to be enabled from Settings. Now a dismissible
prompt card appears for signed-in users on a supporting browser that haven't
decided yet ("Turn on notifications?" + Enable/Later). Tapping Enable triggers
the browser permission request (user gesture, as browsers require), turns on
desktop popups, and immediately fires one (force) so the user sees it works.
Shown once per device (remembered in localStorage); mounted on both the
dashboard and POS/queue layouts. fa/en/ar added.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
27b3ac60c7 |
feat(menu): per-item print station (cold bar / kitchen / barista)
CI/CD / CI · API (dotnet build + test) (push) Successful in 41s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m6s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 3m28s
Each menu item can now pick its own print station, overriding the category's — so a category can fan out to different printers (e.g. a drink → cold bar, a food → kitchen). Adds MenuItem.KitchenStationId (+ migration, FK SetNull), wires create/update/DTO, and updates kitchen-ticket routing to group by the item's station ?? the category's station ?? the branch kitchen printer. Deleting a station now also clears item assignments. Menu item editor gains a "Print station" dropdown (default = "same as category"). fa/en/ar added. Backend built clean via the Nexus mirror; migration applies on deploy (MigrateAsync). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
aede5bfd97 |
refactor(hr): move Custom Roles from Settings into the HR section
CI/CD / CI · API (dotnet build + test) (push) Successful in 42s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m8s
CI/CD / CI · Admin Web (tsc) (push) Successful in 39s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 2m47s
Custom roles is staff governance, so it belongs with the team — added a "Roles & permissions" tab to the HR screen (owner-only) rendering the existing CustomRolesPanel, and removed the Settings → Team → Custom Roles leaf/group. fa/en/ar label added. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
eaf911e12c |
fix(pos): alert on waiter calls / guest orders on the POS & queue display
CI/CD / CI · API (dotnet build + test) (push) Successful in 46s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 28s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m10s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 48s
CI/CD / CI · Koja (tsc) (push) Successful in 51s
CI/CD / Deploy · all services (push) Successful in 3m3s
The call-waiter flow was fully wired (guest QR button → public endpoint → NotifyCallWaiterAsync persists + broadcasts NotificationReceived), but the alert hook (useOrderAlerts: sound + toast + desktop popup) and the bell live only in the (dashboard) layout. During service staff are on the POS (fullscreen) layout, which mounted neither — so a waiter call produced nothing where staff actually stand. Mount useOrderAlerts in the (fullscreen) layout so POS / queue-display get the chime + toast for waiter calls and new guest orders. (KDS is a dashboard route, already covered.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
166f2b2586 |
fix(seo): self-canonical + unique description on 6 pages that deduped to home
CI/CD / CI · API (dotnet build + test) (push) Successful in 1m4s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m9s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 52s
CI/CD / Deploy · all services (push) Successful in 2m1s
contact / careers / status / privacy / terms / docs set no alternates, so they inherited the layout's canonical (= the locale homepage) — Google treats them as duplicates of the home page and drops them. Each now sets a self-referencing canonical + full fa/en/x-default hreflang (new shared lib/seo.ts pageAlternates) and a unique meta description (added *Desc keys, fa/en) + per-page OpenGraph. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
8ea98bdc09 |
fix(seo): website/koja base URL defaulted to localhost → de-indexed in GSC
CI/CD / CI · API (dotnet build + test) (push) Successful in 5m47s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 34s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m10s
CI/CD / CI · Admin Web (tsc) (push) Successful in 40s
CI/CD / CI · Website (tsc) (push) Successful in 47s
CI/CD / CI · Koja (tsc) (push) Successful in 51s
CI/CD / Deploy · all services (push) Successful in 3m53s
Production serves robots.txt Host/Sitemap, sitemap <loc>, and every page's canonical + og:url as http://localhost:3010 — so Google rejects all URLs ("URL not allowed") and indexes nothing. Cause: NEXT_PUBLIC_SITE_URL is baked in at BUILD time and was unset in prod, so it fell back to the localhost defaults in the compose files + website Dockerfile. Changes the defaults to the real domains (website → https://meezi.ir, koja → https://koja.meezi.ir) in docker-compose.yml, docker-compose.full.yml, the website Dockerfile ARG, and .env.example. Build-time var → the website image MUST be rebuilt + redeployed (CI does this on push), then purge the WCDN cache and resubmit the sitemap in Search Console. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
72abf05a5f |
fix(dashboard): review fixes — error toasts, dedupe socket, POS guards
CI/CD / CI · API (dotnet build + test) (push) Successful in 42s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m11s
CI/CD / CI · Admin Web (tsc) (push) Successful in 39s
CI/CD / CI · Website (tsc) (push) Successful in 47s
CI/CD / CI · Koja (tsc) (push) Successful in 52s
CI/CD / Deploy · all services (push) Successful in 3m20s
- Global MutationCache.onError safety net so mutations without their own onError no longer fail silently (skips ones that handle errors → no double toast). - Notifications feed no longer opens its own SignalR connection; it reuses the one in useOrderAlerts (was double sockets + double cache churn per session). - "Send test notification" now works on the settings page (force flag bypasses the tab-visible guard) instead of silently doing nothing. - POS: re-entry guard on payment confirm (no duplicate payment on double-tap); notes on already-sent lines are read-only (a note-only edit was silently lost); ORDER_ALREADY_CLOSED surfaced with a clear Persian message. - Reservation Confirm/Cancel/Complete buttons disabled while pending. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
63e3cb6962 |
fix(security,pos): close payment/push/PII gaps from app review
CI/CD / CI · API (dotnet build + test) (push) Successful in 59s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 33s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m10s
CI/CD / CI · Admin Web (tsc) (push) Successful in 40s
CI/CD / CI · Website (tsc) (push) Successful in 48s
CI/CD / CI · Koja (tsc) (push) Successful in 52s
CI/CD / Deploy · all services (push) Successful in 2m13s
- Payments: reject RecordPaymentsAsync when the order is already Delivered/
Cancelled (ORDER_ALREADY_CLOSED) — prevents duplicate payments, double loyalty
earn, and overstated cash drawer from a double-tap or paying a reopened order.
- Push broadcast: POST /api/push/broadcast was [Authorize]-only (any user → any
topic, platform-wide). Now requires SendSms + café context and is forced to the
caller's own topic (cafe-{slug}); arbitrary/cross-café topics rejected.
- HR reads: GetEmployees/GetAttendance/GetShifts now require ViewStaff/
ViewAttendance/ViewSchedules (were café-access-only, leaking roster PII the UI
already hid). Expenses list now requires ViewExpenses.
- Receipt: removed the auto-print on full payment so the POS success sheet is the
single print path (no more double receipt).
Local build blocked by NU1301 (NuGet network unreachable); CI builds via mirror.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
c360fbb068 |
feat(orders): recent orders view with receipt / kitchen / bar reprint
CI/CD / CI · API (dotnet build + test) (push) Successful in 41s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m10s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 3m34s
Adds a "سفارشها" (Orders) nav page listing closed orders by day (date + branch filter, paged), each with reprint actions: - چاپ فاکتور → customer receipt - فیش آشپزخانه → kitchen ticket (all stations) - one button per print station (e.g. Bar) → reprints only that station's items Backend: the kitchen print endpoint gains an optional ?stationId= to reprint a single station; PrintKitchenTicketAsync filters its station groups accordingly (NO_STATION_ITEMS when that station has nothing on the order). Nav gated by ViewOrders (visible to branch staff too). fa/en/ar strings added. Note: local backend build couldn't run (NU1301 — NuGet restore network timeout); dashboard typecheck is clean and the C# changes are minimal — CI builds via the Nexus mirror. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
1264606410 |
fix(pos): show the post-payment receipt sheet (was rendered in the wrong view)
CI/CD / CI · API (dotnet build + test) (push) Has been cancelled
CI/CD / CI · Admin API (dotnet build) (push) Has been cancelled
CI/CD / CI · Dashboard (tsc) (push) Has been cancelled
CI/CD / CI · Admin Web (tsc) (push) Has been cancelled
CI/CD / CI · Website (tsc) (push) Has been cancelled
CI/CD / CI · Koja (tsc) (push) Has been cancelled
CI/CD / Deploy · all services (push) Has been cancelled
The payment-success sheet with the "چاپ فاکتور" button lives in the order-view return, but confirmPay called backToBoard() which switched to the board view — so the sheet never rendered and the cashier couldn't print after paying. Now payment clears the cart + closes the pay sheet but STAYS on the order view, so the success sheet shows; returning to the board happens when the cashier taps "سفارش جدید" or the backdrop. Offline/local orders still go straight to the board. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
cad5ba6ea3 |
fix(pos): make the per-item note obvious with an explicit button
CI/CD / CI · API (dotnet build + test) (push) Successful in 46s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m9s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 47s
CI/CD / CI · Koja (tsc) (push) Successful in 51s
CI/CD / Deploy · all services (push) Successful in 3m11s
The note control was an unlabeled icon next to the trash on each cart line, so cashiers couldn't tell where to add a note. Replaced it with a clear "افزودن یادداشت" (add note) text button under each item; clicking it reveals the note input, which collapses again on blur when left empty. Existing notes still show the editable field. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
5596e8dbc5 |
chore(pos): fully remove the classic POS
CI/CD / CI · API (dotnet build + test) (push) Successful in 49s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m11s
CI/CD / CI · Admin Web (tsc) (push) Successful in 41s
CI/CD / CI · Website (tsc) (push) Successful in 47s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 2m52s
POS v2 has been the default at /pos for a while; this deletes the old classic POS entirely: - removed the /pos-classic route and all classic-only components (pos-screen, pos-pay-panel, pos-table-board, pos-queue-bar, pos-receipt-modal, pos-slip-modal, pos-receipt-print.css) - relocated the two modules POS v2 still shared into the pos2 tree (lib/pos/submit-order → lib/pos2, components/pos/pos-customer-picker → pos2), so the components/pos and lib/pos folders are gone - dropped the now-dead "نسخه کلاسیک" (classic version) button + RotateCcw import from the POS v2 header, and updated stale comments POS v2 (/pos) is unchanged and fully self-contained. Typecheck clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
46f962eb75 |
fix(pos): keep the receipt printable after paying an order
CI/CD / CI · API (dotnet build + test) (push) Successful in 56s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 31s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m10s
CI/CD / CI · Admin Web (tsc) (push) Successful in 39s
CI/CD / CI · Website (tsc) (push) Successful in 47s
CI/CD / CI · Koja (tsc) (push) Successful in 1m1s
CI/CD / Deploy · all services (push) Successful in 3m0s
Bug: confirming payment ran backToBoard() → clearSession(), wiping the cart's activeOrderId, so the order vanished from the POS and the "print receipt" button (which keys off activeOrderId) went dead — the only escape was a 4s toast. Fix: capture the just-paid order id in local state (survives the session clear) and show a persistent payment-success sheet with a "چاپ فاکتور" button so the cashier can print/reprint the customer receipt, then "سفارش جدید" to continue. Shared printReceiptById() backs both the in-order button and the success sheet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
6184c83fa7 |
feat(pos): print customer receipt from the POS page
CI/CD / CI · API (dotnet build + test) (push) Successful in 44s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 32s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m12s
CI/CD / CI · Admin Web (tsc) (push) Successful in 39s
CI/CD / CI · Website (tsc) (push) Successful in 48s
CI/CD / CI · Koja (tsc) (push) Successful in 51s
CI/CD / Deploy · all services (push) Successful in 3m0s
POS v2 auto-printed the receipt on full payment but had no manual button. Adds a "چاپ فاکتور" (print receipt) action in the order panel that prints/reprints the active saved order's customer receipt, plus a "print receipt" action on the payment-success toast. Replaces the dead disabled "hold" placeholder button. Backend print endpoint unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
0c2ded4070 |
feat(pos): set a per-item note on each cart line in POS v2
CI/CD / CI · API (dotnet build + test) (push) Successful in 43s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 32s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m13s
CI/CD / CI · Admin Web (tsc) (push) Successful in 40s
CI/CD / CI · Website (tsc) (push) Successful in 48s
CI/CD / CI · Koja (tsc) (push) Successful in 52s
CI/CD / Deploy · all services (push) Successful in 3m9s
The cart store, order payload (create + add-items + offline), KDS ticket and receipt already supported per-item notes — but POS v2 had no way to enter one. Adds a note button on each cart line that toggles an inline input (e.g. "no sugar"); the note shows highlighted when set and rides along to the kitchen/bar ticket. No backend change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
2a24798a59 |
feat(audit): show actor full name + role in logs, click to view details
CI/CD / CI · API (dotnet build + test) (push) Successful in 44s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 31s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m11s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 3m39s
Logs showed the raw User ID (ActorName was almost never stored) and an English role enum. Now: - AuditController resolves each entry's actor to the employee's CURRENT full name and localized role at read time (joins Employees with IgnoreQueryFilters, so it also names soft-deleted staff and fixes all historical rows — no migration). - The audit table renders "Full name (Role)" with the role localized (fa/en/ar); the name is a button that opens an employee-details dialog. - New EmployeeDetailsDialog: fetches the employee and shows name, role, phone, base salary, and an "Open in HR" link; handles removed staff gracefully. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
6d71770f2e |
fix(auth): redirect already-signed-in users away from the register page
CI/CD / CI · API (dotnet build + test) (push) Successful in 44s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 31s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m10s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 51s
CI/CD / Deploy · all services (push) Successful in 2m55s
Mirrors the login guard: visiting /register while authenticated redirects to the dashboard home (/) instead of showing the form. Gated on _hasHydrated; shows a brief redirecting state. Reuses the existing auth.redirecting string. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
fd1f985597 |
fix(auth): redirect already-signed-in users away from the login page
CI/CD / CI · API (dotnet build + test) (push) Successful in 40s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m10s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 47s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 2m57s
Visiting /login while authenticated now redirects to the app (/pos) instead of showing the login form again. Guarded on _hasHydrated so the not-yet-rehydrated (null) session isn't misread, and renders a brief "redirecting" state instead of flashing the form. fa/en/ar strings added. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
d261c13175 |
docs(website): note KDS station tabs in the kitchen-display guide
CI/CD / CI · API (dotnet build + test) (push) Successful in 42s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 33s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m11s
CI/CD / CI · Admin Web (tsc) (push) Successful in 39s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 3m44s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
958addf734 |
feat(kds): filter the kitchen display by station (kitchen / bar)
CI/CD / CI · API (dotnet build + test) (push) Successful in 44s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Has been cancelled
CI/CD / CI · Admin Web (tsc) (push) Has been cancelled
CI/CD / CI · Website (tsc) (push) Has been cancelled
CI/CD / CI · Koja (tsc) (push) Has been cancelled
CI/CD / Deploy · all services (push) Has been cancelled
Complements the separate kitchen/bar printers with an on-screen split. The live order DTO now carries each item's prep station (MenuItem → Category → KitchenStation), and the KDS shows station tabs (All / Kitchen / Bar / …) that appear only once ≥2 stations are in play. Selecting a station shows just the tickets — and just the items within each ticket — for that station, so bar staff see drinks and kitchen staff see food. Single-station cafés see the board unchanged. fa/en/ar strings added. Note: order status is still per-order (one advance button); the split is for viewing/printing, not per-item status. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
8703e9cf87 |
docs(website): knowledge-base guide for printing (receipt, kitchen, bar)
CI/CD / CI · API (dotnet build + test) (push) Successful in 42s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m12s
CI/CD / CI · Admin Web (tsc) (push) Successful in 39s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 3m0s
Documents the new separate kitchen/bar print stations plus the customer receipt (factor): how to set printer IPs, create Kitchen/Bar stations, route menu categories to a station, and what auto-prints at send-to-kitchen vs payment. fa/en; auto-listed on /docs and in the sitemap. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
fb6a20eaa1 |
feat(print): separate kitchen & bar printers via print stations UI
CI/CD / CI · API (dotnet build + test) (push) Successful in 47s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 28s
CI/CD / CI · Dashboard (tsc) (push) Has been cancelled
CI/CD / CI · Admin Web (tsc) (push) Has been cancelled
CI/CD / CI · Website (tsc) (push) Has been cancelled
CI/CD / CI · Koja (tsc) (push) Has been cancelled
CI/CD / Deploy · all services (push) Has been cancelled
The print engine already routed items to per-station printers (MenuCategory → KitchenStation.PrinterIp, falling back to the branch kitchen printer) and prints the customer receipt to the receipt printer — but there was no UI to set it up. This exposes it: - Settings → "Kitchen & bar printers": create/edit/delete print stations, each with its own printer IP/port, with a per-station test print (gated by ManageKitchenStations). - Menu category editor: a "Print station" dropdown to route each category to a station (food → Kitchen, drinks → Bar); no station = branch kitchen printer. Result: kitchen and bar tickets print on separate printers, while the customer factor/receipt keeps printing on the receipt printer. fa/en/ar strings added. No backend/migration changes — purely wiring the existing capability. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
97bd63015f |
docs(website): knowledge-base guides for notifications & roles + sitemap docs pages
CI/CD / CI · API (dotnet build + test) (push) Successful in 45s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 28s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m9s
CI/CD / CI · Admin Web (tsc) (push) Successful in 37s
CI/CD / CI · Website (tsc) (push) Successful in 44s
CI/CD / CI · Koja (tsc) (push) Successful in 48s
CI/CD / Deploy · all services (push) Successful in 1m51s
The recent dashboard features shipped without knowledge-base coverage. Adds two
fa/en guides at meezi.ir/docs:
- "Notifications & sound" — bell/unread count, configurable sound (chime + volume
+ preview), desktop/Windows popups, browser-tab counter, and click-to-navigate
to the related page.
- "Roles & permissions" — base roles, defining custom roles via the permission
matrix (CRUD + sensitive actions), assigning them, and how page/action access
is enforced.
Also fixes a standing SEO gap: the sitemap listed only /docs, never the
per-feature /docs/{slug} pages — now all guide pages (fa+en) are included so the
whole knowledge base is crawlable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
3dfcb1585b |
feat(notifications): click a notification to jump to its related page
CI/CD / CI · API (dotnet build + test) (push) Successful in 42s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 28s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m9s
CI/CD / CI · Admin Web (tsc) (push) Successful in 37s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 2m45s
Every notification surface now deep-links to where the staff member needs to act: - bell dropdown: clicking an actionable notification navigates and closes the dropdown (platform broadcasts still expand inline to show their text) - notifications page: rows navigate to the right page - in-app toast: gains a "View" action button - desktop/Windows popup: clicking it focuses the tab and navigates Routing is now permission-aware via a single resolver (notification-routes.ts): a new-order alert sends a kitchen user to /kds, a cashier to /pos, and a floor user to /tables — never to a page their role can't open; a waiter call → /tables. This also fixes the old bug where table_call_waiter (which carries a referenceId) wrongly routed to /kds. Toast/desktop clicks navigate client-side through a small event bridge mounted in the dashboard shell. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
2cff5051ac |
feat(rbac): gate pages and action buttons in the UI by permission
CI/CD / CI · API (dotnet build + test) (push) Successful in 39s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 28s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m8s
CI/CD / CI · Admin Web (tsc) (push) Successful in 37s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 2m45s
Nav already hides pages a role can't view (NAV_REQUIRED_PERMISSION). This wraps the sensitive/CRUD action controls in <Can permission> so users only see what they can do (server still enforces): - POS/orders: void → VoidOrder, cancel → VoidOrder, transfer → EditOrder, pay/split → HandlePayments - menu/inventory/coupons/customers/reservations/expenses/taxes/branches: add/edit/delete buttons → the matching Create/Edit/Delete permission - reports CSV export → ExportReports; SMS send → SendSms, settings → ManageSmsSettings - home dashboard: revenue/orders KPI queries gated on ViewReports so non-report roles don't 403 on the landing page (Refund/discount/comp/cash-drawer have no UI control yet — no buttons to gate.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
53d90fa357 |
feat(rbac): full permission catalog in the custom-role matrix UI (fa/en/ar)
CI/CD / CI · API (dotnet build + test) (push) Successful in 42s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m7s
CI/CD / CI · Admin Web (tsc) (push) Successful in 37s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 3m24s
Mirrors the expanded backend catalog on the client: the Permission type and the custom-role permission matrix now expose all ~80 capabilities grouped into 16 sections (admin, branches, menu, inventory, taxes, staff, tables, orders, register, queue/kitchen, delivery, customers, coupons, marketing, reports, expenses), each with fa/en/ar labels. Nav visibility now maps each page to its View permission; taxes & branches become permission-driven (managers can view), leaving billing as the sole hard owner-only nav gate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
7a5ea75b50 |
feat(rbac): enforce permissions on every café write endpoint
CI/CD / CI · API (dotnet build + test) (push) Successful in 40s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m9s
CI/CD / CI · Admin Web (tsc) (push) Successful in 37s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Has been cancelled
CI/CD / Deploy · all services (push) Has been cancelled
Closes the gap where the custom-role matrix was defined but unenforced — most write endpoints only checked café membership, so the API would accept writes a role's UI hid. Adds EnsurePermission(...) to all mutating/sensitive endpoints across 32 controllers, mapped to the granular catalog: - menu/inventory/coupons/customers/expenses/reservations/taxes/branches → CRUD perms - tables/queue/kitchen-stations/print-settings → manage perms - orders → ProcessOrders / EditOrder / VoidOrder / UpdateOrderStatus / HandlePayments, payment corrections → ManageFinancials - HR → CreateStaff / ManageSchedules / ReviewLeave / View+ManageSalaries / ManageStaffCredentials (self-service clock-in/leave preserved) - reports → ViewReports, export → ExportReports, audit → ViewAuditLog - billing → ManageBilling, sms → SendSms/ManageSmsSettings, reviews → ManageReviews, discover/public profile → ManageDiscoverProfile, café settings → ManageCafeSettings, custom roles → ManageRoles Removes legacy [Authorize(Roles=...)] attributes that would have overridden the permission model (orders, branch-menu, pos-device, print). Manual discount/comp have no backend endpoint yet (discounts come from coupons) — gated on the POS UI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
236013f53c |
feat(rbac): full-CRUD permission catalog + per-role matrix
CI/CD / CI · API (dotnet build + test) (push) Successful in 55s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m9s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 1m33s
Expands the authorization catalog from 21 coarse page-level permissions to a granular set: View/Create/Edit/Delete per record module, plus distinct permissions for sensitive actions (VoidOrder, RefundOrder, ApplyDiscount, CompOrder, OpenCashDrawer, ExportReports) and the previously-uncovered pages (customers/CRM, SMS, reviews, financials, audit log, attendance, schedules). RolePermissions now derives Manager as "everything except owner-only governance" and gives Cashier/Waiter/Chef/Delivery sensible day-to-day defaults; owners refine further via custom roles. Effective permissions already flow to the client through AuthService, so no token-shape change is needed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
170a9aa7ac |
feat(dashboard): Notifications & sound settings panel (fa/en/ar)
CI/CD / CI · API (dotnet build + test) (push) Successful in 1m5s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m9s
CI/CD / CI · Admin Web (tsc) (push) Successful in 39s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 3m46s
New Settings → "Notifications & sound" leaf to make the alert channels changeable: toggle sound (+ picker with live preview + volume slider), enable desktop notifications (permission flow + test button), toggle the tab unread badge and in-app toasts. Strings added for fa/en/ar. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
149a4d88cd |
feat(dashboard): configurable notification sound, desktop popups & tab unread badge
CI/CD / CI · API (dotnet build + test) (push) Has been cancelled
CI/CD / CI · Admin API (dotnet build) (push) Has been cancelled
CI/CD / CI · Dashboard (tsc) (push) Has been cancelled
CI/CD / CI · Admin Web (tsc) (push) Has been cancelled
CI/CD / CI · Website (tsc) (push) Has been cancelled
CI/CD / CI · Koja (tsc) (push) Has been cancelled
CI/CD / Deploy · all services (push) Has been cancelled
Per-device notification preferences (localStorage) drive three new alert channels in the dashboard shell, all fed by the existing SignalR NotificationReceived events: - Sound: 6 selectable procedural Web Audio chimes + volume, no asset files. - Desktop/Windows popups via the Notification API, fired only when the tab is backgrounded (in-app toast covers the focused case). - Unread count on the browser tab: (N) title prefix + numbered favicon badge. useOrderAlerts is now the single orchestrator (sound + toast + desktop), each gated by prefs; topbar feed enableToasts disabled to avoid double toasts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
aebfa825cd |
feat: custom roles with per-permission matrix for café owners
- Owner can define named custom roles (e.g. Barista, Supervisor) with
color, description, and a fine-grained permission set (21 permissions
across 7 categories: admin, menu, staff, customer, reports, ops, kitchen)
- Employee assigned a custom role gets its permissions embedded in the
JWT at login (customPerms claim) and parsed by TenantMiddleware —
overrides the static EmployeeRole matrix for all API permission checks
- New endpoints: GET/POST/PATCH/DELETE /api/cafes/{id}/custom-roles and
PUT /api/cafes/{id}/employees/{id}/custom-role for assignment
- Dashboard Settings → Team & Staff → Custom Roles panel with grouped
checkbox matrix, group-level toggles, color preset picker, CRUD forms,
and employee-count display; translations in fa/en/ar
- EF migration adds CustomRoles table + nullable CustomRoleId FK on Employees
- POS slip now shows per-item notes on both thermal print and bill preview
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||
|
|
73a5e5183b |
fix(seed): IgnoreQueryFilters on all seeder queries + sitemap invalid date guard
CI/CD / CI · API (dotnet build + test) (push) Successful in 45s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 31s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m13s
CI/CD / CI · Admin Web (tsc) (push) Successful in 40s
CI/CD / CI · Website (tsc) (push) Successful in 47s
CI/CD / CI · Koja (tsc) (push) Successful in 59s
CI/CD / Deploy · all services (push) Successful in 3m45s
DemoSeedService / DemoMenuSeeder:
Add IgnoreQueryFilters() to every seeder lookup (Taxes, MenuCategories,
MenuItems). Soft-deleted rows still hold their PKs; without this a second
seed run after user-deletion throws a PK collision on the Tax or category
that was soft-deleted but is still in the index.
sitemap.ts:
Guard new Date(post.date) against empty / missing frontmatter date fields.
new Date("") = Invalid Date → broken <lastmod> in sitemap XML.
Fall back to the build-time date when the post date is absent or invalid.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||
|
|
1daa6d452c |
fix(admin): admin OTP login always failed — rate-limit key clobbered the OTP
CI/CD / CI · API (dotnet build + test) (push) Successful in 47s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 33s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m10s
CI/CD / CI · Admin Web (tsc) (push) Successful in 40s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 1m36s
The admin send-otp used the SAME Redis key ("otp:admin:{phone}") for both the
OTP value and the per-hour attempts counter. After storing the code and SMSing
it, the rate-limit StringIncrementAsync ran on that same key, turning the stored
value into code+1 (e.g. SMS said 337835, Redis held 337836). verify-otp then
compared the entered code to the incremented value, never matched, and returned
INVALID_OTP → 400. Admin OTP login could never succeed.
Give the attempts counter its own key ("otp:admin:attempts:{phone}"), exactly
like the main API (otp:{phone} vs otp:attempts:{phone}). Password login was
unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
24fbbcb01c |
fix(admin): don't prefill a fake phone on the admin login in production
CI/CD / CI · API (dotnet build + test) (push) Successful in 50s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m12s
CI/CD / CI · Admin Web (tsc) (push) Successful in 40s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 1m1s
CI/CD / Deploy · all services (push) Successful in 2m0s
The admin login OTP tab hard-coded phone "09120000001" as the initial value. In production that placeholder belongs to no SystemAdmin, so hitting "send code" returns NOT_FOUND → 404 (which WCDN then repaints as an HTML error page) — it looked like the login endpoint was broken. Keep the convenience prefill in development only; ship an empty field in production so the admin types their real number (e.g. the registered admin phone). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
a967e5d211 |
fix(admin): keep admin panel logged in — refresh the token instead of dying at 7 days
CI/CD / CI · API (dotnet build + test) (push) Successful in 39s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m6s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 44s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 2m35s
Prod diag showed every /api/admin/* call returning 401 with "IDX10223: token expired, ValidTo 06/09" — the admin access token was 6 days dead and nothing renewed it, so cafes/tickets/integrations/settings all loaded empty. The admin web (unlike the café dashboard) had NO refresh logic at all: it only ever sent the access token, and its 401 handler early-returned on any error code before the login redirect, so the admin wasn't even bounced to login — pages just showed no data. Client (admin-client.ts): add a silent refresh-on-401 mirroring the dashboard — one shared in-flight POST /api/admin/auth/refresh for a burst of 401s, replay the original request on success, force-logout only on a definitive 4xx, and ride out a transient failure (API restarting during deploy) without logging out. Backend (AdminAuthService): make refresh non-rotating + sliding (reuse the presented refresh token and re-store it) instead of revoke-and-mint, so the dashboard's many concurrent refreshes don't race the rotated token — same fix already applied to the main API. Also bump admin tokens 7d/30d → 30d/365d to match the main API, so the session is long-lived even before the first refresh round-trip. tsc clean; Admin.API builds clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
82d1cf8e9e |
fix(auth): stop logging users out on every deploy
CI/CD / CI · API (dotnet build + test) (push) Successful in 46s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 28s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m8s
CI/CD / CI · Admin Web (tsc) (push) Successful in 37s
CI/CD / CI · Website (tsc) (push) Successful in 44s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 2m50s
Diagnostic on prod confirmed the backend keeps sessions valid across deploys (stable 64-char JWT key, 30-day access tokens, 62 refresh tokens persisting in Redis with appendonly; redis/db never restart on deploy). The forced logout was client-side: 1. The axios refresh path treated ANY refresh failure as "session gone" and nuked the tokens. During the ~30s API restart window of a deploy, the refresh POST gets a 502/timeout (transient) → user kicked to /login. Now refresh distinguishes a definitive 4xx (truly invalid/expired refresh → log out) from a transient network/5xx failure (reject + keep the session; retry later). Refresh tokens are opaque Redis GUIDs, so they survive even a key rotation — the only thing that was breaking sessions was this over-eager logout. 2. PWA service worker served a stale app shell after an update, pointing at JS chunks the new build replaced. Added skipWaiting + clientsClaim + cleanupOutdatedCaches and a NetworkFirst handler for navigations so the HTML and its chunk refs always match the live deploy; hashed static stays CacheFirst. Net: a normal update no longer logs anyone out. tsc clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
837805b6b8 |
fix(brand): real Meezi launcher icon for meezi_app (was default Flutter)
CI/CD / CI · API (dotnet build + test) (push) Successful in 43s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m7s
CI/CD / CI · Admin Web (tsc) (push) Successful in 36s
CI/CD / CI · Website (tsc) (push) Successful in 44s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 24s
Replaced the placeholder Flutter launcher icons in all 5 mipmap densities (48/72/96/144/192) with the real Meezi mark, ready for the Android APK build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
d4d7b7e679 |
feat(website): full Meezi knowledge base with per-feature wireframes
CI/CD / CI · API (dotnet build + test) (push) Successful in 40s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m8s
CI/CD / CI · Admin Web (tsc) (push) Successful in 37s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 1m53s
Turns the static /docs page into a real help center. Every feature now has a
detail page at /docs/{slug} with a minimal wireframe mockup + concrete Persian
how-to steps (English mirror), grouped into 6 sections.
- guide-data.tsx: typed GUIDE_FEATURES (21 features — pos, tables, kds, queue,
reservations, menu, inventory, crm, coupons, sms, reviews, reports, expenses,
shifts, taxes, hr, branches, subscription, settings, qr-menu, koja) with
fa/en title, tagline, 5–8 steps, tips, tier badge, group, wireframe variant.
- wireframes.tsx: 7 reusable minimal line-art variants (board/order/menu/list/
dashboard/form/phone), brand-colored, RTL-aware.
- docs/[slug]/page.tsx: dynamic guide page (hero, wireframe + numbered steps,
tips, prev/next, support CTA); generateStaticParams + generateMetadata; 404
for unknown slugs.
- docs/page.tsx: module cards now sourced from GUIDE_FEATURES, grouped, linking
to the detail pages.
Verified via SSR: index lists all 21, detail pages render titles + wireframe,
en mirror 200, unknown slug 404, tsc clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
32a7cf5b25 |
ops: nightly DB backup + self-hosted uptime monitoring
CI/CD / CI · API (dotnet build + test) (push) Successful in 41s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m10s
CI/CD / CI · Admin Web (tsc) (push) Successful in 37s
CI/CD / CI · Website (tsc) (push) Successful in 44s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 1m48s
Backup (production data-loss protection — was none):
- meezi-backup sidecar in docker-compose.yml runs pg_dump nightly at 02:00
Tehran, gzip, 14-day rotation, atomic .partial→final, into ./backups
(persists across deploys; rsync off-box per RESTORE.md).
- Wired into the deploy job (up -d --no-deps backup); takes one dump on boot.
- scripts/backup/pg-backup-loop.sh + RESTORE.md (restore + off-box guidance).
Monitoring:
- docker-compose.monitoring.yml: Uptime Kuma stack (own volume), stood up
once, independent of app deploys.
- Caddyfile status.{$DOMAIN} route; docs/monitoring.md lists the exact
monitors (incl. /q guest-menu 200 check) + TLS-expiry alerts (catches the
~90-day cert breakage early) + alert-channel setup.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
d407f0b3e9 |
fix(brand): real Meezi icon/favicon on website + admin (was missing)
CI/CD / CI · API (dotnet build + test) (push) Successful in 40s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m10s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Has been cancelled
- web/website: manifest referenced /icon-192.png and /icon-512.png that didn't exist (broken favicon). Added the real transparent Meezi mark (32/180/192/512) + wired icons into metadata. OG image stays dynamic. - web/admin: had no metadata or icons at all. Added title template, favicon/apple icons (icons/ dir), themeColor, noindex. Dashboard + Koja already carry the real logo; web apps are now consistent. Mobile launcher icons will be handled with the Android packaging task. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
72ab09189c |
fix(brand): real transparent Meezi icon + guest-menu image placeholder
CI/CD / CI · API (dotnet build + test) (push) Successful in 42s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m9s
CI/CD / CI · Admin Web (tsc) (push) Successful in 39s
CI/CD / CI · Website (tsc) (push) Successful in 44s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 3m24s
- Icons/favicon were a plain solid-green square (a 547B placeholder). Replaced with the actual Meezi mark (green rounded square + menu lines) on transparent corners, generated at 32/48/180/192/512 + a full-bleed green maskable-512. Wired 32/48 favicon + 180 apple-touch-icon into the panel and /q metadata. Copied the same icons to Koja for consistent branding. - Guest QR menu showed blank muted boxes for items without a photo. Added a minimal themed café-cup placeholder (MenuImageFallback) across all four layouts so the menu looks intentional. (Admin/POS already had placeholders.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
456a446850 |
feat(meta): per-page titles + favicon/app icons + PWA across the panel
CI/CD / CI · API (dotnet build + test) (push) Successful in 40s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 31s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m9s
CI/CD / CI · Admin Web (tsc) (push) Successful in 39s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 2m54s
The app had no metadata anywhere — pages showed no <title> and no favicon or app icon. Added: - Root metadata in [locale]/layout: title default + "%s — میزی" template, description, icons (favicon + apple-touch-icon → /icons), manifest link, appleWebApp, themeColor viewport, noindex (private panel). - Per-page title on all 22 dashboard route pages (داشبورد, منو, گزارشها, …). - Guest menu (/q) layout: own title + icon + manifest. PWA + favicon now use the Meezi icon everywhere. Verified via SSR: titles render (e.g. "منو — میزی") and icon/manifest/apple-touch-icon links present. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
4523c8861f |
feat(ui): grouped thousands separators for price/amount inputs
Price fields showed raw digits (1490000) while typing — hard to read for Toman amounts. New shared MoneyInput groups as you type (1,490,000), accepts Persian/Arabic digits, and reports a raw digit string so callers keep parsing unchanged. Applied to menu item price, branch price override, expense amount, and payment-correction replacement amount. Displays already group via formatCurrency (incl. the QR guest-menu preview). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
a855cf1d80 |
feat(auth): admin-issued café recovery key login
CI/CD / CI · API (dotnet build + test) (push) Successful in 5m6s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 1m30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m10s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 1m0s
CI/CD / Deploy · all services (push) Successful in 5m31s
Platform admins can generate a permanent recovery key per café (admin
panel → Cafés). The café Owner uses it to sign in when OTP access is lost;
once authenticated, all server-side data syncs as normal (data is per-café
on the server, the device only caches it).
Backend:
- Cafe.RecoveryKeyHash (SHA-256, unique index) + RecoveryKeyCreatedAt; migration
- RecoveryKeyGenerator util: MZ-XXXXX-XXXXX-XXXXX-XXXXX, ~190-bit entropy,
stored as SHA-256 (API-token pattern — raw key shown once, never retrievable)
- Admin: POST/DELETE /api/admin/cafes/{id}/recovery-key (key returned once);
café list now reports HasRecoveryKey + RecoveryKeyCreatedAt
- Login: POST /api/auth/login-key → exact-hash lookup → resolves café Owner →
issues normal JWT; rate-limited (auth-otp), suspended/no-owner guarded, logged
Admin UI: per-café generate / regenerate / revoke with one-time reveal + copy.
Dashboard login: discreet "ورود با کلید بازیابی" link → key field. fa/en/ar.
86 tests pass; all tsc clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
76d4434581 |
fix(qr): guest menu 500 (SSR) + remove café discovery from owner panel
1. The /q/{code} guest menu returned HTTP 500 on every load. Root cause:
menu-item-model-viewer.tsx did a top-level `import "@google/model-viewer"`,
a browser-only lib that touches `self` at module evaluation. Next pulled
it into the server module graph (page → qr-guest-menu → qr-menu-3d-sheet →
model-viewer) and SSR crashed with "self is not defined". Now the library
is imported lazily inside useEffect (client-only); a poster placeholder
shows until the custom element registers. Verified /q/* now returns 200.
2. Removed the "discover" (browse other cafés) item from the café owner
sidebar — café discovery belongs in Koja, not the owner panel. The owner
still manages their OWN Koja listing from Settings.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
9765491f6f |
fix(prod): payment/tax gateways never fake success outside Development
CI/CD / CI · API (dotnet build + test) (push) Successful in 41s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m7s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 51s
CI/CD / Deploy · all services (push) Successful in 1m31s
Production-readiness audit fixes — every mock fallback is now gated on IsDevelopment; in production these paths fail loudly instead: - ZarinPal/Tara/SnappPay init: missing credentials returned a MOCK payment URL whose callback verified as paid — a café could activate a paid plan without paying. Now: "Payment gateway is not configured." - Tara/SnappPay verify: a forged MOCK-* trace/token on the callback was accepted as a verified payment in any environment. Now rejected outside Development. - Taraz (سامانه مودیان): returned a fake MOCK-TARAZ tracking code as if invoices reached the tax authority. Now returns an honest error (the real integration is not built yet). - Admin integrations: NextPay/Vandar removed — they were listed but have no gateway implementation (selecting them silently used ZarinPal). - docker-compose: ASPNETCORE_ENVIRONMENT default flipped Development → Production so a missing env var can never run prod in dev mode. 86 tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
00649d0248 |
feat(sms): bring-your-own-provider — cafés use their own SMS account
CI/CD / CI · API (dotnet build + test) (push) Successful in 40s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m8s
CI/CD / CI · Admin Web (tsc) (push) Successful in 37s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 5m16s
The platform no longer sells SMS. Each café saves its OWN Kavenegar API key + sender line (new Cafes columns + migration) and campaigns are sent and billed through that account. Backend: - GET/PUT /sms/settings (Manager/Owner; key echoed masked, verified against the provider before saving) - campaign + balance use the café's credentials; SMS_NOT_CONFIGURED error when missing; plan-tier SMS gating removed everywhere (PlanLimitChecker, SmsMarketingService, billing status) - platform Kavenegar config stays ONLY for login OTPs (env/DB) - design-time DbContext factory so `dotnet ef migrations add` works without booting the host Dashboard: - SMS screen: provider-settings card, not-configured callout, campaign form disabled until configured; quota bar removed (usage stays as info) - subscription screen + plan comparison no longer show SMS limits Admin panel: - Kavenegar/SMS section removed from integrations (request field now optional; stored OTP config untouched) - SMS limit field removed from the plan editor - nav label "درگاه و پیامک" → "درگاه پرداخت و AI" fa/en/ar translations. 86 tests pass; all tsc clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |