Add CLAUDE.md
This commit is contained in:
79
CLAUDE.md
Normal file
79
CLAUDE.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# iOS App Store
|
||||
|
||||
Self-hosted iOS OTA distribution server. Node.js/Express + SQLite + Docker, deployed on unraid behind Nginx Proxy Manager.
|
||||
|
||||
## Live deployment
|
||||
|
||||
- **URL**: https://appstore.treytartt.com
|
||||
- **Container**: `ios-appstore` on unraid (port `3080` internally, proxied via NPM at host `10.3.3.11:3080`)
|
||||
- **App code**: `/mnt/user/appdata/ios-appstore/` on unraid (Dockerfile, source, compose, `.env`)
|
||||
- **Data volume**: `/mnt/user/downloads/ios-appstore/` mounted as `/data` (SQLite DB, IPAs, icons)
|
||||
|
||||
This split is intentional — app code in appdata, persistent data in downloads. Don't put data volumes in appdata or app source in downloads.
|
||||
|
||||
The `.env` on the server holds `ADMIN_PASSWORD`, `API_TOKEN`, and `SESSION_SECRET`. Read it from `/mnt/user/appdata/ios-appstore/.env` when you need them.
|
||||
|
||||
## Deploy flow
|
||||
|
||||
```bash
|
||||
# 1. Sync local changes to unraid (excludes node_modules, data, .env)
|
||||
rsync -avz --exclude node_modules --exclude data --exclude .env \
|
||||
/Users/m4mini/Desktop/code/ios-appstore/ \
|
||||
unraid:/mnt/user/appdata/ios-appstore/
|
||||
|
||||
# 2. Rebuild and restart
|
||||
ssh unraid "cd /mnt/user/appdata/ios-appstore && docker compose up -d --build"
|
||||
|
||||
# 3. Verify
|
||||
ssh unraid "docker logs ios-appstore --tail 20 && curl -s http://localhost:3080/api/health"
|
||||
```
|
||||
|
||||
`docker-compose.yml` builds the image from local source — no registry. The data volume persists across rebuilds.
|
||||
|
||||
## Architecture
|
||||
|
||||
- `src/server.js` — Express app, all routes, multer upload handling
|
||||
- `src/db.js` — SQLite schema (apps, builds, devices)
|
||||
- `src/ipa-parser.js` — Unzips IPA, extracts `Info.plist` and app icon
|
||||
- `src/manifest.js` — Generates the OTA manifest plist iOS fetches
|
||||
- `src/auth.js` — Session middleware (web UI) + token middleware (API)
|
||||
- `views/` — Login, app listing, upload pages (vanilla HTML)
|
||||
- `public/` — CSS + client-side JS
|
||||
|
||||
Apps are keyed by bundle ID. Uploading the same bundle ID adds a new build to the existing app instead of duplicating it.
|
||||
|
||||
## Auth model
|
||||
|
||||
Two parallel auth schemes:
|
||||
- **Session cookies** for browser users (login at `/login` with `ADMIN_PASSWORD`)
|
||||
- **`X-Api-Token` header** for CLI/automation (`API_TOKEN`)
|
||||
|
||||
`requireAuth` accepts either. The manifest and IPA download endpoints (`/api/manifest/:id`, `/api/download/:id`) are intentionally **public** — iOS fetches them unauthenticated during the OTA install.
|
||||
|
||||
## OTA gotchas
|
||||
|
||||
- **Development-signed IPAs cannot be installed OTA.** iOS only allows OTA installs of `ad-hoc` or `enterprise`-signed builds. If a user reports "integrity could not be verified", first check the export method in their `ExportOptions.plist`.
|
||||
- Ad-hoc requires a **distribution certificate** (not a development cert) and an **ad-hoc provisioning profile** with the target device UDIDs registered.
|
||||
- HTTPS is mandatory and must use a trusted CA. Self-signed certs don't work on iOS 12+. NPM's Let's Encrypt cert handles this.
|
||||
- The manifest's `bundle-identifier` must exactly match the IPA's bundle ID.
|
||||
|
||||
## Testing changes
|
||||
|
||||
For backend changes, after deploying:
|
||||
```bash
|
||||
# Health
|
||||
curl -s https://appstore.treytartt.com/api/health
|
||||
|
||||
# List apps (needs token)
|
||||
curl -s -H "X-Api-Token: $TOKEN" https://appstore.treytartt.com/api/apps
|
||||
|
||||
# Upload an IPA
|
||||
curl -X POST https://appstore.treytartt.com/api/upload \
|
||||
-H "X-Api-Token: $TOKEN" \
|
||||
-F "ipa=@/path/to/App.ipa" \
|
||||
-F "notes=test"
|
||||
```
|
||||
|
||||
Get `$TOKEN` from `/mnt/user/appdata/ios-appstore/.env` on unraid.
|
||||
|
||||
For frontend changes, just rsync + restart and refresh the browser.
|
||||
Reference in New Issue
Block a user