Project repository and structure reorganization draft
milestone: R0-pre
severity: high
state: pre-implementation
author: Anton Afanasyeu
date: 2026-06-18

[AI comment]: Updated 2026-06-18 — PO chose org **`ac`**, **full microservice** end-state, separate **ac-scripts**, URL path migration (§L), optional **ac-workspace** (not build-all-in-one), VM-first cloud (§N). See §G master repo table.

The problem:
The project looks like monolith. For better and more atomic support we need to reorganize the whole project repo structure

[AI comment]: Agree on the problem, but **atomic** should mean: independent release cadence, CI, deploy, and rollback — not “one git repo per PHP class.” Today’s real coupling is **one MariaDB**, **one PHP session** (`ac_crash_sess`, [BUILD_DEPLOY.md](../BUILD_DEPLOY.md)), and **one nginx vhost tree** on BE. Split repos before extracting shared platform code will multiply broken deploys.

──────────────────────────────────────────────────────────────────────────────
A. Current codebase map (monolith → draft names)
──────────────────────────────────────────────────────────────────────────────

| Draft name / intent | Actual path today | Coupling notes |
|---------------------|-------------------|----------------|
| ac-mobile | `app/`, `ndk/`, `gradle/`, `build.gradle`, `settings.gradle` | WireGuard tunnel module; `third-party/*` submodules |
| ac-session-studio | `desktop/session-studio/` | Standalone; low coupling — **easy first extract** |
| ac-docs | `docs/` (+ `docs/_pdf_build/`) | No runtime deps — **easy extract** |
| ac-scripts | `scripts/` (pdf, native codecs, OTA, CI helpers) | Used by mobile + orchestration; keep with **ac-deploy** or meta until split clear |
| ac-be-console (crashes/issues/tickets/graphs/rbac/ra) | `examples/crash_reporter/backend/` | **32 PHP classes**, 24 `public/api/*.php`, shared `Auth.php`, `Database.php`, `Rbac.php` — **one modular monolith** |
| ac-be-builder | `examples/build_console/backend/` | Separate app; shares auth pattern via `examples/platform/shared_session.php` + same DB users table |
| ac-be-landing | `examples/app_hub/` | Static hub + deploy nginx snippets |
| ac-be-ota (artifacts) | `examples/ota/v0/...` | Files on disk + nginx; logic also in builder + `scripts/generate-ota-v0.sh` |
| ac-ms-url-shortener | `backend/url-shortener/` | **Only live submodule today** — `git://f0xx.org/androidcast_project/url-shortener` |
| ac-deploy / orchestration | `orchestration/` (docker, cluster0, nginx, runtime) | Local stack + **cast01–03** lab ([orchestration/sim/cluster0/ARCHITECTURE.md](../../orchestration/sim/cluster0/ARCHITECTURE.md)) |
| ac-ms-vpn / WG / RSSH | Mobile: `app/.../remoteaccess/`; BE: `RemoteAccessRepository.php`, `WireGuard*`, `Rssh*` provisioners | **Split by plane**: client in mobile, control API in BE console — not two deployables yet |
| ac-ms-vcs (gitea) | `examples/crash_reporter/backend/scripts/gitea/` | **Ops scripts only** — Gitea is external service on BE, not app source |
| ac-ms-tracker / analytics | `Ticket*`, `Graph*` repos in crash_reporter | Same DB + session — **logical modules**, not separate services today |
| SFU stub | `examples/sfu/`, `api/sfu_health.php` | Post-alpha; stay in console until F1 SPEC |
| Experimental / lab | Nested `.git` under `examples/` (not `third-party/` or `backend/url-shortener`) | **Out of scope** — omit from migration docs and manifests |
| third-party codecs | `third-party/libvpx|opus|speex|wireguard-android` | Stay **submodules of ac-mobile** (upstream URLs unchanged); Gitea mirrors per existing migrate script |

[AI comment]: **Correction for draft “how” section:** `be-console` is **not** `./examples/build_console` — that is **builder**. Primary operator console is **`examples/crash_reporter/backend`** (crashes + tickets + graphs + RBAC + remote access APIs). Builder is separate product surface under `/build/`.

──────────────────────────────────────────────────────────────────────────────
B. Infrastructure & cloud fit (combine lab + prod + future cloud)
──────────────────────────────────────────────────────────────────────────────

Principles (from [specs/20100612_1_scaling.md](../specs/20100612_1_scaling.md), [INFRA.md](../INFRA.md), cluster0):

1. **Deploy unit = VM role or container image**, not git repo count. Phase A prod: `be-web-1` runs nginx + PHP-FPM for hub + console + graphs UI; `be-data-1` MariaDB; `be-ops-1` url-shortener + Gitea; `be-build-1` builder.

2. **cluster0 pattern** (NFS config only, app on local disk, GTID MariaDB) maps to cloud as:
   - NFS `/shared/cluster/` → **ConfigMaps / object storage** for nginx + SQL seeds + scripts
   - Per-node `/var/www/...` → **container image** or **git pull on VM** per service
   - Managed DB → **connection string in secret** (PO: “pay for DB service”) — must **not** live in `ms-common` git

3. **PHP session + RBAC**: Shared cookie path `/app/androidcast_project` across hub/crashes/build ([BUILD_DEPLOY.md](../BUILD_DEPLOY.md)). Until true SSO/service tokens exist, **splitting BE UI repos is fine**; splitting **API auth** into N repos without `ac-platform-php` Composer package is painful.

4. **OpenAPI**: PO wants MS OpenAPI-compatible — today APIs are PHP files, not generated spec. Recommend **`ac-platform-openapi`** (or `ac-docs/openapi/`) as **contract-first** artifacts; implement in console first, extract services later.

