# BE services & infrastructure โ€” validation map | Field | Value | |---|---| | Author | Anton Afanasyeu | | Revision | R1 | | Creation date | 2026-06-08 | | Last modification date | 2026-06-08 | | Co-authored | | | Severity | medium | | State | in progress | | Document type | technical | \newpage \newpage --- _Last validated: 2026-06-08. Companion to [INFRA.md](INFRA.md), [REMOTE_ACCESS_IMPL.md](REMOTE_ACCESS_IMPL.md)._ --- --- --- --- --- --- --- --- ## Table of contents - [Topology](#topology) - [Service inventory (mobile + console)](#service-inventory-mobile-console) - [Data paths](#data-paths) - [Cast session (LAN โ€” alpha scope)](#cast-session-lan-alpha-scope) - [Telemetry path](#telemetry-path) - [Remote access control plane](#remote-access-control-plane) - [Validation status](#validation-status) - [DNAT chain (WireGuard lab)](#dnat-chain-wireguard-lab) - [RSSH / RBAC](#rssh-rbac) - [Planned: SFU relay (Janus-class)](#planned-sfu-relay-janus-class) - [Agent scripts](#agent-scripts) - [Open findings โ†’ tickets](#open-findings-tickets) **Documentation index:** [README.md](README.md) --- ## Topology ```mermaid flowchart LR subgraph Internet MOB["๐Ÿ“ฑ Android app"] OPS["๐Ÿ–ฅ Operator browser"] end subgraph Router["f0xx.org router"] RDNAT["UDP 45340 DNAT"] end subgraph FE["FE f0xx-monstro ยท apps.f0xx.org"] TLS["TLS :443"] FEDNAT["UDP 45340 DNAT"] NGXFE["nginx reverse proxy"] end subgraph BE["BE Alpine artc0 ยท :80"] NGXBE["nginx apps.conf"] FPM["PHP-FPM"] DB["MariaDB / SQLite"] WG["wg0 :45340"] SSH["sshd bastion :443"] end MOB -->|"HTTPS crashes/graphs/heartbeat"| TLS OPS --> TLS TLS --> NGXFE --> NGXBE --> FPM --> DB MOB -->|"UDP WG lab"| RDNAT --> FEDNAT --> WG MOB -->|"RSSH outbound"| SSH FPM --> WG ``` | Hop | Host | Role | |-----|------|------| | Public DNS | `apps.f0xx.org`, `ra.apps.f0xx.org` | CNAME โ†’ FE | | Router | `f0xx.org` (`134.17.26.161` WAN) | UDP `45340` โ†’ FE `10.7.0.10` | | FE | Gentoo HVM | TLS, HTTP proxy โ†’ BE `:80`, UDP DNAT โ†’ BE `10.7.16.128` | | BE | Alpine `10.7.16.128` | PHP consoles, device APIs, `wg0`, RSSH bastion | --- ## Service inventory (mobile + console) | Service | Public URL / port | Mobile uses | Console uses | Status | |---------|-------------------|-------------|--------------|--------| | **Hub** | `https://apps.f0xx.org/app/androidcast_project/` | Indirect (links) | Landing | โœ… OK | | **Crashes console** | `โ€ฆ/crashes/` | โ€” | Reports, home | โœ… OK | | **Crash upload** | `โ€ฆ/crashes/api/upload.php` | โœ… gzip JSON | โ€” | โœ… OK | | **Heartbeat / RA** | `โ€ฆ/crashes/api/heartbeat.php` | โœ… RA poll | โ€” | โœ… OK | | **Session stats / graphs ingest** | `โ€ฆ/graphs/api/graph_upload.php` | โœ… (when enabled) | โ€” | โœ… OK | | **Graphs dashboard** | `โ€ฆ/graphs/` | โ€” | Analytics UI | โœ… OK | | **Tickets** | `โ€ฆ/crashes/?view=tickets` | โ€” | Issue tracking | โœ… OK | | **Remote access** | `โ€ฆ/crashes/?view=remote_access` | โ€” | WG/RSSH ops | โœ… OK | | **RBAC admin** | `โ€ฆ/crashes/?view=rbac` | โ€” | Roles / lockouts | โœ… OK | | **APK builder** | `โ€ฆ/build/` | โ€” | Internal builds | โœ… OK | | **OTA channel** | `โ€ฆ/v0/ota/channel/stable.json` | โœ… `settings.json` | โ€” | **PENDING** HTTP 400 โ€” not on apps vhost | | **OTA manifest/APK** | TBD host/path | โœ… | โ€” | **PENDING** align with device `ota.base_url` | | **Diag API** | `โ€ฆ/crashes/api/diag.php` | Optional | โ€” | โš ๏ธ 403 at edge (use upload/heartbeat) | | **WireGuard data** | `ra.apps.f0xx.org:45340/udp` | โœ… lab mode | โ€” | โœ… DNAT chain + BE listen | | **RSSH bastion** | `ra.apps.f0xx.org:443/tcp` | โœ… alpha mode | Operator SSH | โœ… API connect payload | --- ## Data paths ### Cast session (LAN โ€” alpha scope) ```text Sender UDP/TCP :41235 โ†โ†’ Receiver :41235 Discovery UDP :41234 (+ NSD) ``` No BE required for LAN alpha. ### Telemetry path ```text Phone โ†’ HTTPS โ†’ FE โ†’ BE PHP upload.php crash JSON heartbeat.php session + RA graph_upload.php session metrics ``` ### Remote access control plane ```text Phone poll โ†’ heartbeat.php (type:ra) Operator โ†’ remote_access.php (whitelist, open_session, dashboard) BE โ†’ wg set / rssh session row โ†’ connect JSON on next poll ``` --- ## Validation status Run: `examples/crash_reporter/backend/scripts/validate_be_services.sh` | Check | 2026-06-08 result | |-------|-------------------| | Hub / crashes / graphs / build HTTP | โœ… | | JS syntax (app, graphs, tickets, i18n) | โœ… | | RBAC API smoke (on BE localhost) | โœ… | | RA API smoke | โœ… (BE) | | RSSH API smoke | โœ… `test_rssh_api.sh` | | OTA public URL | FAIL 400 | | Browser SyntaxError (historical) | โœ… cleared โ€” deployed JS passes `node --check` | --- ## DNAT chain (WireGuard lab) ```mermaid sequenceDiagram participant M as Mobile / laptop participant R as Router f0xx.org participant F as FE monstro participant B as BE wg0 M->>R: UDP 45340 (public) R->>F: DNAT โ†’ 10.7.0.10:45340 F->>B: DNAT โ†’ 10.7.16.128:45340 B->>B: wg0 decrypt ``` | Script | Host | Persist hook | |--------|------|--------------| | `wireguard_router_dnat.sh` | `f0xx.org` `/home/scripts/` | `iodine_warmup_helper.sh apply_rules` | | `wireguard_fe_dnat.sh` | `f0xx-monstro` | `xen_firewall.sh start/stop` | | `install_be_remote_access.sh` | `alpine-be` | `wg0` + sudoers | --- ## RSSH / RBAC | Component | Path | Tune on BE | |-----------|------|------------| | RSSH sessions | `sql/migrations/009_rssh_sessions.sql` | MariaDB migrate | | Provisioner | `src/RsshSessionProvisioner.php` | `config.php` โ†’ `remote_access.rssh` | | Bastion | `sshd` / stream on `:443` | host keys, port range `18000โ€“18999` | | RBAC API | `api/rbac.php` | `privilege_sets`, lockout clear | | Cron purge | `scripts/purge_remote_access.php` | hourly crontab | **Smoke:** `test_rssh_api.sh`, `test_rbac_api.sh`, `ra_e2e_cli.sh` --- ## Planned: SFU relay (Janus-class) > **Not in alpha.** Gray = future design surface; implementation on branch `feature/sfu-relay`, hidden from users until spec lands. ```mermaid flowchart TB classDef future fill:#e5e7eb,stroke:#9ca3af,color:#374151 subgraph Future["SFU path (planned)"] SFU["Janus / mediasoup SFU
BE :8089 or dedicated"] SIG["Signaling API
PHP or sidecar"] TURN["TURN optional"] end subgraph Today["Alpha today"] LAN["LAN UDP/TCP cast"] RA["RSSH debug"] end MOB2["๐Ÿ“ฑ Android"] --> LAN MOB2 -.->|"post-alpha"| SIG SIG -.-> SFU SFU -.-> TURN OPS2["Operator"] -.-> SIG class SFU,SIG,TURN future ``` | Piece | Status | Branch / flag | |-------|--------|---------------| | `CastConfig.SFU_RELAY_PREVIEW` | Stub `false` | `feature/sfu-relay` | | `config.php` โ†’ `sfu.enabled` | Stub `false` | BE | | `api/sfu_health.php` | Returns `disabled` | BE | | Android `SfuRelayGate` | Hidden dev compile gate | App | | FE nginx `location /janus/` | Exists for other stack โ€” **do not mix** with androidcast vhost | INFRA ยง8089 | | Nginx + UDP ports for WebRTC | Design TBD with owner spec | โ€” | | Mobile `TRANSPORT_WEBRTC` UI | Frozen (`ALPHA_FEATURE_FREEZE`) | โ€” | When the owner spec arrives: wire signaling auth to existing session/RBAC, add SFU room lifecycle beside (not replacing) LAN cast, and extend this doc ยง with concrete ports and URLs. --- ## Agent scripts | Script | Purpose | |--------|---------| | `validate_be_services.sh` | Public reachability + JS syntax | | `verify_remote_access_prod.sh` | BE WG/RSSH preflight | | `test_rssh_api.sh` | RSSH connect payload | | `test_rbac_api.sh` | RBAC panel API | | `ra_e2e_cli.sh` | Full RA operator+device flow | | `test_graphs_api.sh` | Graph ingest + dashboard | --- ## Open findings โ†’ tickets | ID | Severity | Topic | Track in | |----|----------|-------|----------| | **SVC-OTA** | High | OTA `v0/ota` returns 400 on `apps.f0xx.org` โ€” wire nginx + staging path | **Tickets** dashboard | | **SVC-DIAG** | Low | `diag.php` 403 at public edge | **Issues** (documented workaround) | | **SVC-URL** | Medium | Legacy `f0xx.org` crash URL 404 โ€” devices should use `apps.f0xx.org` | **Tickets** + device `settings.json` | | **SFU-SPEC** | Planning | Owner SFU spec integration | **Issues** (gray / post-alpha) | File via crashes console โ†’ **Tickets** for service/URL/nginx work; **Issues** for infra validation notes and SFU planning.