b0896dc777660b8efc57e243743537910ef84089
229 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b0896dc777 |
feat(pos): bridge the card terminal through the print agent + LAN auto-detect
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 1m8s
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 3m29s
The card-terminal integration only ever worked when the API could reach the terminal's IP directly — impossible for the cloud deployment, where the terminal sits on the café LAN (the same wall the Print Agent already climbs for printers). And the terminal IP had to be typed by hand. Both fixed by reusing the agent. Cloud→LAN relay: - PrintAgentRegistry.SendPaymentAsync sends a PaymentRequest to the café's online agent and awaits its ack (PaymentResult on the hub); 95s window for the customer. - PosDeviceService now prefers an online agent (branch-matched, else any café agent) to relay POST /pay over the LAN, and falls back to the direct HTTP call only when no agent is connected (on-prem). Agent errors map back to POS_DEVICE_*. - Agent (Program.cs + PosTerminal.cs) handles PaymentRequest → POSTs the amount to the terminal's local http://ip:port/pay and reports approval/decline/timeout. Auto-detect: - Registry.ScanAsync + hub ReportScan; POST /print-agents/scan asks online agents to scan their /24 for given ports and merges the hosts found. - Agent NetworkScanner scans the LAN (:9100 printers, :8088 terminals) with a short per-host TCP probe. - Dashboard: a "تشخیص خودکار" (auto-detect) button on the POS-device, receipt and kitchen IP fields scans via the agent and fills the IP:port from a found host. Backend + agent build clean; dashboard tsc clean. NOTE: the agent app is not in CI — it must be rebuilt and redeployed on the café PC to gain these handlers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
f368765419 |
fix(pos): charge the server amount, and don't book unconfirmed card payments
CI/CD / CI · API (dotnet build + test) (push) Successful in 43s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
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 2m49s
Two go-live money-correctness bugs in the POS pay flow (deferred TODO #1/#2): #2 — pay against the server's amount, not a client recompute. The pay sheet took `orderAmountDue(payTarget) || total`, so any time the server figure was absent/zero it silently fell back to the POS's own 9% tax recompute. The backend records whatever amount the client posts (it only uses its own order.Total to decide closure), so a client/server mismatch books the wrong cash-drawer amount. Now a real (server) order always charges orderAmountDue(serverOrder); only a genuinely-local offline order — which has no server figure — uses the client total. #1 — don't record a card payment that wasn't confirmed. A connected terminal that declines already throws POS_DEVICE_* and records nothing. But when no terminal is wired up the request is "skipped" and the card was booked as paid with zero proof it cleared. Now, when the card leg isn't machine-confirmed, the cashier must confirm "card approved on the terminal?" before it's recorded; cancel records nothing. Also raise the shared AlertDialog to z-[80] so a confirmation renders above the POS pay sheet (z-[60]) and its busy overlay (z-[70]); still below toasts. tsc clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
197f6f2d38 |
feat(print): dashboard UI for print servers + auto-discovered printer pickers
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 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 3m44s
Phase 4 (final). Settings → Printers now has a "Print servers" section: add a print server (issues a one-time pairing code with steps), see each agent's online status, its auto-discovered printers, test any of them, and revoke. Receipt, kitchen and per-station printers can now be picked from a dropdown of discovered devices instead of typing an IP (manual IP stays as fallback). Wires the device mappings through the branch print-settings + kitchen-station DTOs/services and adds the device-test endpoint. fa/en/ar strings added. Completes the cloud↔LAN print-agent feature (entities/hub → routing → agent → UI). Remaining polish: agent system-tray + run-at-login + installer, optional LAN scan. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
7d5af0c81b |
feat(print): Windows print agent — the cloud↔LAN bridge (Phase 3)
CI/CD / CI · API (dotnet build + test) (push) Successful in 39s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 33s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m6s
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 29s
A standalone net10.0-windows console app (agent/Meezi.PrintAgent) installed on the café cash PC. It pairs with a one-time code (POST /print-agent/claim), stores the token in %APPDATA%, holds a SignalR connection to /hubs/print-agent (retries forever, re-reports on reconnect), discovers installed printers via WMI (USB + network, classified), and prints jobs it receives by writing raw ESC/POS bytes — winspool RAW passthrough for installed printers, raw TCP for ip:port devices — acking each job back. Not in the API solution or CI (own net10.0-windows build); see agent/README.md for build/publish/pair. Builds clean; startup + pairing flow smoke-tested. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
9e47a4e60c |
feat(print): route print jobs through a local agent, fall back to TCP
CI/CD / CI · API (dotnet build + test) (push) Successful in 47s
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 49s
CI/CD / Deploy · all services (push) Successful in 1m40s
Phase 2. NetworkPrinterService now builds the ESC/POS bytes (as before) and dispatches them via a new router: if the receipt/kitchen/station printer is mapped to a PrintDevice whose agent is online, the bytes are sent to that agent over the hub and we await its ack; otherwise it falls back to a direct TCP connection (raw IP), so existing on-prem/reachable printers keep working unchanged. Adds nullable mapping columns Branch.ReceiptPrintDeviceId / KitchenPrintDeviceId and KitchenStation.PrintDeviceId (additive migration), plus TestPrintDeviceAsync for testing an agent printer. The cloud can now reach LAN/USB printers it never could. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
cb57c61a11 |
feat(print): cloud↔local print-agent foundation (hub, pairing, registry)
CI/CD / CI · API (dotnet build + test) (push) Successful in 43s
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 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) Has been cancelled
First phase of auto-discovered printing for cloud-hosted cafés whose printers are
on the local network (the cloud can't reach a LAN/USB printer directly). Adds:
- PrintAgent + PrintDevice entities (+ additive migration) — a per-café local
bridge and the printers it reports.
- PrintAgentHub (/hubs/print-agent): agents connect outbound, authenticated by a
token in access_token (not the user JWT); ReportPrinters upserts devices,
PrintJob is pushed to the agent, JobResult/Heartbeat come back.
- PrintAgentRegistry (singleton): tracks connected agents and dispatches a job to
one, awaiting its ack with a timeout.
- Pairing: POST /cafes/{id}/print-agents/pairing-code (ManagePrintSettings) issues
a short one-time code; anonymous POST /print-agent/claim redeems it for a
long-lived token (only its SHA-256 hash is stored). List + revoke endpoints,
online status from the registry.
Inert until Phase 2 routes jobs through it and the agent app (Phase 3) connects.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
67450393fc |
fix(pos): cashier can't delete/reduce an item already sent to the kitchen
CI/CD / CI · API (dotnet build + test) (push) Successful in 42s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 34s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m7s
CI/CD / CI · Admin Web (tsc) (push) Successful in 41s
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 2m54s
On the POS, once a line is fired to the kitchen its sent quantity is the locked portion: a user without the VoidOrder permission (the default cashier) can no longer remove that line or decrease it below what was sent — otherwise they could send food and then erase it from the order (charge less / pocket cash). The unsent portion of a line stays freely editable, and adding more is always allowed. The delete button is replaced by a lock icon on sent lines, and the minus button is disabled at the sent floor. Gated by VoidOrder, so owners/managers with the permission are unaffected. Mirrors the server-side order-cancel lock. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
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> |