5. **CI**: `build.config.yml` + CircleCI shape assume **monorepo checkout**. Meta-repo needs **per-repo pipelines** + `ac-deploy` triggering builds with `git_ref` across submodules (builder already does this for `android_cast`).

6. **URL / paths:** Under **discussion** — PO wants path-per-service (§M), not frozen `?view=` under `/crashes/`. nginx + mobile `BackendEndpoints` must migrate with redirects.

[AI comment]: Shared cookie path may become `/app/androidcast_project/` at **edge** only while backends move to `/issues/`, `/tickets/`, etc.

──────────────────────────────────────────────────────────────────────────────
C. Target structure — **full microservice** (PO decision 2026-06-18)
──────────────────────────────────────────────────────────────────────────────

PO chose **full microservice** end-state (§K comparison). Delivery remains **phased** (§D).

```text
Platform (libraries — Composer, not runtime MS)
  ac-platform-php, ac-platform-db, ac-platform-web, ac-scripts, ac-docs

Infrastructure
  ac-deploy          submodules ac-scripts; cluster0/docker/nginx
  ac-workspace       optional clone manifest only (§N) — NOT unified build

Clients
  ac-mobile-android  (+ future ac-mobile-ios)
  ac-session-studio

Microservices (OpenAPI APIs / workers)
  ac-ms-identity, ac-ms-rbac, ac-ms-devices, ac-ms-issues, ac-ms-tickets,
  ac-ms-graphs, ac-ms-remote-access, ac-ms-url-shortener, ac-ms-build,
  ac-ms-ota, ac-ms-notifications (later)

Backend UI (thin)
  ac-be-hub, ac-be-issues, ac-be-tickets, ac-be-graphs, ac-be-remote-access,
  ac-be-access, ac-be-builder, ac-be-auth (optional)

Edge
  ac-platform-edge   nginx BFF — recommended for cookie + URL migration (§M)
```

[AI]: Collapse PO’s **ms-vpn-rssh** + **ms-vpn-wireguard** → **ac-ms-remote-access**. Drop **ac-ms-vcs** as code repo (Gitea = infra). Drop **ac-ms-tracker** as separate MS — split into **ac-ms-issues** + **ac-ms-tickets** (different URLs PO wants).

**Risk mitigation:** Composer semver for platform libs (avoid @common submodule diamond in 20+ repos).

──────────────────────────────────────────────────────────────────────────────
D. Phased migration (safe order — no big-bang)
──────────────────────────────────────────────────────────────────────────────

| Phase | Action | Alpha blocker? | Rollback |
|-------|--------|----------------|----------|
| **P0** | Create Gitea org **`ac`**; mirror legacy → **ac-workspace** (optional) | No | Keep `android_cast` mirror |
| **P1** | Extract **ac-docs**, **ac-session-studio** submodules; meta points SHAs | No | Revert submodule |
| **P2** | Extract **ac-ms-url-shortener** path to `ac/ac-ms-url-shortener` (already submodule — change URL only) | No | Old URL works via mirror |
| **P3** | **ac-platform-php** + **ac-platform-web** + **ac-ms-identity** first (everything depends on auth) | **Yes** for MS split | Shim monolith |
| **P4** | Extract **ac-ms-issues**, **ac-ms-tickets**, **ac-ms-rbac**, **ac-ms-devices** + matching **ac-be-*** UI repos | Medium | Edge proxy to monolith |
| **P5** | **ac-mobile-android**, **ac-deploy** (+ submodule **ac-scripts**), **ac-ms-build**, **ac-ms-ota** | Medium | Per-repo CI |
| **P6** | **ac-platform-edge** nginx routes (§M); retire `/crashes/?view=` | Medium | 301 redirects |
| **P7** | cluster0 + cloud VMs (§O); optional **ac-ms-graphs**, **ac-ms-remote-access** | No | Per scaling SPEC |

[AI comment]: Do **not** start P4 until P3 — otherwise Auth/Database duplicates diverge in days.

**ms-common sensitive data:** Split into:
- `ac-platform-php` — code (session helpers, RBAC classes, DB adapter interfaces)
- **Runtime config** — `config.php` / env / K8s secrets per deploy (never in git)
- Optional `ac-platform-db` — **SQL migrations only** (shared schema), consumed by console + shortener + builder

──────────────────────────────────────────────────────────────────────────────
E. The what (original table — annotated)
──────────────────────────────────────────────────────────────────────────────

Current project structure
Project                         | Placement                     | Repo                                              | State                       | Description
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AndroidCast all in one          | repo root                     | git://f0xx.org/android_cast                       | monolithic                  | all-in-one project, needs to be splitted
[AI]: → becomes **ac-meta** umbrella; keep **read-only mirror** at old URL ≥ 1 release
libvpx                          | third-party/libvpx            | https://chromium.googlesource.com/webm/libvpx     | 3rdparty exported submodule | VPx video codecs
[AI]: stays upstream URL in .gitmodules; Gitea mirror `AndroidCast/libvpx` unchanged
opus                            | third-party/opus              | https://github.com/xiph/opus                      | 3rdparty exported submodule | Opus voice codec
speex                           | third-party/speex             | https://github.com/xiph/speex/                    | 3rdparty exported submodule | Speex voice codec
wireguard                       | third-party/wireguard-android | https://git.zx2c4.com/wireguard-android           | 3rdparty exported submodule | wireguard for android
url-shortener                   | backend/url-shortener         | git://f0xx.org/androidcast_project/url-shortener  | part of AndroidCast backend | url shortener standalone backend
[AI]: migrate to **git://f0xx.org/ac/ac-ms-url-shortener**; alias old URL

