# 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.