99 lines
4.2 KiB
Markdown
99 lines
4.2 KiB
Markdown
# Cardy
|
|
|
|
Discount card storage. Specification: [development specification-v2.md](development%20specification-v2.md).
|
|
|
|
| Package | Port | Public URL | Proxy auth |
|
|
|---|---|---|---|
|
|
| `server-fe` — admin UI (Vite) | 10001 | `https://dev.aggtaa.com/` | Authelia |
|
|
| `server-be` — admin API | 10002 | `https://dev.aggtaa.com/api/admin/*` → `/admin/*` | Authelia, passes `Remote-Email` |
|
|
| `server-be` — client API | 10002 | `https://dev.aggtaa.com/api/*` → `/*` | none |
|
|
| `mobile-client` — PWA | 10003 | `https://dev.aggtaa.com/m/*` → `/*` | none |
|
|
|
|
The proxy strips `/api` and `/m` and passes them in `X-Forwarded-Prefix`.
|
|
|
|
## Setup
|
|
|
|
```bash
|
|
pnpm install
|
|
cp server-be/.env.example server-be/.env # fill in KEY_ENCRYPTION_SECRET, SUPERADMIN_EMAIL
|
|
cp server-fe/.env.example server-fe/.env
|
|
```
|
|
|
|
## Run
|
|
|
|
```bash
|
|
pnpm --filter @cardy/server-be dev # API on 127.0.0.1:10002 (tsx watch)
|
|
pnpm --filter @cardy/server-fe dev # admin UI on :10001
|
|
```
|
|
|
|
```bash
|
|
pnpm --filter @cardy/mobile-client start # PWA: build + vite preview on :10003 (service worker needs a build)
|
|
```
|
|
|
|
Production-like: `pnpm --filter @cardy/server-be build && pnpm --filter @cardy/server-be start`,
|
|
`pnpm --filter @cardy/server-fe start` (build + `vite preview` on :10001).
|
|
|
|
The mobile client dev server (`pnpm --filter @cardy/mobile-client dev`) works locally at
|
|
`http://localhost:10003/m/`; behind the proxy use `start`.
|
|
|
|
## Android app
|
|
|
|
```bash
|
|
pnpm --filter @cardy/mobile-client build:android # web build for Capacitor + cap sync
|
|
```
|
|
|
|
Then open `mobile-client/android` in Android Studio (or `gradlew assembleDebug` there) to build the APK.
|
|
The app registers `cardy://login?...` links (key QR codes) and asks for camera access when scanning.
|
|
|
|
### Live updates (no APK reinstall)
|
|
|
|
The APK contains the web build and works fully offline. Newer web builds are delivered over the air
|
|
(`@capgo/capacitor-updater` in manual mode, no Capgo cloud, telemetry disabled):
|
|
|
|
```bash
|
|
pnpm --filter @cardy/mobile-client publish:android # build + zip into mobile-client/updates/android
|
|
```
|
|
|
|
The mobile-client server on :10003 serves it at `https://dev.aggtaa.com/m/android/version.json`.
|
|
On launch and on every return to the foreground (when online) the app checks it, downloads a newer
|
|
bundle in the background and reloads into it on the card list; on a card or in the editor it waits
|
|
(`next()`: applied on backgrounding). A bundle that fails to start is rolled back automatically.
|
|
Versions come from the build time (`2026.929.151230` = 2026-09-29 15:12:30 UTC).
|
|
|
|
### APK self-update (native part changed)
|
|
|
|
Changes to the native part (plugins, `AndroidManifest.xml`, Java code) need a new APK:
|
|
|
|
```bash
|
|
pnpm --filter @cardy/mobile-client publish:android-apk # signed release APK into mobile-client/updates/android
|
|
```
|
|
|
|
It needs `mobile-client/android/keystore.properties` (copy `keystore.properties.example`, not committed)
|
|
with the release key. `versionCode` is the build time (`yyDDDHHmm`, UTC), `versionName` the web version.
|
|
Installed apps show "A new version of the app is available" on the card list; Install downloads the
|
|
APK and hands it to Android's installer (first time: allow "Install unknown apps" for Cardy, then
|
|
confirm the system dialog). Web updates published after an APK release require that APK or newer.
|
|
|
|
All builds (also Android Studio debug builds) are signed with the release key, so they can replace
|
|
each other. An app signed with another key (e.g. the old debug key) must be uninstalled once.
|
|
|
|
### Live reload during development
|
|
|
|
`pnpm --filter @cardy/mobile-client android:dev` (with `pnpm --filter @cardy/mobile-client dev` running
|
|
and a device connected via adb) installs an app that loads the dev server through `adb reverse`.
|
|
Run `build:android` again before building an APK for real use.
|
|
|
|
`server-be` listens on `127.0.0.1` by default because `/admin/*` trusts `Remote-Email`.
|
|
If the proxy runs on another machine, set `HOST` and `ADMIN_PROXY_SECRET`, and make the proxy add
|
|
`X-Cardy-Proxy-Secret` on the `/api/admin` route.
|
|
|
|
Without the proxy (local development), `server-fe` emulates it: forwards `/api/*` to `server-be`
|
|
with `/api` stripped; `DEV_REMOTE_EMAIL` in `server-fe/.env` fakes the Authelia user.
|
|
|
|
## Tests
|
|
|
|
```bash
|
|
pnpm test
|
|
pnpm typecheck
|
|
```
|