──────────────────────────────────────────────────────────────────────────────
F. The how (original target — annotated + fixes)
──────────────────────────────────────────────────────────────────────────────

Next hope project structure

AndroidCast project - all in one  | git://f0xx.org/ac/ac-meta
  |-- AndroidCast - common        | @ac-platform-php  [AI: Composer, not submodule diamond]
  |-- AndroidCast - mobile        | @ac-mobile
  |-- AndroidCast - BE            | @ac-be-console (+ builder, hub as siblings)
... TBD

AndroidCast project           | Placement (@ - submodule)     | Description                                   |  Repo
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AndroidCast - common          | @common                       | project all common                            | git://f0xx.org/ac/ac-common
[AI]: **Rename → ac-platform-php** (Composer). Reserve **ac-common** for non-PHP only: LICENSE templates, OpenAPI, semver constants — or drop repo and fold into ac-docs.
  |-- AndroidCast - docs      | @docs                         | project docs, BE, MS, mobile, web, everything | git://f0xx.org/ac/ac-docs
  |-- AndroidCast - scripts   | @scripts                      | common project scripts                        | git://f0xx.org/ac/ac-scripts
[AI]: merge ac-scripts into **ac-deploy** unless mobile-only scripts dominate
AndroidCast - mobile          | @mobile                       | mobile app sources                            | git://f0xx.org/ac/ac-mobile
  |-- AndroidCast - common    | @common                       |                                               | git://f0xx.org/ac/ac-common
[AI]: mobile should NOT submodule ac-common PHP — only third-party natives
AndroidCast - Session Studio  | @session-studio               | offline analytic tools                        | git://f0xx.org/ac/ac-session-studio
  |-- AndroidCast - common    | @common                       |                                               | git://f0xx.org/ac/ac-common
[AI]: session-studio has no PHP dep — drop @common edge
AndroidCast - BE - MS         | @backend                      | backend microservices common base (UI)        | git://f0xx.org/ac/ac-be-microservice
[AI]: **Overloaded name.** Split: **ac-be-console** (main UI+API), **ac-platform-php** (lib). “ac-be-microservice” as umbrella meta for BE apps optional.
  |-- AndroidCast - common    | @common                       |                                               | git://f0xx.org/ac/ac-common
AndroidCast - MS              | @microservices                | microservice commons                          | git://f0xx.org/ac/ac-microservice
[AI]: defer **ac-microservice** meta-repo until ≥3 independently deployed APIs exist (today: 1 = url-shortener)
  |-- AndroidCast - common    | @common                       |                                               | git://f0xx.org/ac/ac-common
... TBD

AndroidCast BE microservices and their derivatives (OpenAPI providers, any REST API services for web and mobile apps)
AndroidCast - MS - template <- AndroidCast - MS (@ means suibmodule)                                        |git://f0xx.org/ac/ac-microservice/ac-ms-template 
[AI]: good template for **future** services; seed from url-shortener layout (public/, src/, sql/, tests/)
  | -- AndroidCast - common                     | @common           | project all common                    | git://f0xx.org/ac/ac-common
  | -- AndroidCast - MS - common                | @ms-common        | microservices common                  | git://f0xx.org/ac/ac-microservice/ac-ms-common
[AI]: **ms-common = ac-platform-php + openapi + migration runner** — NOT DB passwords. Fix typo **@ms-commmon** in remote-access row below.
    |-- AndroidCast - MS - builder              | @ms-builder       | builder microservice                  | git://f0xx.org/ac/ac-microservice/ac-ms-builder
[AI]: today = **ac-be-builder** (UI+worker in one); split worker when be-build-1 is isolated CI agent only
    |-- AndroidCast - MS - VPN                  | @ms-vpn           | VPN microservice                      | git://f0xx.org/ac/ac-microservice/ac-ms-vpn
[AI]: **Phase 6+** — API surface = `remote_access.php` + provisioners; client stays in ac-mobile
      |-- AndroidCast - MS - VPN - RSSH         | @ms-vpn-rssh      | VPN RSSH microservice                 | git://f0xx.org/ac/ac-microservice/ac-ms-vpn-rssh
      |-- AndroidCast - MS - VPN - WireGuard    | @ms-vpn-wireguard | VPN WG microservice                   | git://f0xx.org/ac/ac-microservice/ac-ms-vpn-wireguard
[AI]: package by directory inside console first: `src/RemoteAccess/Rssh/`, `src/RemoteAccess/WireGuard/`
    |-- AndroidCast - MS - VCS                  | @ms-vcs           | VCS  microservice (gitea)             | git://f0xx.org/ac/ac-microservice/ac-ms-vcs
[AI]: **Not a code repo** — Gitea is infra; keep **ac-deploy** scripts + docs for Gitea ops
    |-- AndroidCast - MS - URL shortener        | @ms-url-shortener | URL shortener microservice            | git://f0xx.org/ac/ac-microservice/ac-ms-url-shortener
[AI]: **P2** — flatten path to `git://f0xx.org/ac/ac-ms-url-shortener` (no nested ac-microservice parent)
    |-- AndroidCast - MS - analytics            | @ms-analytics     | analytics microservice                | git://f0xx.org/ac/ac-microservice/ac-ms-analytics
[AI]: graphs ingest + GA config — module in console until read load warrants split
    |-- AndroidCast - MS - orchestration        | @ms-orchestration | orchestration microservice            | git://f0xx.org/ac/ac-microservice/ac-ms-orchestration
