# ZarinPal Merchant Analytics — Frontend Persian-first, RTL merchant analytics dashboard built with SvelteKit 2, Svelte 5, strict TypeScript, Tailwind CSS v4, and a generated OpenAPI client contract. The application is a client-rendered static SPA. In development, Vite serves it and proxies same-origin `/api` requests to the Go backend. In production, it is built into static files and served by the deployment repository's unprivileged Nginx container. Authentication remains backend-owned through an HttpOnly cookie; credentials and tokens are never stored in browser storage. ## Local setup ### Prerequisites - Node.js 20.19+ or 22.12+ - npm - The backend API running at `http://127.0.0.1:8080` - PostgreSQL and Redis running for the backend The frontend does not connect directly to PostgreSQL or Redis. Those external services are required by the backend: PostgreSQL stores application/analytics data, while Redis coordinates and caches background work. Follow the backend README to start them, apply migrations, import the dataset, create the demo account, and run both `cmd/api` and `cmd/worker`. ### 1. Configure and install From the frontend repository root: ```bash cp .env.example .env npm ci ``` PowerShell equivalent: ```powershell Copy-Item .env.example .env npm ci ``` The normal local configuration is: ```dotenv PUBLIC_API_BASE_URL=/api/v1 PUBLIC_AI_GROWTH_ENABLED=false PUBLIC_AI_COACH_ENABLED=false ``` `PUBLIC_API_BASE_URL` is browser-visible routing configuration, not a secret. Keep `/api/v1` for the same-origin Vite proxy. To use a backend at another local address, add `LOCAL_API_ORIGIN=http://127.0.0.1:8080`; this variable configures Vite only. Do not put database URLs, Redis passwords, session secrets, AI provider keys, or any other credential in a frontend environment variable. Every `PUBLIC_*` value is included in the browser build. ### 2. Start the application ```bash npm run dev ``` Open `http://127.0.0.1:5173`. The Vite server proxies `/api/*` to `http://127.0.0.1:8080` by default. ### 3. Sign in with the local demo user The backend creates/resets this account when its `go run ./cmd/admin` command runs with the documented values: ```text Username: merchant-0001 Password: merchant-demo-2026 ``` If login fails, confirm the backend `.env` contains those exact `DEMO_USERNAME` and `DEMO_PASSWORD` values and rerun `go run ./cmd/admin` from the backend repository. These are public development credentials; use a different password on every internet-accessible deployment. ## Commands | Command | Purpose | | ---------------------- | --------------------------------------------------------------------- | | `npm run dev` | Start the Vite development server on `127.0.0.1:5173` | | `npm run generate:api` | Regenerate TypeScript API types from the sibling backend OpenAPI file | | `npm run check` | Run Svelte and TypeScript checks | | `npm test` | Run the Vitest suite once | | `npm run test:watch` | Run Vitest in watch mode | | `npm run format:check` | Check formatting without changing files | | `npm run format` | Format the repository | | `npm run build` | Create the production static build in `build/` | | `npm run preview` | Preview the production build locally | `npm run generate:api` expects the backend repository at `../zarinpal-analytics-backend`. If your checkout uses another layout, update the input path in `package.json` or copy the OpenAPI contract into the expected sibling location before running it. Before submitting a change, run: ```bash npm run generate:api npm run format:check npm run check npm test npm run build ``` ## Production deployment on a remote server Deploy the frontend and backend together through the `zarinpal-analytics-deployment` repository. Its Compose stack builds this static SPA, serves it through Nginx, runs the Go API and worker, and keeps PostgreSQL/Redis private. A separate shared Caddy deployment owns the public domain and HTTPS. The examples use `analytics.example.com`; replace it with your own domain and replace repository URL placeholders with your template/fork URLs. ### 1. Prepare the server 1. Provision an Ubuntu server with a public IP. 2. Install Git, Docker Engine, and the Docker Compose plugin. 3. Permit inbound TCP 80/443 and restrict SSH to trusted addresses. 4. Never expose PostgreSQL 5432 or Redis 6379 publicly. ### 2. Install the main Caddy router Clone and follow the [Caddy deployment repository](https://git.amiirkhl.ir/Interanet/caddy-deployment.git): ```bash git clone https://git.amiirkhl.ir/Interanet/caddy-deployment.git ~/caddy-deployment cd ~/caddy-deployment ``` Start Caddy according to that repository's README. Its container must join an external Docker network named `caddy_proxy`. If the repository does not create it, run `docker network create caddy_proxy` once before starting Caddy. ### 3. Clone the application repositories ```bash git clone ~/zarinpal-analytics-deployment cd ~/zarinpal-analytics-deployment git clone backend git clone frontend ``` Keep all three repositories on clean `main` branches matching `origin/main`; the guarded deployment script checks this layout. ### 4. Configure production ```bash cp .env.example .env cp backend/.env.production.example backend/.env cp frontend/.env.production.example frontend/.env chmod 600 .env backend/.env frontend/.env ``` Replace every placeholder. In particular: - Set `FRONTEND_ORIGIN=https://analytics.example.com` and `COOKIE_SECURE=true` in `backend/.env`. - Generate distinct PostgreSQL, Redis, session, and cursor secrets with `openssl rand -hex 32`. - Replace the public local demo password before exposing the site. - Keep `PUBLIC_API_BASE_URL=/api/v1` in `frontend/.env` for same-origin routing. - Enable frontend AI switches only when the matching backend capability, provider key, and budgets are configured. - Never place a private value in `frontend/.env`. Place the dataset at the private absolute path configured by `IMPORT_FILE`, for example `/srv/zarinpal-data/challenge_data.csv.gz`. ### 5. Run the first deployment From `~/zarinpal-analytics-deployment`, run in order: ```bash docker compose config --quiet docker compose build backend frontend docker compose up -d postgres redis docker compose --profile tools run --rm migrate docker compose --profile import run --rm importer docker compose --profile tools run --rm admin docker compose up -d backend worker frontend docker compose ps ``` The migration, importer, and admin containers are intentional one-off tools. The API, worker, and frontend are long-running. Wait for every service to become healthy and inspect problems with: ```bash docker compose logs --tail=200 postgres redis backend worker frontend ``` ### 6. Point the domain to the application Create an `A` record for `analytics.example.com` pointing to the server's public IPv4 address. Add `AAAA` only when IPv6 is actually configured. In the Caddy deployment, add this site to the `Caddyfile` or equivalent template: ```caddyfile analytics.example.com { @backend path /api/* /healthz handle @backend { reverse_proxy zarinpal-backend:8080 { flush_interval -1 } } handle { reverse_proxy zarinpal-frontend:8080 } } ``` Validate and reload Caddy with the commands documented in its repository. Once DNS resolves and ports 80/443 reach the server, Caddy obtains and renews the HTTPS certificate automatically. Verify the public site and API routing: ```bash curl -I https://analytics.example.com/ curl https://analytics.example.com/healthz ``` Open the site, sign in with the production demo credentials configured in `backend/.env`, and confirm that dashboard data loads without browser console errors. ### 7. Deploy later updates ```bash cd ~/zarinpal-analytics-deployment git pull --ff-only origin main git -C backend pull --ff-only origin main git -C frontend pull --ff-only origin main bash scripts/deploy.sh ``` Later deployments rebuild both images and apply migrations. They do not rerun the one-time importer or reset the demo account. Never run `docker compose down -v` in production because it deletes persistent volumes. ## Project documentation - [`DESIGN.md`](DESIGN.md) defines the visual language, accessibility, RTL, responsive, and interaction rules. - [`docs/DASHBOARD-SPEC.md`](docs/DASHBOARD-SPEC.md) defines dashboard product behavior. - [`docs/DASHBOARD-UX-SPEC.md`](docs/DASHBOARD-UX-SPEC.md) defines screen flows and async/data states. - [`AGENTS.md`](AGENTS.md) defines durable contributor and automation rules.