# mmvarma Zima Store

Protocol v2 [ZimaOS](https://www.zimaspace.com/) / CasaOS app store. The GitHub repo can stay **private**; only the built `dist/` is published publicly via **Cloudflare Pages**.

## One-time Cloudflare setup

1. Create a free [Cloudflare](https://dash.cloudflare.com/) account (if you don’t have one).
2. Create an API token with **Account → Cloudflare Pages → Edit** (and Workers read if prompted).
3. In the Cloudflare dashboard, copy your **Account ID**.
4. In this GitHub repo → **Settings → Secrets and variables → Actions**:
   - Secret `CLOUDFLARE_API_TOKEN` = the API token
   - Secret `CLOUDFLARE_ACCOUNT_ID` = your account ID
5. Optional variables (repo → **Variables**):
   - `STORE_BASE_URL` — public store URL (default `https://mmvarma-zima-store.pages.dev`)
   - `CLOUDFLARE_PAGES_PROJECT` — Pages project name (default `mmvarma-zima-store`)

On first deploy, the workflow creates the Pages project (`mmvarma-zima-store`) if it does not exist, then uploads `dist/`. If you attach a custom domain later, set `STORE_BASE_URL` to that HTTPS origin (no trailing slash) and redeploy so asset URLs in `dist/` match.

## Add this store in ZimaOS

Your ZimaOS build uses the **legacy ZIP app store protocol** (it downloads a zip and reports `zip: not a valid zip file` if you paste a `store.json` URL).

After a successful Actions run, paste this URL in ZimaOS **App Store → Apps → More Apps → Add**:

```text
https://mmvarma-zima-store.pages.dev/store/main.zip
```

Use your `STORE_BASE_URL` / custom domain if configured, for example `https://your-domain.example/store/main.zip`.

**Do not** use `store.json` on ZIP-only ZimaOS/CasaOS versions.

When your ZimaOS App Store supports Protocol v2 static URLs, you can switch to:

```text
https://mmvarma-zima-store.pages.dev/store.json
```

Confirm the store is live:

- ZIP (current ZimaOS): `/store/main.zip` downloads a valid zip
- v2 (newer clients): `/store.json` and `/index.json` return JSON

## Apps

| App | Description |
|-----|-------------|
| **HeyForm** | Open-source form builder with built-in response storage |
| **Frappe HR** | Open-source HR and payroll (Frappe HRMS) |

## Installing HeyForm

Install from the app store with **no required fields** — like Immich or Jellyfin. Secrets are derived from your CasaOS `$AppID` at install time; the default URL is `http://127.0.0.1:9513` for local / dashboard **Open** access.

| Setting | Default | Notes |
|---------|---------|--------|
| Web UI port | `9513` | Fixed in compose (`9513:8000`) |
| `APP_HOMEPAGE_URL` | `http://127.0.0.1:9513` | Change in App Settings only if you access via LAN IP or HTTPS and login redirects fail |
| `SESSION_KEY` / `FORM_ENCRYPTION_KEY` | Auto (`heyform-$AppID-…`) | Unique per install; do not change after data exists |

Register the first user after install — that account becomes admin.

### HeyForm not accessible (connection refused)

On the Zima box, run:

```bash
docker ps -a --filter name=heyform
docker port heyform
docker logs heyform --tail 80
docker logs heyform-mongo --tail 40
docker logs heyform-keydb --tail 40
ss -tlnp | grep -E '9513|heyform'
curl -sv --max-time 5 http://127.0.0.1:9513/ 2>&1 | head -20
```

Expected when healthy: `heyform` is **Up**, `docker port heyform` shows `8000/tcp -> 0.0.0.0:9513`, and `curl` returns HTML.

After updating the store catalog, **reinstall** HeyForm (uninstall first) so the new compose is applied.

## Installing Frappe HR (HRMS)

Install from the app store. First boot pulls `ghcr.io/frappe/hrms` and creates a site with ERPNext + HRMS — expect several minutes and a multi‑GB download.

| Setting | Default | Notes |
|---------|---------|--------|
| Web UI port | `8088` | Fixed in compose (`8088:8080`) |
| Login | `Administrator` / `admin` | Change immediately after first login |
| Architecture | amd64 | Published image is x86_64 only |

Data is stored under `/DATA/AppData/<AppID>/` (sites, MariaDB, Redis queue, logs).

### Frappe HR not ready yet

On the Zima box, run:

```bash
docker ps -a --filter name=hrms
docker logs hrms-create-site --tail 80
docker logs hrms-frontend --tail 40
curl -sv --max-time 5 http://127.0.0.1:8088/ 2>&1 | head -20
```

Wait until `hrms-create-site` has exited successfully and `hrms-frontend` / `hrms-backend` are **Up** before opening the UI.

## Telegram (later)

HeyForm stores responses in its own UI. To push submissions to a Telegram channel, use HeyForm’s **webhook** integration to your bot (or an automation tool such as n8n). That wiring is not part of this package yet.

## Development

Source layout:

```text
Apps/HeyForm/          # compose + icon + screenshot
Apps/HRMS/             # Frappe HR (HRMS) compose + assets
category-list.json     # v1 zip metadata
recommend-list.json
featured-apps.json
store-config.json      # store identity (v1 + v2)
scripts/               # local test + zip build helpers
.github/workflows/     # test → build dist + v1 zip → Cloudflare Pages
```

### Run tests locally (before push)

Requires **Docker** (for `docker compose config` and `docker manifest inspect`).

```bash
chmod +x scripts/*.sh
./scripts/test.sh
```

This checks:

- `store-config.json` is valid JSON
- each app has icon + screenshot + compose file
- compose metadata (`name`, `x-casaos.id`) and `docker compose config`
- **every pinned image exists in its registry** (catches tags like the broken `eqalpha/keydb:6.3.3` before deploy)
- legacy v1 `main.zip` builds and passes `unzip -t`
- Protocol v2 `dist/store.json` and `dist/index.json` build

Optional skips: `SKIP_IMAGE_CHECK=1`, `SKIP_V1_ZIP=1`, or `SKIP_V2_BUILD=1`.

On every push to `main`, GitHub Actions runs the same checks first; **publish only runs if tests pass**, then deploys `dist/` to Cloudflare Pages. Pull requests run tests only (no deploy).