[AI]: today = **ac-deploy** + builder API; name collision with folder `orchestration/`
    |-- AndroidCast - MS - tracker              | @ms-tracker       | issues & tickets tracker microservice | git://f0xx.org/ac/ac-microservice/ac-ms-tracker
    |-- AndroidCast - MS - RBAC                 | @ms-rbac          | RBAC microservice                     | git://f0xx.org/ac/ac-microservice/ac-ms-rbac
... TBD

Sub-project of AndroidCast BE/MS, mostly Web UI stuff, but also should be OpenAPI-compatible and provide services to the mobile app (@ means suibmodule)
AndroidCast - BE - common <- AndroidCast - BE - MS              | git://f0xx.org/ac/ac-backend
[AI]: prefer **per-app repos** (ac-be-console, ac-be-builder, …) over deep `ac-backend/*` tree — flatter Gitea permissions
  |-- AndroidCast - BE - vcs (UI)           | @be-vcs           | VCS frontend, former gitea, backend UI  | git://f0xx.org/ac/ac-backend/ac-be-vcs
[AI]: Gitea **is** the UI — link from hub only; optional thin PHP wrapper if needed
    |-- AndroidCast - MS - vcs              | @ms-vcs           | VCS microservice (gitea)                | git://f0xx.org/ac/ac-microservice/ac-ms-vcs
  |-- AndroidCast - BE - console (UI)       | @be-console       | git://f0xx.org/ac/ac-backend/ac-be-console              | primary console, ./examples/build_console ? check if it is
[AI]: **FIX:** primary console = **ac-be-console** ← `examples/crash_reporter/backend`. Builder = **ac-be-builder** ← `examples/build_console`.
    |-- AndroidCast - MS - common           | @ms-common        | git://f0xx.org/ac/ac-microservice/ac-ms-common          | microservice commons
  |-- AndroidCast - BE - landing (UI)       | @be-landing       | git://f0xx.org/ac/ac-backend/ac-be-landing              | landing page(s), now in ./examples/app_hub
    |-- AndroidCast - MS - common           | @ms-common        | git://f0xx.org/ac/ac-microservice/ac-ms-common          | microservice commons
  |-- AndroidCast - BE - issues (UI)        | @be-issues        | git://f0xx.org/ac/ac-backend/ac-be-issues               | issues tracker UI, now is in ./examples somewhere
[AI]: **same PHP app** as tickets — `?view=` routes in crash_reporter views, not separate deployable
    |-- AndroidCast - MS - tracker          | @ms-tracker       | git://f0xx.org/ac/ac-microservice/ac-ms-tracker         | issues tracker microservice shared base, now is in ./examples somewhere
  |-- AndroidCast - BE - tickets (UI)       | @be-tickets       | git://f0xx.org/ac/ac-backend/ac-be-tickets              | tickets UI, now is in ./examples somewhere
    |-- AndroidCast - MS - tracker          | @ms-tracker       | git://f0xx.org/ac/ac-microservice/ac-ms-tracker         | issues tracker microservice shared base, now is in ./examples somewhere
  |-- AndroidCast - BE - graphs (UI)        | @be-graphs        | git://f0xx.org/ac/ac-backend/ac-be-graphs               | graphs UI, now somewhere in ./examples
    |-- AndroidCast - MS - analytics        | @ms-analytics     | git://f0xx.org/ac/ac-microservice/ac-ms-analytics       | analytics base microservice
  |-- AndroidCast - BE - analytics (UI)     | @be-analytics     | git://f0xx.org/ac/ac-backend/ac-be-analytics            | analytics and statistics web UI
    |-- AndroidCast - MS - analytics        | @ms-analytics     | git://f0xx.org/ac/ac-microservice/ac-ms-analytics       | analytics base microservice
[AI]: graphs + analytics UI = views inside **ac-be-console** today (`GraphRepository`, `AnalyticsHead`)
  |-- AndroidCast - BE - remote access (UI) | @be-remote-access | git://f0xx.org/ac/ac-backend/ac-be-remote-access        | remote access (now for vpn, somewhere in ./examples now) UI
    |-- AndroidCast - MS - common           | @ms-commmon       | git://f0xx.org/ac/ac-microservice/ac-ms-common          | microservice commons
[AI]: typo **commmon** → common; RA UI = admin views in console + mobile app
    |-- AndroidCast - MS - VPN              | @ms-vpn           | git://f0xx.org/ac/ac-microservice/ac-ms-vpn             | VPN MS as a dependency
    |-- AndroidCast - MS - RBAC | @ms-rbac  | @ms-rbac          | git://f0xx.org/ac/ac-microservice/ac-ms-rbac            | RBAC MS as a dependency
  |-- AndroidCast - BE - URL shortener (UI) | @be-url-shortener | git://f0xx.org/ac/ac-backend/ac-be-url-shortener        | URL shortener UI, now is in separate submodule
[AI]: short-link **admin UI** is in crash console (`short_links.js`, hub tokens); **API** is submodule
    |-- AndroidCast - MS - URL shortener    | @ms-url-shortener | git://f0xx.org/ac/ac-microservice/ac-ms-url-shortener   | URL shortener microservice, now is in separate submodule
  |-- AndroidCast - BE - builder (UI)       | @be-builder       | git://f0xx.org/ac/ac-backend/ac-be-builder              | orchestration builder UI, now in ./orchestration
