mirror of
git://f0xx.org/android_cast
synced 2026-07-29 04:18:09 +03:00
sync BE
This commit is contained in:
336
docs/20260610_SERVICES.md
Normal file
336
docs/20260610_SERVICES.md
Normal file
@@ -0,0 +1,336 @@
|
||||
# Android Cast — exposed services catalog
|
||||
|
||||
_Validated: 2026-06-10 after FE `apps.conf` consolidation + BE sync. Public base: **https://apps.f0xx.org**._
|
||||
|
||||
**Documentation index:** [README.md](README.md) · Companion: [INFRA.md](INFRA.md), [20260608_BE_SERVICES_and_infra.md](20260608_BE_SERVICES_and_infra.md)
|
||||
|
||||
---
|
||||
|
||||
## Table of contents
|
||||
|
||||
<!-- toc -->
|
||||
- [Validation snapshot](#validation-snapshot)
|
||||
- [Hub landing](#hub-landing)
|
||||
- [Console home](#console-home)
|
||||
- [Issues (crash reports)](#issues-crash-reports)
|
||||
- [Tickets](#tickets)
|
||||
- [Graphs](#graphs)
|
||||
- [Remote access](#remote-access)
|
||||
- [RBAC / access control](#rbac--access-control)
|
||||
- [APK builder](#apk-builder)
|
||||
- [Git (Gitea)](#git-gitea)
|
||||
- [OTA updates](#ota-updates)
|
||||
- [Heartbeat (device)](#heartbeat-device)
|
||||
- [Auth & account security](#auth--account-security)
|
||||
- [Non-HTTP services](#non-http-services)
|
||||
- [Validation scripts](#validation-scripts)
|
||||
<!-- /toc -->
|
||||
|
||||
---
|
||||
|
||||
## Validation snapshot
|
||||
|
||||
Run: `examples/crash_reporter/backend/scripts/validate_be_services.sh`
|
||||
|
||||
| Check | URL / target | 2026-06-10 |
|
||||
|-------|----------------|------------|
|
||||
| Hub | `/app/androidcast_project/` | ✅ HTTP 200 |
|
||||
| Crashes console | `…/crashes/` | ✅ HTTP 302 → login |
|
||||
| Graphs | `…/graphs/` | ✅ HTTP 302 → login |
|
||||
| Builder | `…/build/` | ✅ HTTP 302 → login |
|
||||
| Git | `…/git/` | ✅ HTTP 200 |
|
||||
| OTA channel | `/v0/ota/channel/stable.json` | ⚠️ HTTP **404** (FE proxy OK; artifact or BE `location` missing) |
|
||||
| Crash upload | `…/crashes/api/upload.php` GET | ✅ HTTP **400** (expects POST JSON) |
|
||||
| Heartbeat | `…/crashes/api/heartbeat.php` GET | ✅ HTTP **405** (expects POST) |
|
||||
| Graph upload | `…/graphs/api/graph_upload.php` GET | ✅ HTTP **400** (expects POST) |
|
||||
| Two-factor | `…/crashes/two-factor` | ✅ HTTP 302 → login (no pending session) |
|
||||
|
||||
**Alerts — may need follow-up patch**
|
||||
|
||||
1. **OTA:** Public returns **404**; BE direct `curl -H 'Host: apps.f0xx.org' http://artc0…/v0/ota/channel/stable.json` returned HTML lander redirect (not JSON). Confirm BE `listen 80` has `location ^~ /v0/ota/` **before** catch-all, and publish `stable.json` under `ota-artifacts/v0/ota/channel/`.
|
||||
2. **2FA:** Fixed in repo — `completeTotpLogin()` no longer clears pending session on wrong code; login redirects to `/two-factor` when pending. **Sync BE** (`Auth.php`, `index.php`, `two_factor_challenge.php`, `app.css`).
|
||||
|
||||
---
|
||||
|
||||
## Hub landing
|
||||
|
||||
**Web:** [https://apps.f0xx.org/app/androidcast_project/](https://apps.f0xx.org/app/androidcast_project/)
|
||||
|
||||
Marketing multipage shell; left nav links to Console, Git, Issues, Tickets, Graphs, Remote access, Builder. Shared session cookie `ac_crash_sess` path `/app/androidcast_project`.
|
||||
|
||||
| Kind | Path | Notes |
|
||||
|------|------|--------|
|
||||
| Static/PHP | `index.php` | Hub landing |
|
||||
| CSS/JS | `hub.css`, `hub-landing.css`, `assets/hub-*.js` | Theme + i18n |
|
||||
| Crashes assets | `…/crashes/assets/css/app.css` | Shared console theme |
|
||||
|
||||
No device ingest on hub root.
|
||||
|
||||
---
|
||||
|
||||
## Console home
|
||||
|
||||
**Web:** [https://apps.f0xx.org/app/androidcast_project/crashes/?view=home](https://apps.f0xx.org/app/androidcast_project/crashes/?view=home) (auth required)
|
||||
|
||||
Landing cards: Issues, New issue, Tickets, New ticket, Graphs; quick links to all services.
|
||||
|
||||
---
|
||||
|
||||
## Issues (crash reports)
|
||||
|
||||
**Web:** [https://apps.f0xx.org/app/androidcast_project/crashes/?view=reports](https://apps.f0xx.org/app/androidcast_project/crashes/?view=reports)
|
||||
|
||||
Triage anonymous crash JSON; grouped/by-time views; tag editor; tree expand.
|
||||
|
||||
### Related endpoints
|
||||
|
||||
| Method | Endpoint | Auth | Purpose |
|
||||
|--------|----------|------|---------|
|
||||
| `POST` | `…/crashes/api/upload.php` | None | Device crash ingest (JSON or gzip JSON) |
|
||||
| `GET` | `…/crashes/api/reports.php` | Session | List/filter reports (console JS) |
|
||||
| `POST` | `…/crashes/api/report_tags.php` | Session | Update report tags |
|
||||
| `POST` | `…/crashes/api/report_viewed.php` | Session | Mark report viewed |
|
||||
| `GET` | `…/crashes/api/tag_catalog.php` | Session | Tag suggestions |
|
||||
| `GET` | `…/crashes/api/diag.php` | Optional | Diagnostics (may 403 at edge) |
|
||||
|
||||
### Upload via curl
|
||||
|
||||
```bash
|
||||
BASE=https://apps.f0xx.org/app/androidcast_project/crashes
|
||||
SAMPLE=examples/crash_reporter/sample_crash_java.json
|
||||
RID="manual-$(date +%s)"
|
||||
jq --arg rid "$RID" '.report_id = $rid' "$SAMPLE" | \
|
||||
curl -sS -X POST "$BASE/api/upload.php" \
|
||||
-H 'Content-Type: application/json' --data-binary @-
|
||||
```
|
||||
|
||||
Gzip upload smoke: `examples/crash_reporter/backend/scripts/test_gzip_upload.sh`
|
||||
|
||||
### Bulk / synthetic issues
|
||||
|
||||
- Optional payload fields: `ingest.source`, `ingest.client_id`, `ingest.run_id` — see [OPEN_API.md](OPEN_API.md).
|
||||
- Loop `upload.php` with varied `report_id` / fingerprints for load tests.
|
||||
- Tag harness traffic `synthetic` via console or `report_tags.php`.
|
||||
|
||||
---
|
||||
|
||||
## Tickets
|
||||
|
||||
**Web:** [https://apps.f0xx.org/app/androidcast_project/crashes/?view=tickets](https://apps.f0xx.org/app/androidcast_project/crashes/?view=tickets)
|
||||
|
||||
Roadmap / QA tasks; workflow tags (`ticket` vs `issue` meta).
|
||||
|
||||
### Related endpoints
|
||||
|
||||
| Method | Endpoint | Auth | Purpose |
|
||||
|--------|----------|------|---------|
|
||||
| `GET` | `…/crashes/api/tickets.php` | Session | List tickets |
|
||||
| `POST` | `…/crashes/api/ticket_create.php` | Session | Create ticket/issue |
|
||||
| `POST` | `…/crashes/api/ticket_update.php` | Session | Update fields/tags |
|
||||
| `POST` | `…/crashes/api/ticket_tags.php` | Session | Tag catalog ops |
|
||||
| `POST` | `…/crashes/api/ticket_comments.php` | Session | Comments |
|
||||
| `POST` | `…/crashes/api/ticket_upload.php` | Session | Attachment upload |
|
||||
| `GET` | `…/crashes/api/ticket_attachments.php` | Session | List attachments |
|
||||
| `GET` | `…/crashes/api/ticket_attachment.php` | Session | Download attachment |
|
||||
|
||||
### Create via UI
|
||||
|
||||
- Issues view: **New issue** → `ticket_create.js` → `ticket_create.php` with `issue` meta tag.
|
||||
- Tickets view / home: **New ticket** → same API with `ticket` meta tag.
|
||||
|
||||
### Create via curl (session cookie)
|
||||
|
||||
```bash
|
||||
BASE=https://apps.f0xx.org/app/androidcast_project/crashes
|
||||
JAR=/tmp/ac-cookie.txt
|
||||
curl -sS -c "$JAR" -b "$JAR" -X POST -d 'username=admin&password=admin' "$BASE/login" -o /dev/null
|
||||
curl -sS -b "$JAR" -X POST -H 'Content-Type: application/json' \
|
||||
-d '{"title":"API test","brief":"from curl","body":"","tags":[{"id":"ticket","label":"ticket","bg":"#6366f1"},{"id":"open","label":"open","bg":"#22c55e"}]}' \
|
||||
"$BASE/api/ticket_create.php"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Graphs
|
||||
|
||||
**Web:** [https://apps.f0xx.org/app/androidcast_project/graphs/](https://apps.f0xx.org/app/androidcast_project/graphs/)
|
||||
|
||||
Session metrics dashboards (user / slug / platform scopes); drag-reorder bricks; empty-session notice when no `graph_upload` data.
|
||||
|
||||
### Related endpoints
|
||||
|
||||
| Method | Endpoint | Auth | Purpose |
|
||||
|--------|----------|------|---------|
|
||||
| `GET` | `…/graphs/api/graphs.php?days=14` | Session | Aggregated metrics JSON |
|
||||
| `POST` | `…/graphs/api/graph_upload.php` | Device/session | Ingest `graph_session` NDJSON/JSON |
|
||||
|
||||
Graphs PHP routes through crashes `public/index.php` (`?view=graphs`).
|
||||
|
||||
### Fake session data (dev / BE)
|
||||
|
||||
```bash
|
||||
# Generate NDJSON
|
||||
php examples/crash_reporter/backend/scripts/generate_fake_graph_sessions.php \
|
||||
--devices=100 --per-device=6 --out=/tmp/sessions.ndjson
|
||||
|
||||
# SQL import on BE (when HTTP upload times out)
|
||||
php examples/crash_reporter/backend/scripts/ndjson_to_graph_sql.php /tmp/sessions.ndjson | \
|
||||
ssh alpine-be 'mariadb androidcast_crashes'
|
||||
```
|
||||
|
||||
API smoke: `examples/crash_reporter/backend/scripts/test_graphs_api.sh`
|
||||
|
||||
---
|
||||
|
||||
## Remote access
|
||||
|
||||
**Web:** [https://apps.f0xx.org/app/androidcast_project/crashes/?view=remote_access](https://apps.f0xx.org/app/androidcast_project/crashes/?view=remote_access) (RBAC: `remote_access_view`)
|
||||
|
||||
Operator console: whitelist devices, open WireGuard or RSSH sessions.
|
||||
|
||||
### Related endpoints
|
||||
|
||||
| Method | Endpoint | Auth | Purpose |
|
||||
|--------|----------|------|---------|
|
||||
| `POST` | `…/crashes/api/remote_access.php?action=…` | Session | `whitelist`, `open_session`, `dashboard`, … |
|
||||
| `POST` | `…/crashes/api/heartbeat.php` | None | Device RA poll (`heartbeat.type=ra`) |
|
||||
|
||||
Device flow: app polls `heartbeat.php` → operator uses console → next poll returns `connect` payload.
|
||||
|
||||
Smoke: `CRASHES_BASE=https://apps.f0xx.org/app/androidcast_project/crashes examples/crash_reporter/backend/scripts/test_remote_access_api.sh`
|
||||
|
||||
Prod checklist: `examples/crash_reporter/backend/scripts/verify_remote_access_prod.sh`
|
||||
|
||||
---
|
||||
|
||||
## RBAC / access control
|
||||
|
||||
**Web:** [https://apps.f0xx.org/app/androidcast_project/crashes/?view=rbac](https://apps.f0xx.org/app/androidcast_project/crashes/?view=rbac) (admin)
|
||||
|
||||
### Related endpoints
|
||||
|
||||
| Method | Endpoint | Auth | Purpose |
|
||||
|--------|----------|------|---------|
|
||||
| `GET/POST` | `…/crashes/api/rbac.php` | Session | Roles, memberships, lockouts |
|
||||
| `GET/POST` | `…/crashes/api/users.php` | Session | User admin |
|
||||
|
||||
Smoke: `examples/crash_reporter/backend/scripts/test_rbac_api.sh`
|
||||
|
||||
---
|
||||
|
||||
## APK builder
|
||||
|
||||
**Web:** [https://apps.f0xx.org/app/androidcast_project/build/](https://apps.f0xx.org/app/androidcast_project/build/)
|
||||
|
||||
Docker CI: trigger builds, stream logs, OTA artifact option.
|
||||
|
||||
### Related endpoints
|
||||
|
||||
| Method | Endpoint | Auth | Purpose |
|
||||
|--------|----------|------|---------|
|
||||
| `GET` | `…/build/api/health.php` | Session | Docker/socket health |
|
||||
| `GET` | `…/build/api/builds.php` | Session | Build history |
|
||||
| `POST` | `…/build/api/build_trigger.php` | Session | Start build |
|
||||
| `GET` | `…/build/api/build_log.php?id=` | Session | Log tail |
|
||||
| `POST` | `…/build/api/build_actions.php` | Session | Cancel / rerun |
|
||||
|
||||
Shared login with crashes (`ac_crash_sess`). See [BUILD_DEPLOY.md](BUILD_DEPLOY.md).
|
||||
|
||||
---
|
||||
|
||||
## Git (Gitea)
|
||||
|
||||
**Web:** [https://apps.f0xx.org/app/androidcast_project/git/](https://apps.f0xx.org/app/androidcast_project/git/)
|
||||
|
||||
FE proxies to `http://artc0.intra.raptor.org:3000/` (Gitea). Canonical git remote: `git://f0xx.org/android_cast`.
|
||||
|
||||
No Android Cast PHP on this path.
|
||||
|
||||
---
|
||||
|
||||
## OTA updates
|
||||
|
||||
**Web channel:** [https://apps.f0xx.org/v0/ota/channel/stable.json](https://apps.f0xx.org/v0/ota/channel/stable.json)
|
||||
|
||||
Device setting: `ota.base_url` in `examples/settings.json` → `https://apps.f0xx.org/v0/ota/channel/stable.json`.
|
||||
|
||||
### Layout
|
||||
|
||||
See [OTA.md](OTA.md): `v0/ota/channel/{stable,staging,…}.json` → manifest → `.otapkg` / `.otabundle.zip`.
|
||||
|
||||
### Publish (operator)
|
||||
|
||||
```bash
|
||||
./scripts/generate-ota-v0.sh app/build/outputs/apk/release/app-release.apk \
|
||||
https://apps.f0xx.org ./out/ota staging
|
||||
OTA_DEPLOY_TARGET=… ./scripts/deploy-ota-staging.sh
|
||||
```
|
||||
|
||||
BE mount: `…/androidcast_project/ota-artifacts/v0/` — `prepare-be-ota-mount.sh`.
|
||||
|
||||
**Status 2026-06-10:** FE `/v0/ota/` → BE :80 configured; channel file **not yet served** (404 / lander) — publish artifacts + verify BE nginx `location ^~ /v0/ota/`.
|
||||
|
||||
---
|
||||
|
||||
## Heartbeat (device)
|
||||
|
||||
**Web:** none (app service only)
|
||||
|
||||
**Endpoint:** `POST https://apps.f0xx.org/app/androidcast_project/crashes/api/heartbeat.php`
|
||||
|
||||
JSON body with `heartbeat` object: session stats, remote-access poll (`type: ra`), etc.
|
||||
|
||||
```bash
|
||||
curl -sS -X POST -H 'Content-Type: application/json' \
|
||||
-d '{"heartbeat":{"type":"ping","device_id":"test-device"}}' \
|
||||
https://apps.f0xx.org/app/androidcast_project/crashes/api/heartbeat.php
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Auth & account security
|
||||
|
||||
| Page | URL |
|
||||
|------|-----|
|
||||
| Login | […/crashes/login](https://apps.f0xx.org/app/androidcast_project/crashes/login) |
|
||||
| Register | […/crashes/register](https://apps.f0xx.org/app/androidcast_project/crashes/register) |
|
||||
| Two-factor challenge | […/crashes/two-factor](https://apps.f0xx.org/app/androidcast_project/crashes/two-factor) |
|
||||
| Account security (TOTP enroll) | […/crashes/account-security](https://apps.f0xx.org/app/androidcast_project/crashes/account-security) |
|
||||
| Email verify | `…/crashes/verify-email?token=` |
|
||||
|
||||
| Method | Endpoint | Purpose |
|
||||
|--------|----------|---------|
|
||||
| `POST` | `…/crashes/api/auth_register.php` | Registration API |
|
||||
|
||||
TOTP verify script: `examples/crash_reporter/backend/scripts/verify_auth_totp.php`
|
||||
|
||||
Flow doc: [20260607-2FA-email-mobile-auth-flow.md](20260607-2FA-email-mobile-auth-flow.md)
|
||||
|
||||
---
|
||||
|
||||
## Non-HTTP services
|
||||
|
||||
| Service | Access | Used by |
|
||||
|---------|--------|---------|
|
||||
| **WireGuard** | `ra.apps.f0xx.org:45340/udp` | Remote access lab mode |
|
||||
| **RSSH bastion** | `ra.apps.f0xx.org:443/tcp` | Reverse SSH alpha mode |
|
||||
| **Cast LAN** | UDP/TCP `:41235`, discovery `:41234` | Screen mirror (no BE) |
|
||||
| **MQTT OTA** (optional) | `mqtt://host:port/v0/ota/…` | Retained topic payloads |
|
||||
|
||||
---
|
||||
|
||||
## Validation scripts
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `validate_be_services.sh` | Public HTTP smoke (this doc’s snapshot) |
|
||||
| `test_gzip_upload.sh` | Crash upload plain + gzip |
|
||||
| `test_graphs_api.sh` | Graphs JSON API |
|
||||
| `test_remote_access_api.sh` | RA whitelist + session |
|
||||
| `test_rbac_api.sh` | RBAC API |
|
||||
| `test_rssh_api.sh` | RSSH mode API |
|
||||
| `test_tags_api.sh` | Report tag API |
|
||||
| `verify_remote_access_prod.sh` | Prod RA checklist |
|
||||
|
||||
FE nginx template: `examples/crash_reporter/backend/nginx/fe/apps.conf`
|
||||
Regenerate FE patch: `scripts/generate-fe-nginx-patch.sh`
|
||||
Reference in New Issue
Block a user