The changelog still described unreleased work under 1.1.0, which was already published with its own notes. Those notes are restored verbatim for history, and the new work has its own 1.2.0 section that the feed publisher will turn into release notes. The release guide, infrastructure map, and mobile SSOT now carry the 1.2.0 identity, state that installer binaries are distributed through the feed and never committed, and record that the published 1.1.0 installer is unsigned and is being superseded rather than rewritten. Backlog entries cover the remaining external signing and token secrets.
224 lines
15 KiB
Markdown
224 lines
15 KiB
Markdown
# 02 — Repository & Infrastructure Map
|
|
|
|
> Surface: whole repo
|
|
> Source of truth for: layout, workspaces, build/test commands, CI/CD, Docker, deploy, scripts, resources
|
|
|
|
---
|
|
|
|
## 1. Repository layout
|
|
|
|
```
|
|
D:/workspace/D3ROVoice
|
|
├── apps/
|
|
│ ├── desktop/ Electron app (npm workspace @d3ro/desktop)
|
|
│ ├── web/ Next.js console (npm workspace @d3ro/web)
|
|
│ ├── admin/ Next.js back office (npm workspace @d3ro/admin)
|
|
│ ├── mobile-rn/ React Native product mobile app (NOT an npm workspace)
|
|
│ ├── api-server/ ASP.NET Core 10 API (D3ROVoice.Api)
|
|
│ ├── api-server.Tests/ xUnit tests for the API
|
|
│ └── admin-swagger/ Static Swagger UI + openapi.json
|
|
├── packages/ Shared TS packages (npm workspaces)
|
|
│ ├── core/ @d3ro/core — types, errors, IPC channels, crypto, utils
|
|
│ ├── ui/ @d3ro/ui — web/desktop design system (MUI + tokens)
|
|
│ ├── ui-native/ @d3ro/ui-native — React Native design system
|
|
│ ├── i18n/ @d3ro/i18n — 12 locales, provider, formatters
|
|
│ └── api-client/ @d3ro/api-client — Supabase wrapper + shared types
|
|
├── server/
|
|
│ ├── supabase/ Supabase project: config.toml, migrations/, functions/, tests/
|
|
│ └── cloudflare-worker/ Edge gateway (wrangler.toml + src/index.ts)
|
|
├── site/ Vite landing site (deployed to Cloudflare Pages + GitHub Pages)
|
|
├── resources/ icons/ (empty), sox/ (bundled Windows SoX binaries)
|
|
├── release/ Version identity SSOT + license/evidence public keys
|
|
├── scripts/ ~145 automation scripts + scripts/ci/ (31) + scripts/lib/
|
|
├── docs/ Design, phases, v2/v3 plans, deployment, map/ (this map)
|
|
├── memory/ Project status, handoffs, archive
|
|
├── tests/e2e/, test-results/ Root-level e2e + last-run artifacts
|
|
├── scratch/ Large local evidence (APKs, screenshots, DBs) — not build input
|
|
├── supabase/ Empty scaffolding (.branches/, snippets/) — real project is server/supabase
|
|
├── .github/workflows/ GitHub Actions (6)
|
|
├── .gitlab-ci.yml GitLab CI (primary desktop/mobile release pipeline)
|
|
├── .forgejo/workflows/ Forgejo Actions (site deploy to Cloudflare Pages)
|
|
├── docker-compose.yml, docker-compose.nas.yml
|
|
├── Dockerfile.admin, apps/api-server/Dockerfile, apps/admin/Dockerfile
|
|
├── turbo.json, tsconfig.json, tsconfig.base.json, pnpm-workspace.yaml
|
|
├── package.json monorepo root, npm workspaces
|
|
├── CLAUDE.md Claude-specific project rules
|
|
└── AGENTS.md Cross-agent entry: rules + map obligation (this map's anchor)
|
|
```
|
|
|
|
Note: root `package.json` declares npm workspaces `apps/desktop`, `apps/web`, `apps/admin`, `packages/*`. `pnpm-workspace.yaml` also exists (`apps/*`, `packages/*`) but npm is the active toolchain. **Mobile is intentionally outside the workspace.**
|
|
|
|
---
|
|
|
|
## 2. Toolchain & versions
|
|
|
|
| Tool | Version | Source |
|
|
|---|---|---|
|
|
| Node | 24.19.0 | `.nvmrc` |
|
|
| TypeScript | 5.7 | root `package.json` |
|
|
| .NET SDK | 10.0.300 (rollForward latestPatch) | `global.json` |
|
|
| Deno | 2.8.1 | CI (`edge-functions-quality`) |
|
|
| JDK | 17 | mobile CI |
|
|
| Electron | 33.4.11 | `apps/desktop/electron-builder.yml` |
|
|
| React Native | 0.85 | `apps/mobile-rn/package.json` |
|
|
| Turborepo | turbo.json tasks: build/typecheck/test/lint/dev | `turbo.json` |
|
|
|
|
---
|
|
|
|
## 3. Root scripts (`package.json`)
|
|
|
|
```bash
|
|
npm run dev # desktop dev (electron-vite)
|
|
npm run build # desktop production build
|
|
npm run build:admin # admin production build
|
|
npm run build:all | npm run ci # scripts/ci/build-all.mjs
|
|
npm run checksum # scripts/ci/generate-checksums.mjs
|
|
npm run version:check | version:sync
|
|
npm run release:metadata[:test]
|
|
npm run release:forgejo[:check] # canonical Forgejo publisher/feed
|
|
npm run release:tag # annotated/signed immutable release tag
|
|
npm run security:secrets[:test] # hardcoded-secret scanner
|
|
npm run test:e2e:red # content-report red e2e
|
|
npm run release:mobile:boundary[:test]
|
|
npm run release:mobile:config[:test]
|
|
npm run release:mobile:build-config:test
|
|
npm run release:play:assets[:test]
|
|
npm run typecheck # all workspaces
|
|
npm run test # all workspaces
|
|
npm run lint # eslint apps/desktop apps/web apps/admin packages
|
|
npm run format # prettier
|
|
npm run typecheck:mobile # apps/mobile-rn tsc (outside npm workspaces)
|
|
npm run lint:mobile # apps/mobile-rn eslint --max-warnings=0
|
|
npm run test:mobile # apps/mobile-rn jest
|
|
npm run verify:all # aggregate: workspaces + mobile (typecheck/lint/test)
|
|
```
|
|
|
|
Per-app commands that matter:
|
|
|
|
| App | Commands |
|
|
|---|---|
|
|
| desktop | `npm run dev --workspace=@d3ro/desktop`, `build`, `typecheck`, `test` (vitest, 1266 tests), playwright e2e |
|
|
| mobile-rn | `npm run typecheck:mobile` / `lint:mobile` / `test:mobile` (root), or `npm --prefix apps/mobile-rn run lint/typecheck/test`; android gradle builds, Maestro E2E |
|
|
| api-server | `dotnet build`, `dotnet test` (also `apps/api-server.Tests`) |
|
|
| web | `next build`, playwright e2e in `apps/web/e2e` |
|
|
| admin | `next build` (`build:admin`) |
|
|
|
|
Desktop GUI execution rule (from `CLAUDE.md` / `.agents/rules/`): run via `run-desktop.bat` or an external terminal; do not background-launch GUI from an agent subshell.
|
|
|
|
---
|
|
|
|
## 4. Shared packages
|
|
|
|
See [`03-shared-packages.md`](./03-shared-packages.md). Summary:
|
|
|
|
| Package | Provides |
|
|
|---|---|
|
|
| `@d3ro/core` | Domain types, `D3ROError`/`ErrorCode`, IPC channel SSOT, constants, `crypto-license`, `pii-redactor`, `secure-memory`, `supabase-config`, `meeting-markdown`, `markdown-to-docx` |
|
|
| `@d3ro/ui` | Theme tokens, CSS vars, MUI DS components (web/desktop) |
|
|
| `@d3ro/ui-native` | RN design system (MetalCard, PhosphorText, Led, PhysicalButton, WaveBars, …) |
|
|
| `@d3ro/i18n` | 12 locales, `I18nProvider`, `t()`, date/number/relative formatters |
|
|
| `@d3ro/api-client` | Supabase browser/server clients, meetings/history/usage/transcribe wrappers, shared types; has vitest tests |
|
|
|
|
---
|
|
|
|
## 5. CI/CD
|
|
|
|
### GitHub Actions (`.github/workflows/`)
|
|
|
|
| Workflow | Purpose |
|
|
|---|---|
|
|
| `ci.yml` | Main CI: `code-quality` (secret scan, mobile release/config/build-config self-tests, Play asset contract, lint, typecheck), `api-server-tests`, `edge-functions-quality` (Deno), `test-matrix` (win/mac/ubuntu vitest), `build-validation` (desktop win, admin ubuntu), `mobile-android` (debug/CSPRNG/E2E APKs + verifiers), `mobile-emulator-e2e` (API 35 + Maestro 2.7.0) |
|
|
| `release.yml` | On tag `v*.*.*`: preflight → `package-windows` (NSIS) → `package-macos` (DMG/ZIP arm64) → `package-android` (signed APK/AAB + evidence) → `package-admin-docker` (GHCR) → `publish-release` (checksums + GitHub Release + Forgejo canonical publish) |
|
|
| `deploy-site.yml` | On `site/**`: build Vite site, boundary self-test, deploy GitHub Pages |
|
|
| `build-mac.yml` | Manual macOS build (arm64/x64), sox + PyInstaller sidecar + electron-rebuild |
|
|
| `payple-renew.yml` | Daily cron → `payple-renew` edge function |
|
|
| `release-signing-ca.yml` | Manual Windows (Azure Trusted Signing) / macOS notarize build+sign |
|
|
|
|
### GitLab CI (`.gitlab-ci.yml`)
|
|
|
|
Stages `validate → test → build → e2e → package → publish → deploy`. Primary pipeline for desktop Windows/macOS releases (Forgejo Generic Registry is the canonical updater feed; GitLab project 1172 is a legacy mirror) and production mobile releases (`mobile-production-release`, manual/protected). Admin NAS deploy job is intentionally **disabled**.
|
|
|
|
### Forgejo Actions (`.forgejo/workflows/`)
|
|
|
|
`deploy-site.yml` / `deploy-site-windows.yml` — build `site`, write release identity, deploy to Cloudflare Pages `d3ro` (`d3ro.chanpaca.net`), verify live commit/version, app-links, legal URLs.
|
|
`release.yml` — tag-triggered Windows build (signed) + `publish-forgejo-release.mjs` to the canonical Forgejo feed/release hub.
|
|
|
|
---
|
|
|
|
## 6. Docker & deployment
|
|
|
|
| File | Purpose |
|
|
|---|---|
|
|
| `Dockerfile.admin` | 3-stage Next.js admin build (node 24.19.0-alpine, port 3001) |
|
|
| `apps/admin/Dockerfile` | Next.js standalone runner for `.next/standalone` |
|
|
| `apps/api-server/Dockerfile` | Multi-stage .NET 10 (sdk → aspnet runtime), port 5000, `VOLUME /app/data` |
|
|
| `docker-compose.yml` | Dev/self-host: `d3ro-api-server` (5050→5000, `./data` volume), `d3ro-admin` (3001), optional `ollama` (profile `ai`, 11434) |
|
|
| `docker-compose.nas.yml` | NAS: prebuilt `d3ro-voice-api:latest` + `d3ro-voice-admin:latest`; API mounts `/volume1/docker/d3ro/wwwroot/{privacy,terms,delete-account,legal.css}` read-only |
|
|
|
|
Deploy scripts: `scripts/deploy-nas.ps1`, `scripts/deploy-nas.sh`, `scripts/deploy-site-to-nas.js`, `scripts/nas-control.sh` (start/stop/restart/status/logs/backup/update).
|
|
|
|
Public endpoints (production): `https://d3ro.chanpaca.net` (portal/API), `https://admin.chanpaca.net` (admin CRM). Edge: `server/cloudflare-worker` proxying to the NAS origin, plus a **Cron Trigger** (`* * * * *`) that drains the Supabase push outbox via `send-push?mode=drain` (`src/push-drain.ts`; needs `SUPABASE_URL` var + `SUPABASE_SERVICE_ROLE_KEY` secret). Tunnel: Cloudflare Tunnel `kd-nas`.
|
|
|
|
---
|
|
|
|
## 7. `server/supabase` (backend)
|
|
|
|
- `config.toml` — project `d3ro-voice`, ports 55321-55324, DB major 17, auth redirects (localhost, `d3ro.chanpaca.net`, `d3ro-voice://auth-callback`), providers Google/GitHub/Apple.
|
|
- `migrations/` — **63 SQL migrations** (schema, RLS, auth triggers, storage, team invites, knowledge/pgvector, push outbox, Payple/Stripe billing, admin roles, mobile platform/monetization, atomic command reorder, device revocation, content reporting, audit log, meeting documents, STT quota reservations, ad reward replay protection, team activity feed).
|
|
- `functions/` — **~27 Deno Edge Functions** (`stt-proxy`, `llm-proxy`, `content-report`, `generate-meeting-document`, `embed-chunks`, `search-knowledge`, `realtime-token`, `team-invite`, `team-accept`, `send-push`, `account-delete`, `admin-users`, `admin-subscriptions`, `admin-payments`, `admin-audit-log`, billing `billing-catalog`/`stripe-checkout`/`stripe-portal`/`stripe-webhook`/`payple-checkout`/`payple-manage`/`payple-renew`/`payple-webhook`, `iap-verify`, `admob-ssv`, `google-play-rtdn`). Shared contracts in `functions/_shared/` — push transports now include `webpush.ts` (VAPID + RFC 8291) and `apns.ts` (.p8 token) alongside FCM. CI (`edge-functions-quality`) runs `deno check` + `deno test` and also the Cloudflare worker drain test.
|
|
- `tests/` — integration/E2E for content report, mobile platform/recording/reward-race, payments, mobile release preflight, push, team push security, STT quota.
|
|
|
|
Full detail: [`09-supabase-backend.md`](./09-supabase-backend.md).
|
|
|
|
---
|
|
|
|
## 8. `scripts/` groups
|
|
|
|
- **CI (`scripts/ci/`, 33 files):** build/version/release (`build-all`, `sync-version`, `generate-checksums`, `verify-release-metadata`, `create-release-tag`, `extract-release-notes`), security (`check-no-hardcoded-secrets`), mobile release gates (`verify-mobile-release-boundary/-config/-build-config`, `verify-android-artifact/-app-links`, `verify-play-store-assets`, `prepare-whisper-model`, `create-mobile-release-evidence`, `prepare-mobile-release-publication`, emulator/CSPRNG gates), keys (`create-desktop-license-keypair`, `create-release-evidence-key`, etc.), publish (`publish-forgejo-release` canonical, `publish-gitlab-release` mirror; legacy `sync-and-publish-forgejo-release`, `upload-asset-to-forgejo-release`), env/tooling (`bootstrap-linux-toolchain.sh`, `audit-nas-stt-config.ps1`, mobile local E2E scripts).
|
|
- **Deploy/release:** `deploy-nas.ps1/.sh`, `deploy-site-to-nas.js`, `nas-control.sh`, `publish-gh.ps1`, `gen-keystore.js`.
|
|
- **GCP/Google OAuth automation + inspection (~70 `*.mjs`):** `auto-configure-oauth`, `automate-google-oauth`, `setup-consent`, `create-*-client`, `check-*`, `inspect-*` — mostly one-off/browser-driven console automation.
|
|
- **AdMob console automation:** `admob-probe.mjs` (read-only login/app/ad-unit probe), `admob-login.mjs` + `run-admob-login.bat` (one interactive headful Chrome login into a persistent profile), `admob-automate.mjs` (dry-run by default; `--apply` creates/verifies banner+rewarded units and reports Play-store link). Uses `playwright` with `channel: 'chrome'` and the gitignored `.chrome-playwright-profile`.
|
|
- **E2E / verification:** `e2e-desktop-*.js`, `real-app-multi-tab-e2e.js`, `test-and-capture-all-10-ad-services.js`, `verify-live-production-d3ro.js`.
|
|
- **Screenshots/captures:** `capture-*.js`.
|
|
- **Forgejo ops:** `check-forgejo-actions-runs.js`, `capture-forgejo-*.js`.
|
|
|
|
> `scripts/` is large and partially scratch. Prefer `scripts/ci/*` for anything release-gated, and `server/supabase/tests` for backend integration.
|
|
|
|
---
|
|
|
|
## 9. Release & versioning SSOT
|
|
|
|
| File | Purpose |
|
|
|---|---|
|
|
| `release/product-version.json` | version `1.2.0`, `androidVersionCode`/`iosBuildNumber` `1020001`, releaseDate, desktop license keyId |
|
|
| `release/android-release-identity.json` | package `com.d3ro.voice`, Play app ID, app-signing SHA-256, upload cert SHA-256, evidence keyId, AdMob unit IDs |
|
|
| `release/desktop-license-public.pem` | Ed25519 public key for desktop offline licenses |
|
|
| `release/mobile-release-evidence-public.pem` | Ed25519 public key for mobile release evidence |
|
|
| `apps/desktop/electron-builder.yml` | appId `com.d3ro.voice`, NSIS x64 (forced code signing), macOS DMG/ZIP arm64, generic Forgejo publish feed, asarUnpack native modules, extraResources (icons, sounds, sox, ollama) |
|
|
| `apps/desktop/src/main/update-feed.ts` | Auto-update feed SSOT (canonical Forgejo + legacy GitLab mirror, channels) |
|
|
| `release/update-policy.json` | Update policy SSOT (channels, minimum supported version, forced update, delta/full, staged rollout, kill switch) |
|
|
| `apps/desktop/src/main/update-policy.ts` | Policy parsing/decision logic |
|
|
| `scripts/ci/publish-forgejo-release.mjs` | Canonical Forgejo registry + Release + feed publisher |
|
|
|
|
Version sync is enforced by `scripts/ci/sync-version.mjs` and `verify-release-metadata.mjs`; `npm run version:check` should be clean.
|
|
|
|
---
|
|
|
|
## 10. Resources & tests
|
|
|
|
- `resources/sox/` — bundled Windows SoX (`sox.exe` + DLLs) for audio capture.
|
|
- `resources/icons/` — empty; electron-builder falls back to `build/icon.ico|png`.
|
|
- Desktop tests: `apps/desktop/tests/` (vitest unit + playwright e2e), `apps/desktop/test-results/`.
|
|
- Mobile tests: `apps/mobile-rn/__tests__/` (57 suites / 353 tests per mobile SSOT), `.maestro/` + `.maestro-output/` E2E evidence. Note: a full parallel Jest run can hit the 5s render timeout on slow machines; re-run the failing spec in isolation before treating it as a regression.
|
|
- Web tests: `apps/web/e2e/` (playwright).
|
|
- API tests: `apps/api-server.Tests/` (xUnit).
|
|
- Root: `tests/e2e/`, `test-results/.last-run.json`.
|
|
|
|
---
|
|
|
|
## 11. Known infrastructure gaps
|
|
|
|
See [`11-gap-backlog.md`](./11-gap-backlog.md) for the maintained list (`INFRA-*`). Headlines:
|
|
- `apps/mobile-rn` is not an npm workspace member; use `typecheck:mobile`/`lint:mobile`/`test:mobile` or `verify:all`.
|
|
- Admin NAS deploy job disabled in GitLab CI; admin ships via GitHub/GHCR + manual NAS compose.
|
|
- Two identity systems (.NET JWT/SQLite vs Supabase); a canonical resolver now exists in `@d3ro/core/entitlement` but web/mobile/.NET adoption is incremental (`11` GAP-ID-02).
|