[AI]: **FIX:** builder UI = `examples/build_console`; **orchestration/** = docker/cluster0 (**ac-deploy**)
    |-- AndroidCast - MS - orchestration    | @ms-orchestration | git://f0xx.org/ac/ac-microservice/ac-ms-orchestration   | orchestration microservice, now in ./orchestration
  |-- AndroidCast - BE - RBAC (UI)          | @be-rbac          | git://f0xx.org/ac/ac-backend/ac-be-rbac                 | RBAC backend, now mixed within ./examples somewhere
    |-- AndroidCast - MS - common           | @ms-common        | git://f0xx.org/ac/ac-microservice/ac-ms-common          | microservice commons
    |-- AndroidCast - MS - RBAC             | @ms-rbac          | git://f0xx.org/ac/ac-microservice/ac-ms-rbac            | RBAC microservice
  |-- AndroidCast - BE - OTA                | @be-ota           | git://f0xx.org/ac/ac-backend/ac-be-ota                  | OTA BE UI
    |-- AndroidCast - MS - OTA              | @ms-ota           | git://f0xx.org/ac/ac-microservice/ac-ms-ota             | OTA microservice, now intermixed in examples/ota and other commons
[AI]: OTA = static tree + builder publish + nginx location; extract API when `5.1 OTA` nginx stable
... TBD

ms-common (microservices common) needs a sharp eye, it may share project sensitive parts, like common stuff such as shared web sessions, DB access (or should be separated to @be-db-service/@ac-db-service sort of)
[AI]: **Agree.** Recommended split:
  - **ac-platform-php** — session *code*, Auth, Rbac, PDO factory (reads DSN from env)
  - **ac-platform-db** — SQL migrations + schema version table (shared by console, builder, shortener)
  - **ac-deploy/secrets** — example only; prod DSN in vault / Alpine `config.php` outside git
  - **No ac-db-service runtime** until you run DB proxy (PlanetScale, RDS, etc.) — app VMs use driver + secret

──────────────────────────────────────────────────────────────────────────────
G. FULL REPO CATALOG — microservice end-state (Gitea org **ac**)
──────────────────────────────────────────────────────────────────────────────

Canonical clone: `git://f0xx.org/ac/<repo>`. HTTPS UI: `https://apps.f0xx.org/app/androidcast_project/git/ac/<repo>.git` (path TBD with edge migration). Legacy `git://f0xx.org/android_cast` → read-only mirror until retired.

| ID | Repo | Git URL | Role | From (monolith) | VM / cloud slot |
|----|------|---------|------|-----------------|-----------------|
| **Workspace** |
| W0 | ac-workspace | `git://f0xx.org/ac/ac-workspace` | Optional submodule manifest; **no unified build** | `.gitmodules` | dev laptops |
| **Platform** |
| P0 | ac-platform-php | `git://f0xx.org/ac/ac-platform-php` | Composer: HTTP, auth client, PDO factory | Auth*, bootstrap | baked into PHP images |
| P1 | ac-platform-db | `git://f0xx.org/ac/ac-platform-db` | SQL migrations + schema version | sql/, migrations | be-data-1 job |
| P2 | ac-platform-web | `git://f0xx.org/ac/ac-platform-web` | Shared CSS/JS/theme | crashes/assets, hub links | CDN / edge static |
| P3 | ac-platform-edge | `git://f0xx.org/ac/ac-platform-edge` | nginx routes, cookie domain, proxy | fe/apps.conf | be-web-1 / FE |
| P4 | ac-scripts | `git://f0xx.org/ac/ac-scripts` | CI, OTA, native codec, pdf scripts | `scripts/` | CI runners |
| P5 | ac-docs | `git://f0xx.org/ac/ac-docs` | Documentation | `docs/` | — |
| **Deploy** |
| D0 | ac-deploy | `git://f0xx.org/ac/ac-deploy` | docker, cluster0, env templates; **uses ac-scripts** | `orchestration/` | all VMs |
| **Clients** |
| C0 | ac-mobile-android | `git://f0xx.org/ac/ac-mobile-android` | Android app + ndk + third-party | `app/`, `ndk/` | CI → OTA |
| C1 | ac-mobile-ios | `git://f0xx.org/ac/ac-mobile-ios` | Future iOS client | — | CI → OTA |
| C2 | ac-session-studio | `git://f0xx.org/ac/ac-session-studio` | Desktop analyzer | `desktop/session-studio/` | releases |
| **Microservices** |
| S0 | ac-ms-template | `git://f0xx.org/ac/ac-ms-template` | Cookiecutter for new PHP MS | url-shortener layout | — |
| S1 | ac-ms-identity | `git://f0xx.org/ac/ac-ms-identity` | Users, login, register, 2FA, sessions | Auth*, UserRepository | be-web-1 |
| S2 | ac-ms-rbac | `git://f0xx.org/ac/ac-ms-rbac` | Companies, memberships, privileges | Rbac*, RbacAdmin* | be-web-1 |
| S3 | ac-ms-devices | `git://f0xx.org/ac/ac-ms-devices` | Device registry | DeviceRepository | be-web-1 |
| S4 | ac-ms-issues | `git://f0xx.org/ac/ac-ms-issues` | Crash/report ingest + reports API | upload, Report*, Tag* | be-web-1 |
| S5 | ac-ms-tickets | `git://f0xx.org/ac/ac-ms-tickets` | Tickets workflow, comments, attachments | Ticket* | be-web-1 |
| S6 | ac-ms-graphs | `git://f0xx.org/ac/ac-ms-graphs` | Graph ingest + query | GraphRepository, graph_*.php | be-web-1 |
| S7 | ac-ms-remote-access | `git://f0xx.org/ac/ac-ms-remote-access` | WG + RSSH control API | RemoteAccess*, WireGuard*, Rssh* | be-ops-1 |
| S8 | ac-ms-url-shortener | `git://f0xx.org/ac/ac-ms-url-shortener` | Short link API | `backend/url-shortener/` | be-ops-1 |
| S9 | ac-ms-build | `git://f0xx.org/ac/ac-ms-build` | Build queue + worker API | BuildRunner, build_console APIs | be-build-1 |
| S10 | ac-ms-ota | `git://f0xx.org/ac/ac-ms-ota` | Channel manifests; multi-client SHAs | OTA scripts + v0 tree | be-web-1 / OBJ |
| S11 | ac-ms-notifications | `git://f0xx.org/ac/ac-ms-notifications` | SMTP / auth mail (post-alpha) | AuthMailer | be-ops-1 |
| **Backend UI** |
| B0 | ac-be-hub | `git://f0xx.org/ac/ac-be-hub` | Landing | `examples/app_hub/` | be-web-1 |
| B1 | ac-be-issues | `git://f0xx.org/ac/ac-be-issues` | Issues UI → S4 | views reports/* | be-web-1 |
| B2 | ac-be-tickets | `git://f0xx.org/ac/ac-be-tickets` | Tickets UI → S5 | views tickets/* | be-web-1 |
| B3 | ac-be-graphs | `git://f0xx.org/ac/ac-be-graphs` | Graphs dashboard UI | graphs views | be-web-1 |
| B4 | ac-be-remote-access | `git://f0xx.org/ac/ac-be-remote-access` | RA admin UI → S7 | view remote_access | be-web-1 |
| B5 | ac-be-access | `git://f0xx.org/ac/ac-be-access` | RBAC admin UI → S2 | view rbac | be-web-1 |
| B6 | ac-be-builder | `git://f0xx.org/ac/ac-be-builder` | Builder UI → S9 | `examples/build_console/` | be-build-1 |
| B7 | ac-be-auth | `git://f0xx.org/ac/ac-be-auth` | Login/register chrome → S1 | login.php shared | be-web-1 |
| **Third-party (submodules of C0 only)** |
| — | libvpx, opus, speex, wireguard-android | upstream URLs + Gitea mirrors under `ac/` | Native deps | `third-party/*` | mobile CI |
| **Future** |
| F1 | ac-ms-sfu-signaling | `git://f0xx.org/ac/ac-ms-sfu-signaling` | WebRTC signaling | examples/sfu | be-media-N |
| F2 | ac-ms-media-transcode | `git://f0xx.org/ac/ac-ms-media-transcode` | VOD/ffmpeg | V.2x draft | be-media-N |

**PO draft mapping fixes:**
- `ac-be-console` (monolith) → **dissolved** into B1–B5 + S4–S7
- `ac-ms-tracker` → **S4 + S5** (issues ≠ tickets — PO URL split confirms)
- `ac-ms-analytics` → **S6** (graphs) + later BI; GA config in **P2 platform-web**
- `ac-ms-orchestration` → **S9 + D0** (worker vs deploy)
- `ac-ms-vcs` → **not a repo**; document in **D0**
- `ac-be-url-shortener` UI → admin panel in **B5** or **B0** calling **S8** (tokens already in crashes console)

**ac-deploy ↔ ac-scripts:** D0 submodules P4 at pinned SHA; deploy-local scripts only for image entrypoints.

──────────────────────────────────────────────────────────────────────────────
H. ac-workspace sketch (optional — PO §5)
──────────────────────────────────────────────────────────────────────────────

**Purpose:** “I only work on mobile” or “I only work on tickets UI” — clone workspace, init selected submodules. **Not** for building everything in one Gradle/PHP tree.

```ini
# ac-workspace — example partial checkout
[submodule "mobile-android"]
	path = clients/android
	url = git://f0xx.org/ac/ac-mobile-android
[submodule "ms-issues"]
	path = services/issues
	url = git://f0xx.org/ac/ac-ms-issues
[submodule "be-issues"]
	path = ui/issues
	url = git://f0xx.org/ac/ac-be-issues
[submodule "deploy"]
	path = deploy
	url = git://f0xx.org/ac/ac-deploy
```

Developers without workspace clone individual repos directly.

──────────────────────────────────────────────────────────────────────────────
I. PO decisions (2026-06-18) — recorded
──────────────────────────────────────────────────────────────────────────────

| # | Question | Decision |
|---|----------|----------|
| 1 | Gitea org | **`ac`** |
| 2 | Architecture | **Full microservice** end-state (phased delivery) — §K |
| 3 | ac-scripts | **Separate repo**; **ac-deploy submodules/invokes it** |
| 4 | Public URLs | **Change desired** — path-per-service (§M); not frozen under `/crashes/?view=` |
| 5 | Meta repo | **`ac-workspace` optional** — selective clone only; **not** build-all-in-one; §N OTA |
| 6 | Cloud | **No K8s requirement** — start VM lift-and-shift (§O); K8s later optional |

──────────────────────────────────────────────────────────────────────────────
J. Microservice vs modular monolith — comparison (PO requested)
──────────────────────────────────────────────────────────────────────────────

| Criterion | Full microservice (PO choice) | Modular monolith (single ac-be-console) |
|-----------|------------------------------|----------------------------------------|
| **Independent deploy** | Deploy tickets without touching issues | One PHP deploy for any UI fix |
| **Team scaling** | Different owners per repo/service | Single codebase, simpler grep |
| **Failure isolation** | Ticket MS down ≠ crash ingest | Shared FPM pool — blast radius larger |
| **CI speed** | Small repos, faster per-service tests | One `./gradlew`-scale PHP test suite |
| **Auth/session** | Needs **ac-ms-identity** + edge cookie early | Already works (`ac_crash_sess`) |
| **DB** | Shared MariaDB OK initially; schema ownership per MS | One migration stream today |
| **Operational cost** | More nginx routes, more images, more logs | One BE tree to sync ([INFRA.md](../INFRA.md)) |
| **PO microservice learning curve** | Higher — mitigated by **ac-ms-template**, **D0** | Lower short-term |
| **Cloud path** | Maps 1:1 to VM roles then containers | Lift whole monolith first |
| **URL clarity** | Natural `/issues/`, `/tickets/` per service | Stuck on `?view=` without refactor |
| **Rollback** | Revert one service SHA | Revert one monolith commit |
| **Risk for alpha** | **Higher** if done before identity split | Lower — current prod pattern |

[AI]: PO choice is valid **if P3 (identity + platform) is non-negotiable first**. Without it, full MS split repeats the build-console/bootstrap.php class of failures across N repos.

──────────────────────────────────────────────────────────────────────────────
K. Service dependency graph (logical + structural + repo)
──────────────────────────────────────────────────────────────────────────────

```mermaid
flowchart TB
    subgraph clients [Clients]
        AND[ac-mobile-android]
        IOS[ac-mobile-ios future]
        HUB[ac-be-hub]
        SS[ac-session-studio]
    end

    subgraph edge [Edge]
        EDGE[ac-platform-edge]
    end

    subgraph core [Core platform MS]
        ID[ac-ms-identity]
        RB[ac-ms-rbac]
        DV[ac-ms-devices]
    end

    subgraph domain [Domain MS]
        IS[ac-ms-issues]
        TK[ac-ms-tickets]
        GR[ac-ms-graphs]
        RA[ac-ms-remote-access]
        UL[ac-ms-url-shortener]
        BL[ac-ms-build]
        OT[ac-ms-ota]
    end

    subgraph ui [Backend UI]
        UI_I[ac-be-issues]
        UI_T[ac-be-tickets]
        UI_G[ac-be-graphs]
        UI_R[ac-be-remote-access]
        UI_A[ac-be-access]
        UI_B[ac-be-builder]
    end

    AND -->|upload API| EDGE
    AND -->|RA API| EDGE
    AND -->|graph upload| EDGE
    HUB --> EDGE
    UI_I & UI_T & UI_G & UI_R & UI_A & UI_B --> EDGE
    EDGE --> ID & IS & TK & GR & RA & UL & BL & OT & RB

    ID --> RB
    RB --> DV
    IS --> DV
    IS --> RB
    TK --> RB
    TK -.->|optional link| IS
    GR --> ID
    RA --> RB
    RA --> DV
    RA -.->|issue deep links| IS
    BL --> ID
    BL -->|git clone| GITEA[(Gitea infra)]
    OT --> BL
    OT --> AND
    OT --> IOS
    UL --> RB
```

**Dependency rules (enforce in DR/SPEC):**

| Service | Hard depends on | Soft / read depends on | Mobile / public API |
|---------|-----------------|------------------------|---------------------|
| ac-ms-identity | ac-platform-db (users schema) | ac-ms-notifications (mail) | register, login |
| ac-ms-rbac | identity (JWT/session validation) | — | — |
| ac-ms-devices | rbac (company scope) | identity | — |
| ac-ms-issues | devices, rbac | tags catalog | **upload.php** |
| ac-ms-tickets | rbac | issues (link ticket↔report) | — |
| ac-ms-graphs | identity | — | graph_upload |
| ac-ms-remote-access | rbac, devices | issues (device context URLs) | remote_access.php |
| ac-ms-url-shortener | rbac (API tokens) | — | s.f0xx.org |
| ac-ms-build | identity | gitea mirror | — |
| ac-ms-ota | build artifacts | mobile/ios SHAs | `/v0/ota/` |
| ac-be-hub | identity (session for nav) | **P2 platform-web** assets | — |

**Cross-cutting fixes vs PO draft:**

1. **Auth must be first MS** — every UI and API currently includes `bootstrap.php` → Auth.
2. **Devices before issues** — upload auto-registers device + company ([README](../examples/crash_reporter/backend/README.md) RBAC).
3. **Hub → crashes assets** — today `app_hub/index.php` loads `/crashes/assets/css/app.css`; extract **ac-platform-web** before splitting hub.
4. **Builder → same DB users** — build_console uses `androidcast_crashes.users`; cannot split S9 before S1.
5. **Short links admin** — UI in monolith, API in submodule; UI calls S8, not duplicate repo **ac-be-url-shortener**.
6. **Graphs** — already separate nginx location `/graphs/` ([apps.conf](../../examples/crash_reporter/backend/nginx/fe/apps.conf)) — good MS boundary.

**Suggested new intermediates (actors):**

| Service | Why |
|---------|-----|
| **ac-ms-identity** | Single login/register/2FA; avoids 8 copies of Auth.php |
| **ac-ms-devices** | Shared by issues, RA, graphs device keys |
| **ac-platform-edge** | One nginx config for PO’s URL map + SSO cookie |
| **ac-ms-ota** | PO multi-repo Android+iOS same version (§N) |
| **ac-ms-notifications** | Decouple SMTP from identity (task 2.x mail frozen) |
| **ac-ms-attachments** (later) | Ticket files → object store when > local disk |

──────────────────────────────────────────────────────────────────────────────
L. Public URL migration map (PO §4)
──────────────────────────────────────────────────────────────────────────────

Base prefix (discussion): keep **`/app/androidcast_project/`** for alpha compatibility, or shorten to **`/app/ac/`** later. Below uses PO’s intent under current prefix.

| Today | Target path | MS / UI | Notes |
|-------|-------------|---------|-------|
| `/crashes/?view=reports` | **`/issues/`** | B1 → S4 | “Issue tracker” / crash reports list |
| `/crashes/?view=report&id=N` | **`/issues/N`** or `/issues/report/N` | B1 | Detail |
| `/crashes/?view=tickets` | **`/tickets/`** | B2 → S5 | Tickets catalog |
| `/crashes/?view=ticket&id=N` | **`/tickets/N`** | B2 | Detail |
| `/crashes/?view=rbac` | **`/access/`** | B5 → S2 | RBAC admin |
| `/crashes/?view=remote_access` | **`/remote-access/`** | B4 → S7 | RA admin |
| `/crashes/?view=short_links` | **`/short-links/`** or hub panel | B0/B5 → S8 | API stays on s.f0xx.org |
| `/crashes/?view=home` | **`/`** hub or `/console/` | B0 | Retire crashes “home” |
| `/crashes/api/upload.php` | **`/issues/api/upload`** or `/api/v1/issues/upload` | S4 | Update `BackendEndpoints.java`, `CrashSettings.java` |
| `/crashes/api/*` (tickets) | **`/tickets/api/*`** | S5 | |
| `/graphs/` | **`/graphs/`** (keep) | B3 → S6 | Already separate vhost block |
| `/build/` | **`/build/`** (keep) | B6 → S9 | |
| `/` (hub) | **`/`** (keep) | B0 | |
| `/git/` | **`/git/`** (keep) | Gitea | Not a MS |
| `/v0/ota/` | **`/v0/ota/`** (keep) | S10 | |

**Migration mechanics:** ac-platform-edge 301 redirects old URLs ≥ 1 release; mobile app legacy URL rewrite already in `BackendEndpoints.normalizeUploadUrl()`.

**Naming note:** Today “reports” in code = **issues/crashes** in product language — align UI strings when moving to `/issues/`.

──────────────────────────────────────────────────────────────────────────────
M. ac-workspace + OTA multi-repo versioning (PO §5)
──────────────────────────────────────────────────────────────────────────────

**ac-workspace is NOT:**
- A single Gradle/Composer build root
- Required for CI (each repo has own pipeline)

**ac-workspace IS:**
- Optional manifest: “which repos at which SHA for a release train”
- Convenience for developers who want `clients/android` + `services/issues` side by side

**OTA same version, different client SHAs (Android + iOS):**

`ac-ms-ota` channel manifest example:

```json
{
  "channel": "staging",
  "version": "00.02.00.00",
  "artifacts": {
    "android": { "repo": "ac-mobile-android", "git_sha": "abc123", "apk_url": "..." },
    "ios":     { "repo": "ac-mobile-ios",     "git_sha": "def456", "ipa_url": "..." }
  }
}
```

Builder (S9) triggers per-repo builds; **S10** assembles manifest. Mobile apps read **`version`** for UX; **`git_sha`** per platform for support.

──────────────────────────────────────────────────────────────────────────────
N. Cloud & VM strategy (PO §6 — no K8s experience)
──────────────────────────────────────────────────────────────────────────────

**Recommendation: Phase 1 = VM lift-and-shift** (matches cluster0 lab, scaling SPEC §6.3, PO skill set).

| Stage | Where | Pattern |
|-------|-------|---------|
| **Now** | FE + BE Alpine | nginx + PHP-FPM + MariaDB ([INFRA.md](../INFRA.md)) |
| **Lab** | cast01–03 | GTID MariaDB, NFS config only, apps local ([cluster0 ARCHITECTURE](../../orchestration/sim/cluster0/ARCHITECTURE.md)) |
| **Cloud phase A** | 4–6 VMs (be-web, be-data, be-ops, be-build) | Same as scaling table; **docker only on build** |
| **Cloud phase B** | Managed DB (RDS-class) | Apps use DSN secret; **ac-platform-db** migrations as job |
| **Cloud phase C** (optional) | K8s / compose swarm | **Not required** — introduce when MS count > ~8 and PO wants auto-scale |

**ac-deploy deliverables for cloud:** Terraform optional; minimum **Ansible + docker-compose fragments per VM role** + env templates. Each MS = one PHP-FPM pool or one container behind edge nginx.

**Inter-service calls (PO poor on microservices):** Start with **HTTP on localhost/private VLAN** (same BE host), not service mesh. Edge nginx routes public paths; internal `127.0.0.1:900x` or docker network. OpenAPI spec in **ac-docs/openapi/** is the contract.

──────────────────────────────────────────────────────────────────────────────
O. DR readiness checklist
──────────────────────────────────────────────────────────────────────────────

- [x] Map monolith → full MS catalog (§G)
- [x] PO decisions recorded (§I)
- [x] Comparison table (§J)
- [x] Dependency graph + fixes (§K)
- [x] URL migration map (§L)
- [x] Workspace / OTA model (§M)
- [x] Cloud recommendation (§N)
- [ ] PO confirms URL prefix (`/app/androidcast_project/` vs `/app/ac/`) — **locked: full prefix**
- [ ] PO confirms **ac-ms-identity** as P3 gate — **approved**
- [x] Write `docs/DRs/20260618_repos_reorganizing.md` + PDF
- [ ] Update gitea migrate scripts for org **`ac`**
- [ ] Migration runbook P0–P7

[AI]: **Create Gitea repos from §G table in waves:** Wave 1 = P4,P5,D0,C2,S8; Wave 2 = S1,S2,S3; Wave 3 = S4,S5 + B1,B2; then edge + URL migration.
