Commit Graph

122 Commits

Author SHA1 Message Date
soroush.asadi 86bbefb9e3 Fix admin-web build: drop invalid --webpack flag on Next.js 14
The admin app runs Next.js 14.2.18, where `next build --webpack` is an
unknown option (the flag only exists in Next 15+). This broke the CI
admin-web image build. Other web apps stay on the flag since they're on
Next 16.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 05:57:31 +03:30
soroush.asadi 8ca2cae988 Pull Docker images from Nexus connector port 8087
The Docker daemon reaches the Nexus Docker group over the dedicated
connector port 8087 (its registry mirror), not the main 8081 HTTP port,
which caused HTTPS-to-HTTP pull failures in CI. Repoint all image refs to
171.22.25.73:8087 at the connector root; npm and NuGet stay on 8081.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 05:17:21 +03:30
soroush.asadi 09c55669ca Add proforma invoice step to subscription checkout
Insert a factor/invoice page between plan selection and payment showing
billing-period choice, line items, and totals before redirecting to the
gateway, moving payment-method selection to where the charge happens.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 00:29:17 +03:30
soroush.asadi 639573dfde Add dashboard chrome to POS and collapsible sidebar
Wrap the POS terminal in the sidebar + topbar layout via a nested
fullscreen layout, and make the sidebar collapse to an icon-only rail
with a persisted toggle so operators keep navigation on the POS screen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 00:28:56 +03:30
soroush.asadi b6e4f83035 Migrate Kavenegar SMS to official .NET SDK
Replace the raw HttpClient implementation with the Kavenegar NuGet SDK
(v1.2.4) for OTP, single, and bulk sends plus account info, wrapping the
synchronous SDK calls and translating its exceptions. Register the
service as scoped instead of via AddHttpClient.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 00:28:28 +03:30
soroush.asadi e8cd6d3282 Route all package mirrors through local Nexus
Point Docker, NuGet, and npm pulls at the Nexus group repos on
171.22.25.73:8081 for both CI/CD and local builds, so the pipeline and
developers no longer depend on Docker Hub, MCR, nuget.org, or npmjs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 00:28:07 +03:30
soroush.asadi 62bd7a12f5 Build Next.js apps with Webpack instead of Turbopack
Next 16 defaults `next build` to Turbopack, which requires native SWC
bindings unavailable for Alpine musl from our npm mirror (only the WASM
fallback loads). Pass --webpack so the build uses the WASM SWC fallback
and succeeds inside the Docker images.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 17:35:28 +03:30
soroush.asadi 634ebe4856 Add .gitignore for Koja app
Ignore build artifacts (tsbuildinfo, .next) and Capacitor native
output directories.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 17:25:31 +03:30
soroush.asadi 377ef109cd Make Koja native deps optional to unblock web Docker build
Move Capacitor and cordova-plugin-pushe to optionalDependencies. They are
only needed for the native mobile shell, are never imported by the Next.js
source, and are not served by the Liara npm mirror — so installing them as
hard dependencies broke the web image build. As optional deps, npm skips
them when the mirror can't resolve them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 17:21:40 +03:30
soroush.asadi 99aa6b7048 Centralize OTP dev logging in Kavenegar SMS service
Move the dev-mode OTP logging into KavenegarSmsService so consumer and
admin auth flows no longer duplicate the fallback log.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 17:15:11 +03:30
soroush.asadi c68cca4f17 Add OTP login flow and multi-cafe role switching
Introduce an OTP input box on login/register, surface user roles and a
cafe chooser, add a dashboard switch button in the POS screen, and
register OTP validators explicitly to survive Docker layer caching.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 17:14:46 +03:30
soroush.asadi 923a00b113 Redesign thermal receipts with Vazirmatn font and cafe branding
Embed Vazirmatn web font in printed bills, add branded header with logo
and tagline, and wait for fonts to load before printing for clean output.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 17:14:32 +03:30
soroush.asadi 963d02a265 Add push notifications (Pushe) + Capacitor shell for Koja
Iran-safe push for the Koja Android app (Cafe Bazaar / Myket / direct APK):

Backend
- PushDevice entity + EF migration; idempotent device register/unregister.
- IPushSender / PusheNotificationSender (Pushe REST) — SendToTopic for
  marketing (city-{slug}) and saved-café (cafe-{slug}) pushes, SendToTokens
  for targeted order/reservation updates.
