1
0
mirror of git://f0xx.org/ac/ac-docs synced 2026-07-29 08:57:49 +03:00
Files
ac-docs/20260610_SERVICES.md
Anton Afanasyeu 69a448f156 initial
2026-06-23 12:20:43 +02:00

412 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Android Cast — exposed services catalog
<!-- doc-meta:start -->
| Field | Value |
|---|---|
| Author | Anton Afanasyeu |
| Revision | R1 |
| Creation date | 2026-06-10 |
| Last modification date | 2026-06-10 |
| Co-authored | |
| Severity | medium |
| State | in progress |
| Document type | technical |
<!-- doc-meta:end -->
\newpage
\newpage
---
_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)
- [Related endpoints](#related-endpoints)
- [Upload via curl](#upload-via-curl)
- [Bulk / synthetic issues](#bulk-synthetic-issues)
- [Tickets](#tickets)
- [Related endpoints](#related-endpoints-1)
- [Create via UI](#create-via-ui)
- [Create via curl (session cookie)](#create-via-curl-session-cookie)
- [Graphs](#graphs)
- [Related endpoints](#related-endpoints-2)
- [Fake session data (dev / BE)](#fake-session-data-dev-be)
- [Remote access](#remote-access)
- [Related endpoints](#related-endpoints-3)
- [RBAC / access control](#rbac-access-control)
- [Related endpoints](#related-endpoints-4)
- [APK builder](#apk-builder)
- [Related endpoints](#related-endpoints-5)
- [Git (Gitea)](#git-gitea)
- [OTA updates](#ota-updates)
- [Layout](#layout)
- [Publish (operator)](#publish-operator)
- [Heartbeat (device)](#heartbeat-device)
- [Auth & account security](#auth-account-security)
- [URL shortener](#url-shortener)
- [Non-HTTP services](#non-http-services)
- [Validation scripts](#validation-scripts)
<!-- /toc -->
**Documentation index:** [README.md](README.md)
---
## 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)
---
## URL shortener
**Web:** [https://s.f0xx.org](https://s.f0xx.org) · **Admin:** […/crashes/?view=short_links](https://apps.f0xx.org/app/androidcast_project/crashes/?view=short_links) (RBAC: company owner/admin)
| Kind | Path | Notes |
|------|------|--------|
| Health | `GET /api/v1/health` | JSON `status: ok`, DB ping |
| Shorten | `GET/POST /api/v1/shorten` | Bearer token required |
| QR | `GET /api/v1/qr/{slug}.png` | PNG (`libqrencode-tools` on BE) |
| Redirect | `GET /{slug}` | `302` → origin; `410` if expired |
| Admin UI | `…/crashes/?view=short_links` | Mint/revoke bearers, list links (session RBAC) |
Spec: [specs/20100611_3_url_shortener.md](specs/20100611_3_url_shortener.md) · code: [backend/url-shortener/](../backend/url-shortener/)
```bash
curl -fsS https://s.f0xx.org/api/v1/health
# Bearer: hub Short links → Mint, or php backend/url-shortener/scripts/seed_bearer.php (CLI)
export BEARER=BASE=https://s.f0xx.org backend/url-shortener/scripts/demo_curl.sh
CRASHES_BASE=https://apps.f0xx.org/app/androidcast_project/crashes ./examples/crash_reporter/backend/scripts/test_short_links_api.sh
```
---
## 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 docs 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`