Files
zarinpal-analytics-frontend/README.md

218 lines
8.9 KiB
Markdown

# 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 <deployment-repository-url> ~/zarinpal-analytics-deployment
cd ~/zarinpal-analytics-deployment
git clone <backend-repository-url> backend
git clone <frontend-repository-url> 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.