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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
- 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>
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>
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>
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>
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>
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>
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>
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>
--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>
nuget-group aggregates nuget.org-proxy (Liara) and nuget-runflare-proxy
(Runflare) — automatic fallback if one upstream is down.
npm-proxy and docker-hub-proxy names match exactly, no changes needed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
provision.sh: Docker proxy defaults to registry-1.docker.io (works directly
from VPS). Set DOCKER_MIRROR_URL/USER/PASS env vars to route through
docker-mirror.liara.ir once Liara credentials are obtained.
update-docker-upstream.sh: swap Docker proxy upstream at any time without
re-running the full provision (useful after getting Liara credentials).
indexType auto-selects: HUB for docker.io direct, REGISTRY for Liara/Harbor.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
github.server_url returns 'http://gitea:3000' (Gitea ROOT_URL using Docker
service name). CI job containers run on an isolated network and can't resolve
the 'gitea' hostname.
host-gateway maps to the Docker bridge IP (172.17.0.1). Gitea publishes
port 3000 on all interfaces, so http://gitea:3000 becomes reachable inside
every job container via the bridge.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
actions/checkout@v4 is a JS action executed inside the job container:
- dotnet/sdk:10.0 has no Node.js → exit 127
- node:20-alpine has no git → checkout fails
Fix: manual git clone via shell using http.extraheader for token auth.
Token never appears in process list or git log. deploy job (self-hosted:host)
keeps actions/checkout — the act_runner image has both node and git.
Also removes defaults.run.working-directory from Node.js jobs (the checkout
step must start in workspace root, not web/<app>).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>