- Public register/unregister endpoints + authorized topic broadcast.

App
- capacitor.config.ts (native WebView loads the live PWA via server.url).
- push.ts Pushe glue: topic helpers + backend device registration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 17:06:42 +03:30
soroush.asadi 289c808257 Rename public discovery app from "finder" to "koja"
Rebrand the public café-discovery app: directories web/finder→web/koja and
docker/finder→docker/koja, plus all service wiring (docker-compose, Caddy
subdomain koja.meezi.ir, env vars KOJA_PORT / NEXT_PUBLIC_KOJA_URL, CI
workflows) and the app's display name (Koja / کجا).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 17:02:22 +03:30
soroush.asadi 16cff8730b feat : kavenegar otp added 2026-05-29 10:18:47 +03:30
soroush.asadi 27e61d257e Set Kavenegar OTP template to meeziotp
Template content: کد ورود : %token / میزی

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 02:55:02 +03:30
soroush.asadi fc21471131 Native thermal printing via iframe — 80mm, RTL, no blank tail
Problem: window.print() on the main page used A4 height (blank paper
after receipt), no RTL direction, and Tailwind styles leaked into print.

Solution — iframe isolation:
- lib/thermal-print.ts: builds a self-contained HTML document
  (@page { size: 80mm auto; margin: 0 }, html { direction: rtl })
  and fires it through a hidden off-screen <iframe>. The iframe
  document contains only the receipt so height == content height.
- pos-slip-modal.tsx: Print button calls printThermal(buildThermalDocument())
  instead of window.print(). Preview panel is unchanged (screen only).
- pos-receipt-print.css: updated @page + direction as fallback for any
  remaining window.print() callers.

Works with USB driver (Atom A300) as default printer — OS print spooler
receives the job exactly as if it were any other document.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 02:52:46 +03:30
soroush.asadi 42d7667735 Fully implement Kavenegar SMS support
Core changes:
- ISmsService: add SendBulkAsync (batches of 200) + GetAccountInfoAsync
- KavenegarSmsService: POST requests, sender number config, bulk send
  via comma-separated receptors, account balance, full error code mapping
  (HTTP 400-432), enabled-flag check before any send
- SmsMarketingService: replaced per-recipient loop with SendBulkAsync
- SmsController: new GET /sms/balance endpoint returns Kavenegar credit
- SmsDtos: SmsBalanceDto
- IntegrationDtos + PlatformIntegrationService: SenderNumber field
- appsettings.json + docker-compose: Kavenegar__SenderNumber = 90005671

Dashboard:
- sms-screen: char counter, SMS parts indicator (Persian 70/67 chars,
  Latin 160/153), account balance card, sender line display, result banner

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 02:38:06 +03:30
soroush.asadi b78f2affb6 Move POS page to fullscreen layout for full viewport width
POS terminal needs the entire screen — the dashboard navigation
sidebar (224px) was eating into the cashier's working space.
Moving /pos from (dashboard) to (fullscreen) gives the POS the
full viewport with no chrome. Auth redirect and CafeThemeProvider
are applied directly in the new page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 02:20:43 +03:30
soroush.asadi a21cb7dd8e fix(dashboard): fallback for crypto.randomUUID on HTTP (non-secure context)
crypto.randomUUID() is only available over HTTPS. Add a timestamp+random
fallback so the dashboard works on plain HTTP during development/IP access.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 02:01:21 +03:30
soroush.asadi 83758fe68a fix(admin-web): add .gitkeep to public/ so Docker COPY finds /app/public
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 01:46:56 +03:30
soroush.asadi c87c40ffe6 fix(website): add .gitkeep to public/fonts so Docker COPY finds /app/public
Empty directories are not tracked by git — without this the runner stage
COPY --from=builder /app/public ./public fails with "not found".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 01:31:56 +03:30
Soroush.Asadi b8e56b8f83 ci: retrigger build with fixed Dockerfiles 4 2026-05-28 23:13:23 +03:30
Soroush.Asadi 112113dbfc ci: retrigger build with fixed Dockerfiles 3 2026-05-28 23:07:03 +03:30
soroush.asadi 060f724f7c fix(website): revert generateStaticParams params to non-Promise
generateStaticParams receives plain params (not Promise).
Only page/layout default exports get Promise params in Next.js 15+.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 22:56:50 +03:30
soroush.asadi 98a7efc719 fix(website): update all route/layout params to Promise for Next.js 16
Next.js 15+ requires params to be typed as Promise<{...}> and awaited.
Fixed 17 files: all [locale] pages, layouts, and blog [slug] page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 22:46:09 +03:30
Soroush.Asadi 5f4ec511cb ci: retrigger build with fixed Dockerfiles 2 2026-05-28 22:29:34 +03:30
Soroush.Asadi 3b234df4f9 ci: retrigger build with fixed Dockerfiles 2026-05-28 22:29:02 +03:30
soroush.asadi 1559ee95c7 fix(website): update route params type for Next.js 16
Next.js 15+ changed dynamic route params to Promise<...>.
Update GET and POST type signatures in blog comments route.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 22:20:14 +03:30
soroush.asadi aa4612e06b fix: use Liara mirrors directly for images with Nexus OCI proxy issues
- aspnet:10.0, postgres:16-alpine, redis:7-alpine all fail on first
  fetch through Nexus proxy (OCI manifest format bug in Nexus)
- Change DOTNET_ASPNET_IMAGE default to mcr-mirror.liara.ir directly
- Change postgres/redis service images to docker-mirror.liara.ir
- CI service containers (api-build job) also use Liara directly
- All images parameterized so ENV_FILE can override for any registry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 22:08:07 +03:30
Soroush.Asadi ce41b2306d ci: retrigger build with fixed Dockerfiles 2026-05-28 21:36:57 +03:30
Soroush.Asadi aaf61e0b98 Merge branch 'main' of https://github.com/codesoroush/Meezi 2026-05-28 21:03:02 +03:30
soroush.asadi 979dcaa949 fix: route all Docker builds through local Nexus mirrors
- All Node Dockerfiles rewritten with NODE_IMAGE + NPM_REGISTRY build args
  defaulting to local Nexus proxies (171.22.25.73:5000/library/node:20-alpine
  and http://mirror:8081/repository/npm-group/)
- Add extra_hosts: mirror:host-gateway to every build section so the
  mirror hostname resolves during docker build
- Replace nuget.org with nuget.docker.config (Nexus mirror) in api/admin-api
  Dockerfiles to fix NuGet restore in Iranian network
- Rewrite admin-web and website Dockerfiles (were referencing non-existent
  meezi-node:20-alpine base image with no npm install step)
- Update dotnet image defaults to 171.22.25.73:5002 MCR proxy in admin-api
  and docker-compose.admin.yml

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 21:01:43 +03:30
Soroush.Asadi b1365c501e CI CD 2 2026-05-28 20:43:35 +03:30
Soroush.Asadi 96dad89016 CI CD 2026-05-28 19:50:23 +03:30
Soroush.Asadi d5a3056bfb Merge branch 'main' of https://github.com/codesoroush/Meezi 2026-05-28 19:28:56 +03:30
soroush.asadi 25154f9dd9 fix(ci): set PATH in deploy job so docker binary is found
act runner (host mode) inherits a minimal PATH from the process
environment — docker is not found even though it is installed.
Explicitly include all standard locations plus /snap/bin.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 19:28:15 +03:30
Soroush.Asadi 665de97c49 ci : workflow updated 15 2026-05-28 19:18:24 +03:30
soroush.asadi 34040503cf docs: rewrite DEPLOY.md with self-hosted setup guide
Replaces outdated Arvan Cloud instructions with the current
self-hosted stack: Gitea CI, Nexus mirror, Docker Compose,
IP-based access today and Caddy+domain tomorrow.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 19:06:28 +03:30
soroush.asadi cb80afaf42 fix(ci): replace actions/checkout@v4 in deploy job with shell git
Node.js is not in PATH on the self-hosted:host runner, so JS actions
(actions/checkout@v4) fail with "cannot find node". Use the same shell
git init/fetch/checkout pattern used in all other jobs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 18:57:58 +03:30
soroush.asadi 88a9f96108 feat(infra): parameterize secrets, add Caddy reverse proxy for domain
All hardcoded passwords/keys replaced with env vars so .env controls
everything in both dev and production:
  - DB_PASSWORD, DB_CONNECTION_STRING, JWT_KEY
  - CORS_ORIGIN_*, ASPNETCORE_ENVIRONMENT
  - All ZarinPal/Kavenegar/Snappfood secrets

New files for tomorrow's domain setup:
  - Caddyfile        → routes all subdomains with auto TLS
  - docker-compose.caddy.yml → adds Caddy service to the stack

.env.example now has clear TODAY (IP) vs TOMORROW (domain) sections.
Fixed hardcoded ZarinPal MerchantId in docker-compose.full.yml.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 18:54:55 +03:30
soroush.asadi 0a33497d40 feat(admin-web): add web/admin to repo
Initial commit of the Super-Admin web panel (Next.js + TypeScript).
CI admin-web-check job was failing because the directory was never
tracked in git.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 18:46:25 +03:30
Soroush.Asadi f717c02467 Merge branch 'main' of https://github.com/codesoroush/Meezi 2026-05-28 18:34:56 +03:30
soroush.asadi 539165b6bb fix(ci): replace python3 with cat heredoc; sync local registry IPs
python3 is not in PATH inside dotnet/sdk:10.0 container — replace the
"Write NuGet config" step with a cat heredoc which works in any container.

Also syncs GitHub with the Gitea-side changes:
  - All images pulled from local Nexus mirrors (no internet round-trip)
      171.22.25.73:5000 → docker-hub-proxy (node, postgres, redis)
      171.22.25.73:5002 → mcr-proxy        (dotnet/sdk)
  - npm steps already on npm-group (Liara + Runflare fallback)
  - docker-compose.mirror.yml: expose port 5002 for mcr-proxy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 18:34:06 +03:30
Soroush.Asadi da81be926a ci : workflow updated 13 2026-05-28 18:24:29 +03:30
Soroush.Asadi 37afa965e7 ci : workflow updated 12 2026-05-28 18:08:49 +03:30
soroush.asadi 720bab457e feat(mirror): add Liara npm/PyPI/Ubuntu APT mirrors to Nexus
Adds mirrors/nexus/add-liara-mirrors.sh that provisions:
  - npm-liara-proxy  → https://package-mirror.liara.ir/repository/npm/
  - npm-group        → npm-liara-proxy + npm-proxy (Liara first, Runflare fallback)
  - pypi-liara-proxy → https://package-mirror.liara.ir/repository/pypi/
  - pypi-group       → pypi-liara-proxy + pypi-proxy
  - ubuntu-proxy     → http://linux-mirror.liara.ir/repository/ubuntu/
  - ubuntu-security-proxy → http://linux-mirror.liara.ir/repository/ubuntu-security/

Also updates CI npm install steps to use npm-group instead of npm-proxy
so all four Node.js jobs benefit from the Liara-first, Runflare-fallback
group from day one.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 17:35:01 +03:30
soroush.asadi f825c72ca2 perf(ci): replace apk add git with Gitea archive API for Node.js jobs
apk add git downloads from dl-cdn.alpinelinux.org (Fastly CDN) which is
slow/blocked in Iran — caused 6m+ checkout times.

New approach: wget the repo tarball from Gitea's archive API endpoint.
wget + tar (busybox) are already in node:20-alpine — no package install.
Gitea is on the same machine as the runner = download is instant.

GET /api/v1/repos/{owner}/{repo}/archive/{sha}.tar.gz
Authorization: Bearer {token}

dotnet/sdk jobs unchanged — Debian base has git pre-installed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 17:12:49 +03:30
soroush.asadi ca17cffee6 fix(ci): write NuGet config inline to allow HTTP source (NU1302)
NuGet 10 blocks HTTP sources by default. allowInsecureConnections=true
must be set in a config file — the --source CLI flag doesn't support it.

Write the config to /tmp/nuget.ci.config inline in the step so there is
no dependency on any file existing in the workspace.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 16:55:19 +03:30
soroush.asadi 32d9900e07 fix(ci): use --source flag instead of --configfile for NuGet restore
--configfile nuget.mirror.config fails when the file isn't present in
the workspace (e.g. when Gitea is behind GitHub on commits).

--source inline URL is simpler, self-contained, and replaces all
configured sources — no extra file dependency in CI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 16:39:36 +03:30