docs: record the 1.1.0 release and add the infrastructure map
Some checks failed
deploy-site / deploy (push) Failing after 40s
Some checks failed
deploy-site / deploy (push) Failing after 40s
Release notes for 1.1.0 were split between an Unreleased section and the version section, so the published notes would have omitted the update-feed and desktop changes. Everything shipping in this version now sits under one `## [1.1.0]` heading. `docs/map/` becomes the entry point for what infrastructure exists per platform and how far each feature is developed, with a documented update protocol so feature work and this map do not drift apart again. The release guide now states that installer binaries live in the update feed rather than the repository.
This commit is contained in:
parent
c2db1b2176
commit
c3ddd36c6f
29 changed files with 3207 additions and 23 deletions
77
docs/map/00-index.md
Normal file
77
docs/map/00-index.md
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# D3RO Voice — Feature & Infrastructure Map (Index)
|
||||
|
||||
> Status: ACTIVE
|
||||
> Last full audit: 2026-09-13
|
||||
> Scope: entire monorepo `D:/workspace/D3ROVoice` at product version `1.1.0`
|
||||
> Purpose: let any agent (or human) answer two questions in under a minute:
|
||||
> 1. **What infrastructure exists?** (build, CI, services, APIs, data, packages, deploy)
|
||||
> 2. **How far is each feature developed?** (per surface, with file anchors and status)
|
||||
|
||||
This is the entry point. Read the index, then open only the sub-document you need. Do not read all files every time.
|
||||
|
||||
---
|
||||
|
||||
## 1. How to use this map
|
||||
|
||||
| You need to know… | Open |
|
||||
|---|---|
|
||||
| The product, its IA, platforms, identity/data model | [`01-system-overview.md`](./01-system-overview.md) |
|
||||
| Repo layout, build, CI/CD, Docker, deploy, scripts, docs | [`02-infrastructure.md`](./02-infrastructure.md) |
|
||||
| Shared packages (`@d3ro/core`, `ui`, `ui-native`, `i18n`, `api-client`) | [`03-shared-packages.md`](./03-shared-packages.md) |
|
||||
| Desktop (Electron) services, IPC, pages, popups, status | [`04-desktop-app.md`](./04-desktop-app.md) |
|
||||
| Web (Next.js) routes, components, clients, status | [`05-web-app.md`](./05-web-app.md) |
|
||||
| Mobile (React Native) screens, features, tabs, status | [`06-mobile-app.md`](./06-mobile-app.md) |
|
||||
| .NET cloud API: controllers, services, tables, auth | [`07-api-server.md`](./07-api-server.md) |
|
||||
| Admin back office (Next.js) routes, guards, status | [`08-admin-console.md`](./08-admin-console.md) |
|
||||
| Supabase migrations, Edge Functions, Cloudflare worker | [`09-supabase-backend.md`](./09-supabase-backend.md) |
|
||||
| **The feature map** — every feature, per platform, with status | [`10-feature-catalog.md`](./10-feature-catalog.md) |
|
||||
| **Known gaps / under-developed / backlog** | [`11-gap-backlog.md`](./11-gap-backlog.md) |
|
||||
| **Mandatory rules for keeping this map current** | [`12-update-protocol.md`](./12-update-protocol.md) |
|
||||
|
||||
An agent starting a task should:
|
||||
1. Read the relevant surface doc (04–09) for infrastructure.
|
||||
2. Read `10-feature-catalog.md` for the feature's current status and platform coverage.
|
||||
3. Read `11-gap-backlog.md` to see if the feature is already tracked as backlog.
|
||||
4. After finishing, follow `12-update-protocol.md` before the work is considered done.
|
||||
|
||||
---
|
||||
|
||||
## 2. Status legend
|
||||
|
||||
Feature rows in `10-feature-catalog.md` use this scale:
|
||||
|
||||
| Symbol | Meaning |
|
||||
|---|---|
|
||||
| `[x]` | Implemented and verified on this platform (code + tests / evidence exist in-repo). |
|
||||
| `[~]` | Implemented but partial, unverified, or blocked on an external/console gate. |
|
||||
| `[ ]` | Planned or absent on this platform. |
|
||||
| `[!]` | Blocked on something outside the repo (external console, secret, physical device, store review). |
|
||||
| `[-]` | Not applicable to this platform (with a one-line reason). |
|
||||
|
||||
Status is **per platform**. A feature can be `[x]` on desktop, `[~]` on mobile, `[ ]` on web.
|
||||
|
||||
---
|
||||
|
||||
## 3. One-paragraph system summary
|
||||
|
||||
D3RO Voice is a multi-platform AI voice assistant (transcription, LLM command execution, meeting intelligence, RAG, voice conversation) sold as Free / Pro / Pro+ / Team / Enterprise tiers. It ships as an **Electron desktop app** (local-first: bundled SoX, faster-whisper sidecar, Ollama, local SQLite), a **React Native mobile app** (`apps/mobile-rn`, cloud-first: Supabase auth + Edge Functions + on-device Whisper fallback), a **Next.js web console**, a **Next.js admin back office**, and a **.NET cloud API** (AI proxy + back office backend). The shared backend is **Supabase** (Postgres + RLS + Auth + Storage + ~27 Deno Edge Functions), deployed to a Synology NAS via Docker with a Cloudflare edge worker and tunnel. Shared code lives in `packages/*`. Distribution: Windows NSIS + macOS DMG (GitLab/Forgejo feed + electron-updater), Android APK/AAB via Google Play.
|
||||
|
||||
---
|
||||
|
||||
## 4. Reading order for a brand-new agent
|
||||
|
||||
1. `AGENTS.md` (root) — operating rules + the obligation to update this map.
|
||||
2. `docs/map/01-system-overview.md` — the big picture and IA.
|
||||
3. The surface doc for your task (04–09).
|
||||
4. `docs/map/10-feature-catalog.md` — find the feature and its status.
|
||||
5. `docs/map/11-gap-backlog.md` — check for existing backlog notes.
|
||||
|
||||
Deeper design history (not required to start): `docs/design/*`, `docs/phases/*`, `docs/v2/*`, `docs/v3/*`, `memory/*`, `CHANGELOG.md`. The mobile SSOT is `docs/v3/MOBILE_APP_COMPLETION_SSOT.md`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Maintenance
|
||||
|
||||
This map must change whenever a feature is added, removed, changed, or deferred.
|
||||
See [`12-update-protocol.md`](./12-update-protocol.md) for the exact checklist and
|
||||
`AGENTS.md` for the agent obligation.
|
||||
181
docs/map/01-system-overview.md
Normal file
181
docs/map/01-system-overview.md
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
# 01 — System Overview & Information Architecture
|
||||
|
||||
> Surface: whole product
|
||||
> Source of truth for: vision, platforms, IA, identity/data model, AI pipeline, tiers
|
||||
|
||||
---
|
||||
|
||||
## 1. Product in one line
|
||||
|
||||
A multi-platform AI voice assistant: press/hold or tap to speak, get a transcript, optionally run it through an LLM (cleanup, translate, summarize, execute a command), and keep the result in a searchable history that syncs across desktop, web, and mobile.
|
||||
|
||||
---
|
||||
|
||||
## 2. Surfaces (apps) and their roles
|
||||
|
||||
| Surface | Path | Stack | Runtime model | Role |
|
||||
|---|---|---|---|---|
|
||||
| Desktop | `apps/desktop` | Electron 33 + React 19 + MUI 7 + Vite | **Local-first** (SoX, faster-whisper sidecar, Ollama, SQLite) with optional cloud sync | The flagship: global hotkey dictation, text insertion into other apps, meetings, captions, RAG, voice conversation, OS actions |
|
||||
| Web | `apps/web` | Next.js 15 App Router + Supabase | **Cloud** | Browser console: record/STT, history, commands, meetings, knowledge, teams, chat, billing |
|
||||
| Mobile | `apps/mobile-rn` | React Native 0.85 + React 19 (CLI, not Expo) | **Cloud-first** (Supabase + Edge Functions), on-device Whisper fallback | Product mobile app: recording/import, history, meetings, memos, templates, teams, Talk, admin, data portability, IAP + ads |
|
||||
| API server | `apps/api-server` | ASP.NET Core 10 + EF Core + SQLite | Cloud (self-hosted/NAS) | LLM/STT proxy and admin back-office backend for the .NET identity side |
|
||||
| Admin console | `apps/admin` | Next.js 16 + MUI | Cloud | Back office: users, subscriptions, models/STT providers, usage, audit log, releases, ads |
|
||||
| Landing site | `site/` | Vite 6 + React 19 + Tailwind | Static | Marketing/download/legal pages, deployed to Cloudflare Pages + GitHub Pages |
|
||||
| Edge gateway | `server/cloudflare-worker` | Cloudflare Worker (TS) | Edge | CORS + proxy to the NAS-hosted API origin |
|
||||
| Backend data/functions | `server/supabase` | Postgres + Deno Edge Functions | Cloud | Canonical product data, auth, RLS, storage, AI proxies, billing, delivery |
|
||||
|
||||
---
|
||||
|
||||
## 3. Information architecture (feature domains)
|
||||
|
||||
The product IA is stable across surfaces; each surface implements a subset.
|
||||
|
||||
```
|
||||
D3RO Voice
|
||||
├── Capture & Transcribe
|
||||
│ ├── Dictation (hold/release, push-to-talk)
|
||||
│ ├── Hands-free (toggle)
|
||||
│ ├── File transcription (audio/video)
|
||||
│ ├── Live captions (system audio)
|
||||
│ └── Multiple STT engines (local Whisper, cloud providers)
|
||||
├── AI Processing
|
||||
│ ├── Local LLM (Ollama) / Cloud LLM (Claude, OpenAI)
|
||||
│ ├── Auto Polish / cleanup / translate / summarize
|
||||
│ ├── Custom instructions (user commands)
|
||||
│ ├── Voice commands (keyword → command)
|
||||
│ └── LLM Chains (multi-step pipelines)
|
||||
├── Memory & Knowledge
|
||||
│ ├── History (search, favorites, export)
|
||||
│ ├── Dictionary (custom vocabulary)
|
||||
│ ├── Memos (tags over history)
|
||||
│ ├── Knowledge base (local RAG / cloud RAG)
|
||||
│ └── Voice actions (OS automation)
|
||||
├── Meetings
|
||||
│ ├── Meeting recording + live transcript
|
||||
│ ├── Timestamped memos
|
||||
│ ├── AI summary + speaker diarization
|
||||
│ ├── Document generation (minutes/report/idea-note/mindmap)
|
||||
│ └── Export (PDF/DOCX/TXT/Markdown)
|
||||
├── Conversation
|
||||
│ ├── Local duplex conversation (STT→LLM→TTS)
|
||||
│ └── Realtime conversation (OpenAI gpt-realtime, Premium)
|
||||
├── Accounts & Sync
|
||||
│ ├── Supabase auth (email + Google/GitHub/Apple OAuth)
|
||||
│ ├── Cloud sync (per-user DB/rows)
|
||||
│ ├── Devices (registration, revocation)
|
||||
│ ├── Teams (members, invites, roles)
|
||||
│ └── Data portability (export/import, account delete)
|
||||
├── Monetization
|
||||
│ ├── Tiers: Free / Pro / Pro+ / Team / Enterprise
|
||||
│ ├── Desktop licenses (Ed25519, offline)
|
||||
│ ├── Web billing (Stripe + Payple)
|
||||
│ ├── Mobile IAP (Google Play / App Store)
|
||||
│ └── Free-tier ads (AdMob rewarded + banner, mediation roster)
|
||||
├── Platform Shell
|
||||
│ ├── Settings / preferences / themes (6 themes)
|
||||
│ ├── Onboarding
|
||||
│ ├── Notifications / push
|
||||
│ ├── Support & content reporting
|
||||
│ └── Admin & audit
|
||||
```
|
||||
|
||||
Legacy/other: voice keyword shortcuts, screen/context capture, auto-launch, system tray.
|
||||
|
||||
---
|
||||
|
||||
## 4. Identity & data model (multi-source, converging)
|
||||
|
||||
There are **three** identity/data systems in the repo. This is a known architectural tension (see `11-gap-backlog.md` G-01).
|
||||
|
||||
| System | Where | Stores | Status |
|
||||
|---|---|---|---|
|
||||
| Supabase Auth + Postgres | `server/supabase` | Canonical product users, profiles, subscriptions, history, meetings, teams, knowledge, push, billing, ads | **Canonical SSOT** for web + mobile |
|
||||
| .NET API server | `apps/api-server` | Its own SQLite `Users` (JWT, roles), model/STT endpoints, usage/error logs, admin audit | Back-office + AI proxy; legacy SHA-256 users force-disabled at startup |
|
||||
| Desktop local license | `apps/desktop` | Ed25519-signed offline license key, local SQLite DB per user (`_local` for anonymous) | Local-first tier gating + optional Supabase cloud sync |
|
||||
|
||||
Data flow:
|
||||
- Desktop: local SQLite (per-user file) ↔ optional Supabase sync (history/dictionary/meetings).
|
||||
- Web/Mobile: Supabase directly (tables + RLS) and via Edge Functions.
|
||||
- Admin: Next.js server routes → Supabase service role and/or .NET `/api/admin/*`.
|
||||
|
||||
---
|
||||
|
||||
## 5. AI pipeline
|
||||
|
||||
**Local path (desktop):** mic → SoX/native capture (PCM16 16kHz mono) → faster-whisper Python sidecar → optional Ollama LLM → SQLite history → clipboard/text insertion into the active app.
|
||||
|
||||
**Cloud path (web/mobile/desktop online):**
|
||||
- STT → Supabase Edge Function `stt-proxy` (quota reservation, provider fallback) or .NET `SttProxyService` (internal gateway token only).
|
||||
- LLM → Supabase `llm-proxy` / `realtime-token` (Claude/OpenAI) or .NET `LlmProxyService`.
|
||||
- Meetings/documents → `generate-meeting-document`, `embed-chunks`, `search-knowledge`.
|
||||
|
||||
**Realtime voice (Premium):** OpenAI `gpt-realtime-2.1` via ephemeral token from `realtime-token`, WebRTC in the desktop renderer with local-pipeline fallback.
|
||||
|
||||
STT providers supported by the desktop dispatcher (`apps/desktop/src/main/services/stt`): local Whisper, OpenAI, Groq, Deepgram, AssemblyAI, Google, Custom (OpenAI-compatible), and D3RO Cloud.
|
||||
|
||||
---
|
||||
|
||||
## 6. Monetization tiers
|
||||
|
||||
| Tier | Notes |
|
||||
|---|---|
|
||||
| Free | Quotas on STT/LLM; free-tier ads (desktop/mobile). |
|
||||
| Pro / Pro+ | Paid subscriptions. Desktop: offline Ed25519 license. Web: Stripe/Payple. Mobile: Google Play Billing. |
|
||||
| Team / Enterprise | Teams, shared meetings, admin roles. |
|
||||
|
||||
Desktop license verification is Ed25519 (public key in `release/desktop-license-public.pem`); the private key was rotated out of the repo. Mobile release evidence uses a separate Ed25519 keypair.
|
||||
|
||||
---
|
||||
|
||||
## 7. Platform architecture diagram (text)
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────┐
|
||||
│ Supabase (SSOT) │
|
||||
│ Postgres+RLS · Auth · Storage · Realtime │
|
||||
│ ~27 Deno Edge Functions │
|
||||
└───────────────┬──────────────────────────┘
|
||||
┌──────────────┬───────┴────────┬───────────────┐
|
||||
│ │ │ │
|
||||
apps/web apps/mobile-rn apps/desktop apps/admin
|
||||
(Next.js) (React Native) (Electron) (Next.js)
|
||||
│ │ │ │
|
||||
└──────────────┴────────────────┘ │
|
||||
│ │
|
||||
┌───────┴────────┐ ┌─────────┴─────────┐
|
||||
│ Cloudflare │ │ apps/api-server │
|
||||
│ Worker (edge) │──────────────▶ .NET 10 + SQLite │
|
||||
└───────┬────────┘ │ + admin audit │
|
||||
│ └───────────────────┘
|
||||
Cloudflare Tunnel
|
||||
│
|
||||
┌───────┴────────┐
|
||||
│ D3RO NAS │ docker-compose.nas.yml
|
||||
│ API + Admin │ d3ro.chanpaca.net / admin.chanpaca.net
|
||||
└────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Cross-cutting concerns
|
||||
|
||||
| Concern | Implementation |
|
||||
|---|---|
|
||||
| Design system | `packages/ui` (web/desktop, MUI + tokens), `packages/ui-native` (mobile). Theme SSOT `theme.ts` (`d3roPalette`/`d3roTypo`/`d3roShadow`/`d3roRadius`). 6 themes. |
|
||||
| i18n | `packages/i18n`, 12 locales, `ko` master, `t()` + type-safe keys. |
|
||||
| IPC | `packages/core/src/ipc-channels.ts` is the channel SSOT; desktop preload exposes `window.electronAPI` (33 namespaces). |
|
||||
| Errors | `D3ROError` + `ErrorCode`, `IPCResult<T>` envelope. |
|
||||
| Crypto | Ed25519 license signing (`packages/core/src/utils/crypto-license`), HMAC admin sessions, PKCE on mobile. |
|
||||
| Observability | `LoggerService` (electron-log) on desktop; `ServerErrorLog`/`ApiUsageLog`/`SttUsageLog` in .NET; admin audit log in Supabase. |
|
||||
| Security posture | Fail-closed defaults: STT/LLM never return synthetic success; admin panels show explicit "unavailable" rather than sample data; secret scanning in CI. |
|
||||
|
||||
---
|
||||
|
||||
## 9. Related deep documents
|
||||
|
||||
- Desktop architecture: `docs/design/00-master-architecture.md` … `09-history-popup.md`
|
||||
- Build-out history: `docs/phases/phase-1.md` … `phase-15.5-speaker-diarization.md`
|
||||
- Multi-platform plan: `docs/v2/00-v2-master-plan.md`
|
||||
- Mobile SSOT (authoritative checklist): `docs/v3/MOBILE_APP_COMPLETION_SSOT.md`
|
||||
- Monetization: `docs/monetization-plan.md`
|
||||
- Release process: `docs/deployment/release-guide.md`, `docs/deployment/nas-deployment-guide.md`
|
||||
224
docs/map/02-infrastructure.md
Normal file
224
docs/map/02-infrastructure.md
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
# 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.1.0`, `androidVersionCode`/`iosBuildNumber` `1010001`, 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).
|
||||
108
docs/map/03-shared-packages.md
Normal file
108
docs/map/03-shared-packages.md
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# 03 — Shared Packages Map
|
||||
|
||||
> Surface: `packages/*` (npm workspaces)
|
||||
> Source of truth for: shared domain logic, design systems, i18n, API client
|
||||
|
||||
All packages are private, version `1.1.0`, source-only (`main`/`types` point at `src`).
|
||||
|
||||
---
|
||||
|
||||
## 1. `@d3ro/core` — business logic SSOT (`packages/core`)
|
||||
|
||||
The canonical place for types and cross-surface logic. Both desktop and web/mobile depend on it.
|
||||
|
||||
| Area | Exports | Notes |
|
||||
|---|---|---|
|
||||
| Types | `./types` | Domain types shared across surfaces |
|
||||
| Errors | `./errors` | `D3ROError`, `ErrorCode` |
|
||||
| IPC channels | `./ipc-channels` | `IPC_CHANNELS` object + `IPCChannel` union. **SSOT** for every desktop IPC channel (VOICE, AUDIO, STT, TTS, LLM, HOTKEY, CONFIG, HISTORY, DICTIONARY, WINDOW, SYSTEM, STATS, MEMO, VOICE_COMMAND, CONTEXT, CHAIN, CAPTION, FILE_TRANSCRIPTION, MEETING_SUMMARY, DICTATION_TEMPLATE, VOICE_CONVERSATION, RAG, VOICE_ACTION, MEETING_MODE, MEETING_DOC_TEMPLATE, MEETING_CHAT, LICENSE, CLOUD_SYNC, INSTRUCTION, SYSTEM_AUDIO, POPUP_RESULT, POPUP_HISTORY, POPUP_COMMAND, POPUP_CAPTION, VOICE_PARTIAL, CLIPBOARD, APP, ONLINE_AUTH, ADS, SUPPORT, PAYMENT) |
|
||||
| Constants | `./constants` | Shared constants |
|
||||
| Crypto license | `./utils/crypto-license` | Ed25519 license sign/verify (used by admin issuer + desktop verifier) |
|
||||
| PII | `pii-redactor`, `secure-memory` | Redaction + secure memory helpers |
|
||||
| Supabase config | `supabase-config` | Shared Supabase config shape |
|
||||
| Entitlement | `./entitlement` | `EntitlementTier`, `AdminRole`, `EntitlementSnapshot`, `resolveEntitlement`, `normalizeEntitlementTier`/`normalizeAdminRole` — canonical tier/role contract across Supabase, desktop license, and .NET |
|
||||
| Doc utils | `./utils/meeting-markdown`, `./utils/markdown-to-docx` | Meeting Markdown export + DOCX generation (dep: `docx`) |
|
||||
|
||||
**When to change:** new cross-surface type, new error code, new IPC channel, license format. Add here first, then consume.
|
||||
|
||||
---
|
||||
|
||||
## 2. `@d3ro/ui` — web/desktop design system (`packages/ui`)
|
||||
|
||||
| Export | Contents |
|
||||
|---|---|
|
||||
| `.` | Barrel |
|
||||
| `./theme` | `theme.ts` — `d3roPalette`, `d3roTypo` (13 steps), `d3roShadow` (10), `d3roRadius` (7); 6 themes (dark/Midnight, light, nord, solarized, catppuccin, dracula) + build helpers |
|
||||
| `./theme-vars` | CSS variable map for popups/vanilla surfaces |
|
||||
| `./components/ds` | MUI/Emotion DS components: CrtDisplay, InstrumentPanel, Led, PhysicalButton, MetalCard, PhosphorText (13 variants), MetalDial, ScreenPanel, ButtonGroup, TiltCard, GradientWave, StatRing |
|
||||
|
||||
Peers: React 19, MUI 7, Emotion 11. Depends on `@d3ro/core`.
|
||||
|
||||
**Theme SSOT rule:** never hardcode hex outside `theme.ts`; use `d3roPalette`/`d3roShadow` tokens. `accent.amber` was removed in Wave 2; use `accent.main`.
|
||||
|
||||
---
|
||||
|
||||
## 3. `@d3ro/ui-native` — React Native design system (`packages/ui-native`)
|
||||
|
||||
| Provides |
|
||||
|---|
|
||||
| `NativeThemeProvider` / `useNativePalette`, native palette/typo/radius/fonts |
|
||||
| Components: `MetalCard`, `PhosphorText`, `Led`, `PhysicalButton`, `ScreenPanel`, `WaveBars`, `AppStatusBar`, `Header`, `FilterChip` |
|
||||
|
||||
Peers: `react`, `react-native`. Consumed by `apps/mobile-rn` via file: workspace dependencies.
|
||||
|
||||
---
|
||||
|
||||
## 4. `@d3ro/i18n` — internationalization (`packages/i18n`)
|
||||
|
||||
| Provides | Notes |
|
||||
|---|---|
|
||||
| 12 locales | `ko` (master), `en`, `ja`, `zh`, `zh-TW`, `es`, `fr`, `de`, `pt`, `ru`, `vi`, `th` in `src/locales/` |
|
||||
| Type-safe keys | `TranslationKey` derived from `ko.json` |
|
||||
| React context | `I18nProvider`, `useI18n`, `TFunction` |
|
||||
| Fallback chain | locale → `en` → `ko` → key |
|
||||
| Formatters | `formatDate`, `formatNumber`, `formatRelativeDate`, `formatTime` via `Intl` |
|
||||
| Storage injection | `I18nStorage` adapter (localStorage on web, AsyncStorage on mobile) |
|
||||
|
||||
Electron-independent. Rule: no hardcoded Korean/English strings in UI; use `t()`.
|
||||
|
||||
---
|
||||
|
||||
## 5. `@d3ro/api-client` — Supabase wrapper (`packages/api-client`)
|
||||
|
||||
| Export | Purpose |
|
||||
|---|---|
|
||||
| `client` | Base Supabase client factory |
|
||||
| `auth` | Auth helpers |
|
||||
| `meetings` | Meeting queries |
|
||||
| `history` | History queries |
|
||||
| `usage` | Usage queries |
|
||||
| `transcribe` | STT calls |
|
||||
| `supabase-browser` | Browser client (`getSupabaseBrowserClient`, `isSupabaseConfigured`) |
|
||||
| `supabase-server` | Server client (`createSupabaseServerClient`) |
|
||||
| `types` | Shared DB/domain types — **canonical; do not redefine table types per app** |
|
||||
|
||||
Deps: `@d3ro/core`, `@supabase/supabase-js`; optional peer `@supabase/ssr`. Tests: `__tests__/` (client, transcribe, types) via vitest.
|
||||
|
||||
Consumed by `apps/web`, `apps/admin` (via re-exports), `apps/mobile-rn`, and desktop cloud paths.
|
||||
|
||||
---
|
||||
|
||||
## 6. Dependency direction
|
||||
|
||||
```
|
||||
@d3ro/i18n (standalone)
|
||||
@d3ro/ui → @d3ro/core
|
||||
@d3ro/ui-native(standalone, peers react-native)
|
||||
@d3ro/api-client → @d3ro/core
|
||||
@d3ro/core (standalone)
|
||||
```
|
||||
|
||||
Apps depend on packages, never the reverse. Shared package changes ripple to all consumers (see `docs/REFACTOR_POLICY.md`).
|
||||
|
||||
---
|
||||
|
||||
## 7. Package-level gaps
|
||||
|
||||
- `apps/mobile-rn` is not an npm workspace member, so root `typecheck`/`test` skip it; use `typecheck:mobile`/`lint:mobile`/`test:mobile` from the repo root.
|
||||
- No versioned publishing of packages (private, source-only); all consumers are in-repo.
|
||||
208
docs/map/04-desktop-app.md
Normal file
208
docs/map/04-desktop-app.md
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
# 04 — Desktop App (Electron) Map
|
||||
|
||||
> Surface: `apps/desktop`
|
||||
> Stack: Electron 33 + React 19 + MUI 7 + Vite (electron-vite) + better-sqlite3/drizzle + uiohook-napi + nut-js
|
||||
> Source root: `apps/desktop/src` (`main/`, `preload/`, `renderer/`)
|
||||
|
||||
---
|
||||
|
||||
## 1. Process architecture
|
||||
|
||||
| Layer | Path | Contents |
|
||||
|---|---|---|
|
||||
| Main | `src/main/` | Services, IPC handlers, windows, bootstrap/lifecycle, DB |
|
||||
| Preload | `src/preload/` | `index.ts` exposes `window.electronAPI`; `popup.ts` exposes `window.popupAPI` |
|
||||
| Renderer | `src/renderer/` | React app: `AppLayout` + 7 pages + modals + 5 vanilla popups |
|
||||
|
||||
**Main entry** `src/main/index.ts`: sets app name/AppUserModelId, disables GPU acceleration, EPIPE/uncaught handlers, registers `d3ro-voice://` deep-link protocol (Supabase OAuth implicit + PKCE), single-instance lock, then `bootstrap()` + `setupLifecycle()`.
|
||||
|
||||
**Bootstrap** `src/main/bootstrap.ts`: ordered `BootstrapStep[]` — logger, config, **database (critical)**, license, create-windows (critical), tray, **ipc-handlers (critical)**, custom-instructions, voice-commands, sound-effects, auto-launch, popup-preload, hotkey, voice-mode, llm-polling, meeting-summary-wiring, meeting-mode, cloud-sync, auto-update. Wires VoiceMode events to sound + history persistence.
|
||||
|
||||
---
|
||||
|
||||
## 2. Main services (`src/main/services/`)
|
||||
|
||||
Singleton + `EventEmitter` pattern (`getXService()` accessors).
|
||||
|
||||
### Core voice pipeline
|
||||
| Service | Purpose |
|
||||
|---|---|
|
||||
| `VoiceModeService` | Orchestrator: 9-state `RecognitionState` + 4-state `AudioState`, dual-condition flush, action queue. Events: session-started/completed/cancelled, transcription-update, audio-level, recognition/audio-state-changed, premium-llm-fallback, error |
|
||||
| `AudioCaptureService` | Mic PCM16 16kHz mono (SoX on Windows, node-record-lpcm16 elsewhere). Events: audio-data, audio-level, device-changed, started, stopped, error |
|
||||
| `LocalSTTService` | faster-whisper Python sidecar manager (state machine, dual-flush, model download/cancel) |
|
||||
| `HotkeyService` | uiohook-napi global hooking (dictation/hands-free/command/caption). Events: hotkey-pressed/released, double-press, error |
|
||||
| `TextInsertService` | Clipboard save→set→Ctrl+V→restore via nut-js |
|
||||
| `SoundEffectService` | Preloaded WAV feedback (start/stop/error/cancel/chime) |
|
||||
|
||||
### STT engine layer (`services/stt/`)
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `STTManager` | Dispatcher across local + 6 cloud providers, auto-fallback (events provider-changed, config-changed, fallback-to-local) |
|
||||
| `types.ts` | `ISTTDriver` contract |
|
||||
| `audio-utils.ts` | `pcmToWav`, `createProbeWav` |
|
||||
| `drivers/OpenAI|Groq|Deepgram|AssemblyAI|Google|Custom|D3ROCloud` | Provider drivers; `D3ROCloudDriver` uses Supabase access token |
|
||||
|
||||
### LLM layer
|
||||
| Service | Purpose |
|
||||
|---|---|
|
||||
| `LocalLLMService` | Ollama REST (models, pull w/ progress, server start, NDJSON streaming) |
|
||||
| `PremiumLLMService` | Claude via Supabase `llm-proxy`, local fallback |
|
||||
| `OnlineLLMService` | JWT-authenticated .NET backend client |
|
||||
| `llm-prompts.ts` | `resolveSystemPrompt` SSOT for action prompts |
|
||||
|
||||
### Memory & knowledge
|
||||
| Service | Purpose |
|
||||
|---|---|
|
||||
| `HistoryService` | SQLite history CRUD/search/stats |
|
||||
| `DictionaryService` | Custom vocabulary CRUD/search + cloud sync hooks + JSON/CSV import/export (`dictionary:import`/`export`, save/open dialogs) |
|
||||
| `MemoService` | Memo tags over history (`memo_tags`) |
|
||||
| `RAGService` | Local RAG: `nomic-embed-text` embeddings, cosine search over `rag_chunks` |
|
||||
| `CustomInstructionService` | User LLM commands (5 built-ins) |
|
||||
| `VoiceCommandService` | Keyword → command rule matching |
|
||||
| `ChainService` | Multi-step LLM pipelines (LLMChain) |
|
||||
| `ScreenContextService` | Active-window + selected-text context |
|
||||
|
||||
### Phase 10+ features
|
||||
| Service | Purpose |
|
||||
|---|---|
|
||||
| `CaptionService` | Live captions from system/loopback audio; caption overlay (events segment, state-changed, session-saved, error) |
|
||||
| `FileTranscriptionService` | Audio/video file → ffmpeg → 30s chunks → STT merge (events progress, complete, error, state-changed) |
|
||||
| `MeetingSummaryService` | Post-caption LLM summary |
|
||||
| `DictationTemplateService` | Field-by-field voice form filling |
|
||||
| `VoiceConversationService` | STT→LLM→TTS loop, 10-turn memory |
|
||||
| `TTSPlaybackService` | Platform TTS (macOS `say`, Windows SAPI), sentence queue |
|
||||
| `VoiceActionService` | Voice → LLM JSON action plan → OS execution (dangerous blocked) |
|
||||
|
||||
### Phase 12–15
|
||||
| Service | Purpose |
|
||||
|---|---|
|
||||
| `MeetingModeService` | Meeting recording: live transcript, timestamp memos, doc generation/export, diarization |
|
||||
| `MeetingDocTemplateService` | Meeting-doc templates (built-ins + CRUD) |
|
||||
|
||||
### Account / infra / monetization
|
||||
| Service | Purpose |
|
||||
|---|---|
|
||||
| `ConfigService` | electron-store `AppConfig` (`configGet/Set`, defaults) |
|
||||
| `LicenseService` | Freemium tiers, quotas (`daily_usage`), activation, upgrade prompts |
|
||||
| `CloudSyncService` | Supabase sync, per-user DB switching, history/dictionary/meeting mirror |
|
||||
| `CloudSTTService` | Thin cloud STT wrapper over `D3ROCloudDriver` |
|
||||
| `UpdateService` | electron-updater (canonical Forgejo feed, channels, mandatory/full-vs-delta policy, staged rollout, restart dialog) |
|
||||
| `AutoLaunchService` | OS login-item auto-start |
|
||||
| `LoggerService` | electron-log wrapper + category loggers |
|
||||
| `checkout`/payment | `payment-handlers.ts` — authenticated Edge-only Stripe/Payple checkout + server readback |
|
||||
|
||||
### Ads (`services/ads/`)
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `AdMediationEngine` | Multi-ad mediation + header bidding |
|
||||
| `AdSettlementService` | Revenue settlement, withholding, payout ledger |
|
||||
| `BaseAdAdapter` / `UnavailableAdAdapter` | Adapter contract + fail-closed base |
|
||||
| `DirectHouseSponsorAdapter` | **Real configurable adapter**: bids/reports against an operator HTTPS `endpointUrl` (`AdNetworkConfig.endpointUrl`), validates creatives, fail-closed (`adapter_not_configured`) when unconfigured |
|
||||
| 9 placeholder adapters (AppLovin, Carbon, EthicalAds, GoogleAdManager, InMobi, Mintegral, Playwire, PubMatic, Unity) | Extend `UnavailableAdAdapter` — registered, no live bids (`provider_not_integrated`) |
|
||||
|
||||
---
|
||||
|
||||
## 3. IPC layer
|
||||
|
||||
Registry: `src/main/ipc/index.ts` calls 29 `registerXHandlers()` in fixed order. Channel SSOT: `packages/core/src/ipc-channels.ts`.
|
||||
|
||||
| Handler | Channel group(s) |
|
||||
|---|---|
|
||||
| `ads-handlers` | ADS |
|
||||
| `audio-handlers` | AUDIO |
|
||||
| `caption-handlers` | CAPTION + SYSTEM_AUDIO |
|
||||
| `chain-handlers` | CHAIN |
|
||||
| `cloud-sync-handlers` | CLOUD_SYNC |
|
||||
| `config-handlers` | CONFIG |
|
||||
| `context-handlers` | CONTEXT |
|
||||
| `dictionary-handlers` | DICTIONARY |
|
||||
| `file-transcription-handlers` | FILE_TRANSCRIPTION |
|
||||
| `history-handlers` | HISTORY + `stats:getSummary` |
|
||||
| `hotkey-handlers` | HOTKEY |
|
||||
| `instruction-handlers` | INSTRUCTION |
|
||||
| `license-handlers` | LICENSE |
|
||||
| `llm-handlers` | LLM + `llm:premium:*` + ONLINE_AUTH |
|
||||
| `meeting-doc-template-handlers` | MEETING_DOC_TEMPLATE |
|
||||
| `meeting-mode-handlers` | MEETING_MODE + MEETING_CHAT |
|
||||
| `meeting-summary-handlers` | MEETING_SUMMARY |
|
||||
| `memo-handlers` | MEMO |
|
||||
| `payment-handlers` | PAYMENT |
|
||||
| `rag-handlers` | RAG |
|
||||
| `stt-handlers` | STT |
|
||||
| `support-handlers` | SUPPORT |
|
||||
| `system-handlers` | SYSTEM |
|
||||
| `template-handlers` | DICTATION_TEMPLATE |
|
||||
| `voice-action-handlers` | VOICE_ACTION |
|
||||
| `voice-command-handlers` | VOICE_COMMAND |
|
||||
| `voice-conversation-handlers` | VOICE_CONVERSATION |
|
||||
| `voice-handlers` | VOICE |
|
||||
| `window-handlers` | WINDOW + `SYSTEM.OPEN_EXTERNAL` |
|
||||
|
||||
Preload exposes **`window.electronAPI`** with 33 namespaces: `platform, audio, config, voice, stt, hotkey, llm (incl. premium), history, dictionary, stats, window, system, instruction, app, memo, voiceCommand, context, chain, caption, license, fileTranscription, meetingSummary, dictationTemplate, rag, voiceAction, voiceConversation, meetingMode, meetingChat, meetingDocTemplate, cloudSync, onlineAuth, ads, support, payment`. Envelope: `IPCResult<T>` (success/error); `app.onDataChanged` is the global refresh channel.
|
||||
|
||||
---
|
||||
|
||||
## 4. Windows & popups
|
||||
|
||||
`windows/WindowManager.ts` creates 6 windows: main (borderless, custom TitleBar; macOS `hiddenInset`), recording-tip, result-popup, history-popup, command-popup, caption-overlay. Injects popup theme CSS + i18n strings; 2-phase resize. `windows/TrayManager.ts` — tray icon + menu + double-click show.
|
||||
|
||||
Vanilla popups (`src/renderer/popups/`):
|
||||
| Popup | Purpose |
|
||||
|---|---|
|
||||
| `recording-tip` | 9-bar waveform indicator, partial transcript |
|
||||
| `result-popup` | Transcription result + copy, auto-close with hover pause |
|
||||
| `history-popup` | Recent transcriptions; ↑↓/Enter/1-9/ESC |
|
||||
| `command-popup` | Command selection (Ctrl+Shift+C) |
|
||||
| `caption-overlay` | Live caption overlay (font/opacity/maxLines) |
|
||||
|
||||
---
|
||||
|
||||
## 5. Renderer IA
|
||||
|
||||
Routing is state-based in `AppLayout.tsx` (`Route` union + `NAV_ITEMS`), no react-router.
|
||||
|
||||
| Page | Route | Feature |
|
||||
|---|---|---|
|
||||
| `DashboardPage` | dashboard | Voice cockpit: hero, bento tiles, multi-engine hub (STT/LLM), telemetry, recent history, file drop |
|
||||
| `HistoryPage` | history | History & memory timeline; search, tag filter, pagination, export/delete |
|
||||
| `DictionaryPage` | dictionary | Custom vocabulary editor |
|
||||
| `CommandsPage` | commands | Custom instructions + voice keyword rules + LLM chains + dictation templates |
|
||||
| `VoiceConversationPage` | conversation | Duplex voice assistant (local pipeline vs OpenAI Realtime) |
|
||||
| `KnowledgeBasePage` | knowledge | Local RAG: add/index docs, semantic query, reindex/remove |
|
||||
| `MeetingModePage` | meeting | Meeting studio: live transcript, memos, doc generation/export, diarization |
|
||||
|
||||
Modals/components: `SettingsModal` (tabs General/Audio/STT/LLM/License/Cloud/About), `LicenseModal`, `LicenseTab`, `CloudSyncSection`, `OnboardingModal`, `UpgradePromptModal`, `ProBadge`, `TemplateSection`, `FileDropZone`, `HotkeyRecordModal`, `OllamaGuideModal`, `CodexOAuthGuideModal`, `TitleBar`, `StatusBar`, meeting components (9), voice-conversation, payment (`CheckoutModal`, `checkout-flow.ts`), support (`SupportModal`), ads (`AdBanner`, `RewardedQuotaModal`), shared cards.
|
||||
|
||||
Hooks: `useRealtimeConversation` (OpenAI Realtime WebRTC), `useLicenseState`, `useProFeature`.
|
||||
|
||||
DB schema (`src/main/db/schema.ts`, drizzle SQLite): `history`, `dictionary`, `stats`, `memo_tags`, `daily_usage`, `rag_documents`, `rag_chunks`, `meeting_sessions`, `meeting_memos`, `meeting_documents`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Desktop status summary
|
||||
|
||||
- Core dictation/LLM/history pipeline: **implemented + tested** (~590 desktop tests; vitest + playwright).
|
||||
- Cross-platform packaging: Windows NSIS (signed, `forceCodeSigning`), macOS DMG/ZIP arm64 (ad-hoc signing); auto-update via canonical Forgejo feed with update policy (`release/update-policy.json`).
|
||||
- Local-first AI (SoX + faster-whisper sidecar + bundled Ollama) and cloud paths both present.
|
||||
- Meeting intelligence, RAG, voice conversation (local + Realtime), captions, file transcription: implemented.
|
||||
- **Ad mediation**: `DirectHouseSponsorAdapter` performs real configurable REST bids; the other 9 adapters remain fail-closed stubs pending official SDKs (see `11-gap-backlog.md` GAP-ADS-01/02).
|
||||
- Tier resolution now routes through `@d3ro/core/entitlement` (`resolveEntitlement`, `normalizeEntitlementTier`); `useLicenseState.isPro` includes `pro_plus`.
|
||||
- No `TODO`/`FIXME` markers found in `src` (grep clean). `src/main/types/` is an empty directory.
|
||||
|
||||
---
|
||||
|
||||
## 7. Key file anchors
|
||||
|
||||
| Thing | Path |
|
||||
|---|---|
|
||||
| App entry / deep links | `src/main/index.ts` |
|
||||
| Bootstrap order | `src/main/bootstrap.ts` |
|
||||
| IPC registry | `src/main/ipc/index.ts` |
|
||||
| IPC channel SSOT | `packages/core/src/ipc-channels.ts` |
|
||||
| Preload API | `src/preload/index.ts` |
|
||||
| Windows | `src/main/windows/WindowManager.ts` |
|
||||
| Voice orchestrator | `src/main/services/VoiceModeService.ts` |
|
||||
| DB schema | `src/main/db/schema.ts` |
|
||||
| Renderer shell / routes | `src/renderer/components/AppLayout.tsx` |
|
||||
| Update feed SSOT | `src/main/update-feed.ts` |
|
||||
| Update policy SSOT | `release/update-policy.json` + `src/main/update-policy.ts` |
|
||||
86
docs/map/05-web-app.md
Normal file
86
docs/map/05-web-app.md
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
# 05 — Web App (Next.js) Map
|
||||
|
||||
> Surface: `apps/web`
|
||||
> Stack: Next.js 15 App Router + React 19 + MUI (via `@d3ro/ui`) + Supabase
|
||||
> Role: cloud console; the reference surface for server-shared data UX
|
||||
|
||||
---
|
||||
|
||||
## 1. Route tree (`src/app/`)
|
||||
|
||||
Root layout: `ThemeProvider → I18nProvider → AuthProvider`.
|
||||
|
||||
| Route | Type | Feature |
|
||||
|---|---|---|
|
||||
| `/` | server | Redirects: session → `/dashboard`, else `/login` (also `/login` when Supabase unconfigured) |
|
||||
| `/login` | client | OAuth (Google/GitHub/Apple) + email/password |
|
||||
| `/accept-invite` | client | Team invite acceptance (`?token=` → `team-accept`); stores pending token if logged out |
|
||||
| `/download` | client | Download center + release history; desktop installers marked "release pending"; client SHA-256 verify tool |
|
||||
| `/releases` | server | Re-exports `/download` |
|
||||
| `/auth/callback` | route handler | OAuth code → session exchange |
|
||||
| `(app)/record` | server | `<MicRecorder/>` real-time record/STT |
|
||||
| `(app)/commands` | client | Custom instruction CRUD/reorder/activate/execute |
|
||||
| `(app)/dashboard` | client | Stats (sessions, time, words, streak), tier, recent history |
|
||||
| `(app)/actions` | server | NL command → LLM parse → action (`<ActionRunner/>`) |
|
||||
| `(app)/meetings` | server | Meetings list |
|
||||
| `(app)/meetings/[id]` | server | Meeting detail: audio player, live transcript (Realtime), memos, generated docs |
|
||||
| `(app)/knowledge` | server | RAG doc list + add + semantic search (search "planned V2-M+1") |
|
||||
| `(app)/teams` | server | Teams list + create |
|
||||
| `(app)/teams/[id]` | server | Team detail: members, owner-only invite, team meetings |
|
||||
| `(app)/chat` | server | Talk AI chat (`<ChatPanel/>`) |
|
||||
| `(app)/dictionary` | client | Pronunciation dictionary CRUD |
|
||||
| `(app)/history` | client | History list: search, favorites, pagination, copy/delete |
|
||||
| `(app)/history/[id]` | client | History detail: edit title/original/polished, favorite, delete |
|
||||
| `(app)/billing` | client | Plans + Payple/Stripe checkout, manage/portal |
|
||||
|
||||
`(app)/layout.tsx` is the auth guard + shared `<Sidebar/>`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Components (`src/components/`)
|
||||
|
||||
| Group | Components |
|
||||
|---|---|
|
||||
| `actions/` | `action-runner.tsx` (LLM parse → action: create_meeting/search_knowledge/create_memo/send_team_invite) |
|
||||
| `record/` | `mic-recorder.tsx` (MediaRecorder + level analyser → `transcribeWebAudio`) |
|
||||
| `dashboard/` | `meetings-trend-chart.tsx` (recharts) |
|
||||
| `billing/` | `billing-checkout-options`, `checkout-button` (Stripe), `payple-checkout-button`, `payple-client`, `payple-manage-button`, `portal-button` |
|
||||
| `meetings/` | `document-editor`, `generate-document-button`, `live-transcript-list` (Realtime), `markdown-preview` (Mermaid), `meeting-audio-player` (signed URL), `memo-form` |
|
||||
| `chat/` | `chat-panel.tsx` |
|
||||
| `teams/` | `create-team-form`, `invite-member-form`, `activity-feed` (team notes + realtime) |
|
||||
| `knowledge/` | `add-knowledge-form` (text or `.txt`/`.md` file, newline-aware chunking, `embed-chunks` on submit), `knowledge-search` (semantic via `search-knowledge`) |
|
||||
| `layout/` | `sidebar.tsx` (nav, theme selector, logout, i18n) |
|
||||
| `providers/` | `auth-provider`, `i18n-provider`, `theme-mode-context`, `theme-provider` |
|
||||
|
||||
---
|
||||
|
||||
## 3. Clients (`src/lib/`)
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `billing-catalog.ts` | Parse/validate billing catalog (schema v1, pro/pro_plus, Payple/Stripe prices) |
|
||||
| `command-client.ts` | Custom instruction client (types, error codes, execute) |
|
||||
| `dashboard-client.ts` | Dashboard snapshot loader |
|
||||
| `dictionary-client.ts` | Dictionary CRUD/pagination/search + `serializeDictionary` / `parseDictionaryFile` / `importDictionaryFile` (JSON/CSV) |
|
||||
| `history-client.ts` | History list/get/update/delete, revision-safe |
|
||||
| `supabase-browser.ts` | Re-export `@d3ro/api-client/supabase-browser` |
|
||||
| `supabase-server.ts` | Next `cookies()` wrapper |
|
||||
| `web-stt-client.ts` | Web STT via `stt-proxy`, 25 MB limit, `WebSttError` codes |
|
||||
|
||||
---
|
||||
|
||||
## 4. Tests
|
||||
|
||||
Playwright specs in `apps/web/e2e/`: billing, payple-checkout, dashboard-dictionary-commands, history, web-stt-client, smoke.
|
||||
|
||||
---
|
||||
|
||||
## 5. Web status summary
|
||||
|
||||
- Full App Router console: auth (email + OAuth), record/STT, history (list+detail), commands, actions, meetings (list+detail+docs), knowledge (add+search), teams (list+detail+invite), chat, dictionary, billing, download/releases.
|
||||
- Backed by Supabase tables + Edge Functions (`stt-proxy`, `llm-proxy`, `team-invite`, `team-accept`, `stripe-checkout`, `payple-checkout`, `payple-manage`, `search-knowledge`, `generate-meeting-document`).
|
||||
- No literal `TODO`/`FIXME` markers; remaining smaller items (see [`11-gap-backlog.md`](./11-gap-backlog.md) `WEB-*`):
|
||||
- Teams `member_count` is `0` in MVP (separate query needed) — `teams/page.tsx`.
|
||||
- Action runner team-invite uses a manual redirect safety path instead of a live invite (`action-runner.tsx`).
|
||||
- `/download` shows "artifact not yet published" for the current desktop release.
|
||||
- Knowledge file upload, semantic search, dictionary import/export, and the team activity feed are now implemented (`[x]` in the catalog).
|
||||
114
docs/map/06-mobile-app.md
Normal file
114
docs/map/06-mobile-app.md
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
# 06 — Mobile App (React Native) Map
|
||||
|
||||
> Surface: `apps/mobile-rn` (ACTIVE product mobile app)
|
||||
> Stack: React Native 0.85 + React 19 (CLI) + Supabase + Google Play Billing + AdMob
|
||||
> The Expo legacy skeleton (`apps/mobile`) was **removed 2026-09-13**; `apps/mobile-rn` is the only mobile runtime.
|
||||
> Authoritative checklist: `docs/v3/MOBILE_APP_COMPLETION_SSOT.md`
|
||||
|
||||
---
|
||||
|
||||
## 1. Navigation structure
|
||||
|
||||
Root stack (`App.tsx` `RootNavigator`) branches on auth/onboarding:
|
||||
- `recovery` → `UpdatePassword`
|
||||
- `onboarding` → Onboarding + InviteAccept + Login
|
||||
- unauthenticated → Login, SignUp, ForgotPassword, InviteAccept
|
||||
- authenticated → `Main` (`TabNavigator`) + ~22 stack screens
|
||||
|
||||
Bottom tabs (`TabNavigator.tsx`): **Dash / Works / Record (center raised FAB) / Talk / Settings**.
|
||||
Deep links: `d3ro-voice://` and `https://d3ro.chanpaca.net` (`accept-invite`).
|
||||
|
||||
Provider stack: `GestureHandlerRootView → SafeAreaProvider → AuthProvider → EntitlementProvider → BillingProvider → MobileAdsProvider → MobilePreferencesProvider → DeviceProvider → LocalizedApplication (I18n + StatusBar)`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Screens (`src/screens/`, 30)
|
||||
|
||||
| Screen | Feature |
|
||||
|---|---|
|
||||
| `RecordScreen` | Recording + local-whisper/cloud transcription, import audio, share |
|
||||
| `DashScreen` | Dashboard: usage stats, tier, streaks, trends |
|
||||
| `WorksHubScreen` | WORKS hub: pinned feature drill-down (desktop-parity) |
|
||||
| `TalkScreen` | Voice/text AI chat: STT, LLM streaming, TTS |
|
||||
| `HistoryScreen` / `HistoryDetailScreen` | History list/detail: sync, search, filters, audio playback, edit/share/favorite/delete |
|
||||
| `MeetingsScreen` / `MeetingDetailScreen` | Meeting workspaces: create/rename/delete, transcript, memos, documents, export, content report |
|
||||
| `MemosScreen` | Memos: list, tags, search, share |
|
||||
| `TemplatesScreen` | Dictation/meeting document templates CRUD |
|
||||
| `KnowledgeScreen` | Knowledge docs: create/import/index/merge/delete/search |
|
||||
| `CommandsScreen` | Custom instruction CRUD/reorder/activate/execute |
|
||||
| `ActionsScreen` | Voice-action parse/confirm/execute + history |
|
||||
| `DictionaryScreen` | Dictionary CRUD/search/filters |
|
||||
| `TeamsScreen` / `TeamDetailScreen` | Teams: create, members, invites, rename, leave, meetings, activity feed/comments |
|
||||
| `DevicesScreen` | Registered devices, revoke/remove |
|
||||
| `NotificationsScreen` | Notification list, permission, deep-link nav |
|
||||
| `AccountScreen` | Profile, identities, data export/delete, logout |
|
||||
| `DataPortabilityScreen` | Export/import archive, dictionary, history, meeting docs |
|
||||
| `AdminScreen` / `AdminUserDetailScreen` | Role-gated admin: users, subscriptions, audit, role/tier edits |
|
||||
| `ProPaywallScreen` | Pro/Pro+ paywall: Play IAP, restore, rewarded ads |
|
||||
| `OnboardingScreen` | First-run audience/theme/locale |
|
||||
| `SettingsScreen` | Preferences, locale/theme, privacy links, logout |
|
||||
| `LoginScreen` / `SignUpScreen` / `ForgotPasswordScreen` / `UpdatePasswordScreen` / `InviteAcceptScreen` | Auth flows |
|
||||
|
||||
---
|
||||
|
||||
## 3. Features (`src/features/`, 20 modules)
|
||||
|
||||
| Module | Purpose |
|
||||
|---|---|
|
||||
| `recording/` | Durable offline recording queue, retry processing, language handling |
|
||||
| `import/` | Audio pick/decode/validate, local Whisper fallback, resumable multipart upload, Android share-intent intake |
|
||||
| `history/` | History service + local cache + sync hook |
|
||||
| `meetings/` | Meeting workspace CRUD, realtime channels, processing jobs, transcripts/memos/docs |
|
||||
| `memos/` | Memo CRUD, tags, search, realtime, share |
|
||||
| `talk/` | Streaming LLM, transcription, TTS playback |
|
||||
| `teams/` | Team CRUD/members/invites/realtime, pending invite, `listTeamActivities`/`createTeamActivity` (activity feed) |
|
||||
| `knowledge/` | Knowledge docs CRUD/index/merge/search + file picker |
|
||||
| `commands/` | Custom command client |
|
||||
| `actions/` | Voice-action parse/execute + side effects |
|
||||
| `dictionary/` | Dictionary CRUD/pagination/search |
|
||||
| `devices/` | Device registration/list/revoke |
|
||||
| `dashboard/` | Dashboard stats + recent entries |
|
||||
| `templates/` | Templates + generation idempotency |
|
||||
| `auth/` | OAuth sign-in (in-app browser, PKCE) + identity linking |
|
||||
| `admin/` | Admin user/subscription/audit APIs + session/role |
|
||||
| `data-portability/` | Canonical JSON export/import, schema validation, legacy import, meeting export, file sharing |
|
||||
| `chat/` | Chat LLM normalization/streaming, reportable generation IDs |
|
||||
| `notifications/` | Notification contract/native registration/service/runtime hook |
|
||||
| `reporting/` | AI content reporting (reason codes, Edge calls, idempotency) |
|
||||
|
||||
Core libs (`src/lib/`): `auth-context`, `auth-redirect`, `auth-capabilities`, `secure-auth-storage` (Keychain + legacy migration), `logout`, `account-exit`, `account-local-data` (central purge), `supabase`, `billing-context` (Play/App Store IAP), `entitlement-context`, `device-context`, `preferences-context`, `mobile-ads-context` (UMP consent + rewarded), `native-config`, `pkce-s256`, `random-id`, `audio-recorder`, `e2e-runtime-bootstrap`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Mobile status summary
|
||||
|
||||
Source of truth for status is `docs/v3/MOBILE_APP_COMPLETION_SSOT.md` sections 0.1, 2.1, 4. Current condensed state:
|
||||
|
||||
| Area | Status |
|
||||
|---|---|
|
||||
| Auth / account | `[~]` Implemented + Jest GREEN; external OAuth consent→callback and logout/delete/provider device E2E pending |
|
||||
| Onboarding / theme / accessibility | `[x]` device journey GREEN (some checklist rows still `[ ]` for a11y specifics) |
|
||||
| Recording / transcription / Talk | `[x]` core path GREEN on API 34 (FGS, recovery, local Whisper, cloud fail-closed, TTS) |
|
||||
| Data portability | `[x]` export/restore + share E2E GREEN |
|
||||
| History / meetings | `[x]` real data + meeting creation contract GREEN; audio timestamp/speaker + cross-app E2E pending |
|
||||
| Teams / push | `[~]` teams GREEN; real FCM delivery needs Firebase/FCM credentials |
|
||||
| Billing / ads | `[~]` test ads + Google Play verification code GREEN; live store purchase/restore/settlement and production AdMob serving **RED (external)** |
|
||||
| Admin | `[x]` mobile admin role E2E GREEN (ordinary/manager/admin/super_admin, stale JWT) |
|
||||
| Quality / distribution | `[~]` lint/typecheck/Jest GREEN; production signed AAB + Play submission **RED (external gates)** |
|
||||
|
||||
**External blockers (do not treat as code gaps):** production Firebase project, AdMob live serving, Play Billing license tester, CI secret injection, signed production AAB, Play closed test (0/12, 14 days), production access approval. See SSOT §0, §6.
|
||||
|
||||
---
|
||||
|
||||
## 5. Legacy removal
|
||||
|
||||
The Expo skeleton (`apps/mobile`) was deleted on 2026-09-13: it duplicated auth/data logic, shipped a dev-bypass login, and was outside the workspace and CI. `scripts/ci/sync-version.mjs` and `package-lock.json` no longer reference it. `apps/mobile-rn` is the sole mobile runtime; git history retains the old app.
|
||||
|
||||
---
|
||||
|
||||
## 6. Tests & evidence
|
||||
|
||||
- Jest: `apps/mobile-rn/__tests__/` — per SSOT 57 suites / 353 tests (auth, privacy purge, admin, billing, recording language, generation idempotency, templates/memos, STT quota integration).
|
||||
- Maestro E2E: `apps/mobile-rn/.maestro/` + evidence in `.maestro-output/`.
|
||||
- Android instrumentation: `apps/mobile-rn/android/app/src/androidTest` (CSPRNG + incoming share).
|
||||
- Build verifiers: `scripts/ci/verify-android-artifact.mjs`, `verify-android-app-links.mjs`, `verify-mobile-build-config.mjs`, `verify-mobile-release-boundary.mjs`.
|
||||
107
docs/map/07-api-server.md
Normal file
107
docs/map/07-api-server.md
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
# 07 — API Server (.NET) Map
|
||||
|
||||
> Surface: `apps/api-server` (`D3ROVoice.Api`), tests in `apps/api-server.Tests`
|
||||
> Stack: ASP.NET Core 10 + EF Core + SQLite
|
||||
> Role: AI proxy (LLM/STT) + admin back-office backend for the .NET identity side
|
||||
|
||||
---
|
||||
|
||||
## 1. Composition root (`Program.cs`)
|
||||
|
||||
- **DI:** `AddControllers`, `AddHttpClient` (proxies), Swagger (`v1`), rate limiter policy `auth` (fixed window 10/min per IP, 429), `AddDbContext<AppDbContext>` (SQLite; `DATA_DIR`/`DB_PATH`), scoped `IAuthService`, `ILlmProxyService`, `ISttProxyService`, `IAdminOperationService`.
|
||||
- **Auth:** JWT Bearer HS256; startup hard-fails unless `JWT_SECRET` (≥32 bytes), `JWT_ISSUER`, `JWT_AUDIENCE` are set. Zero clock skew.
|
||||
- **Policies:** `ManagerOrAbove` (manager/admin/superadmin), `AdminOrAbove` (admin/superadmin), `SuperAdminOnly` (superadmin). Role normalization strips `_`/`-`, lowercases.
|
||||
- **CORS/Hosts:** strict origin validation (`CORS_ALLOWED_ORIGINS`), `ALLOWED_HOSTS` required outside Development.
|
||||
- **Startup DB init:** `EnsureCreated()`, raw `CREATE TABLE IF NOT EXISTS` for admin operation/audit tables, legacy SHA-256 password lockdown (`IsActive=false`, `Role="LegacyDisabled"`), idempotent env admin provisioning (`ADMIN_EMAIL`/`ADMIN_PASSWORD`, only when no active user), default LLM/STT endpoints seeded.
|
||||
- **Middleware order:** Swagger (dev) → CORS → invite-page hardening (CSP/no-store) → default files → mobile/legacy asset block (404 for `.apk`/`.aab`/signed zips + legacy bundles) → static files → rate limiter → authentication → authorization.
|
||||
- **Health:** `GET /health`, `GET /api/health` → `{status, service, version, uptimeSeconds, database, timestamp}`.
|
||||
- **Fallbacks:** `/accept-invite` → `accept-invite.html`; `/admin/{*path}` → legacy embedded admin SPA in `wwwroot/admin`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Controllers & routes
|
||||
|
||||
### `AuthController` (`/api/auth`)
|
||||
| Route | Auth | Behavior |
|
||||
|---|---|---|
|
||||
| `POST /register` | anonymous + `X-D3RO-Bootstrap-Token` | Rate-limited, ≤16KB; requires `ADMIN_BOOTSTRAP_TOKEN`; fixed-time compare; `409` if registered |
|
||||
| `POST /login` | anonymous | Rate-limited; returns JWT; `401` invalid |
|
||||
| `GET /me` | `[Authorize]` | `UserInfoDto` or `404` |
|
||||
|
||||
### `LlmController` (`/api/llm`, class `[Authorize]`)
|
||||
| Route | Behavior |
|
||||
|---|---|
|
||||
| `POST /generate` | Requires prompt; `GenerateAsync` |
|
||||
| `POST /chat` | `ChatAsync` (last message = prompt) |
|
||||
|
||||
### `SttController` (`/api/stt`, class `[Authorize]`)
|
||||
| Route | Auth | Behavior |
|
||||
|---|---|---|
|
||||
| `POST /transcribe` | any auth | **Always `410 Gone` `stt_edge_gateway_required`** — user transcription is Edge-only |
|
||||
| `POST /internal/transcribe` | anonymous + `X-D3RO-STT-Gateway-Token` | multipart, ≤26MB; requires `D3RO_API_TOKEN`; fixed-time compare; provider orchestration; error map `503/400/502` |
|
||||
| `GET /providers` | ManagerOrAbove | List STT endpoints |
|
||||
| `POST /test?endpointId=` | ManagerOrAbove | Test endpoint |
|
||||
|
||||
### `AdminController` (`/api/admin`, class `ManagerOrAbove`)
|
||||
All mutations flow through `ExecuteAdminMutationAsync` (idempotent + audited).
|
||||
|
||||
| Route | Effective policy |
|
||||
|---|---|
|
||||
| `GET /stats` | Manager+ |
|
||||
| `GET /users` | Manager+ |
|
||||
| `GET/POST/PUT/DELETE /endpoints[/{id}]` | Manager+ read; Admin+ write |
|
||||
| `GET /stt-endpoints`, `/stt-endpoints/{id}` | Manager+ |
|
||||
| `POST/PUT/DELETE /stt-endpoints[/{id}]`, `POST .../set-default` | Admin+ |
|
||||
| `POST /stt-endpoints/{id}/test` | Manager+ |
|
||||
| `POST /stt-endpoints/test-direct` | Admin+ |
|
||||
| `GET /stt-usage`, `GET /usage` | Manager+ |
|
||||
| `POST /license-audit` | **SuperAdminOnly** |
|
||||
|
||||
---
|
||||
|
||||
## 3. Services
|
||||
|
||||
| Service | Purpose |
|
||||
|---|---|
|
||||
| `AuthService` | Register (one-time SuperAdmin bootstrap only, `PasswordHasher<User>`, serialized), login (timing-safe dummy verify, inactive rejection, rehash), JWT gen (8h, claims id/email/role) |
|
||||
| `LlmProxyService` | Resolve endpoint by model → fallback → Mock echo; OpenAI-style POST; parse content+usage; token cost → `ApiUsageLog`; errors → `ServerErrorLog` + fallback text |
|
||||
| `SttProxyService` (~1182 lines) | Provider adapters (groq/openai/custom, deepgram, google, assemblyai, azure, local-sidecar), candidate resolution + fallback, content-type/duration detection, `SttUsageLog` cost, synthetic-tone endpoint test, CRUD with exclusive default, usage report |
|
||||
| `AdminOperationService` | Validates actor/idempotency key/memo, SHA-256 request hash, `Serializable` transaction, idempotent replay, before/after audit entry |
|
||||
|
||||
---
|
||||
|
||||
## 4. Data (`Data/AppDbContext.cs`)
|
||||
|
||||
| DbSet / table | Key fields |
|
||||
|---|---|
|
||||
| `Users` | Id, unique Email, PasswordHash, Role (default "User"), IsActive, CreatedAt, LastLoginAt |
|
||||
| `ModelEndpoints` | Id, unique ModelId, ModelName, Provider, EndpointUrl, ApiKey, per-1k costs, IsActive |
|
||||
| `UsageLogs` | UserId/Email, model, tokens, cost, duration, status |
|
||||
| `ErrorLogs` | ErrorType, Message, StackTrace, Endpoint |
|
||||
| `SttProviderEndpoints` | Name, ProviderType, URL, ApiKey, ModelId, Method, Language, Prompt, Temperature, per-minute/second cost, IsDefault, FallbackPriority, ExtraHeadersJson |
|
||||
| `SttUsageLogs` | User, endpoint, provider, duration, cost, latency, status, transcript preview |
|
||||
| `AdminOperationRequests` | ActorEmail + IdempotencyKey (unique), Operation, RequestHash, ResponseJson |
|
||||
| `AdminAuditEntries` | ActorEmail, Action, TargetType/Id, BeforeJson, AfterJson, Memo, IdempotencyKey |
|
||||
|
||||
DTOs (`Dtos/Dtos.cs`): auth, license audit, LLM, admin/model endpoints, STT (transcribe, endpoints, test, usage reports).
|
||||
|
||||
---
|
||||
|
||||
## 5. Tests (`apps/api-server.Tests/`, xUnit)
|
||||
|
||||
`AdminAuthorizationE2ETests`, `AdminOperationServiceTests`, `AuthBootstrapControllerTests`, `AuthSecurityTests`, `SttControllerSecurityTests`, `SttFailClosedTests`, `SttGatewayAuthorizationE2ETests` (26/26 per SSOT).
|
||||
|
||||
---
|
||||
|
||||
## 6. API server status summary
|
||||
|
||||
- Auth, login, JWT, role policies, rate limiting, CORS, host restrictions: **implemented**.
|
||||
- LLM proxy: **implemented** (with local Mock echo fallback for standalone testing).
|
||||
- STT proxy: **implemented** for internal gateway; public `/transcribe` intentionally `410` (Edge-only by design).
|
||||
- Admin API: users, endpoints (LLM + STT), usage, license audit: **implemented** with idempotency + audit.
|
||||
- Known intentional states (not bugs):
|
||||
- Legacy SHA-256 users force-disabled.
|
||||
- No hardcoded/seeded admin credentials.
|
||||
- Mobile/legacy release assets blocked with 404.
|
||||
- `LlmProxyService` Mock fallback.
|
||||
- This backend holds a **separate identity** from Supabase; see `11-gap-backlog.md` `ID-01`.
|
||||
91
docs/map/08-admin-console.md
Normal file
91
docs/map/08-admin-console.md
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# 08 — Admin Console (Next.js) Map
|
||||
|
||||
> Surface: `apps/admin`
|
||||
> Stack: Next.js 16 App Router + MUI (`@d3ro/ui` theme) + Supabase service role + .NET proxy
|
||||
> Role: back office CRM/ops — users, subscriptions, models, usage, audit, releases, ads
|
||||
|
||||
---
|
||||
|
||||
## 1. Route tree (`src/app/`)
|
||||
|
||||
### Public
|
||||
| Route | Purpose |
|
||||
|---|---|
|
||||
| `/login` | Email/password → `/api/auth/login`; Google OAuth via Supabase → `/auth/callback`; maps error keys |
|
||||
| `/unauthorized` | 403 screen |
|
||||
| `/auth/callback` | OAuth code → session exchange |
|
||||
|
||||
### Protected `(admin)` (guarded by `(admin)/layout.tsx` → `requireManager()`)
|
||||
| Route | Purpose |
|
||||
|---|---|
|
||||
| `/` | Dashboard: backend stats, node health, MRR/ARR/active subscriptions (Supabase), recent errors |
|
||||
| `/pipelines` | AI/voice pipeline telemetry; explicit "unavailable" card when no measured data |
|
||||
| `/models` | LLM model + STT provider manager (presets, CRUD, test) |
|
||||
| `/releases` | Forgejo live release hub (assets, platforms, sizes, downloads, SHA-256) |
|
||||
| `/users` | User directory: search + tier/role filters |
|
||||
| `/users/[id]` | User 360: profile, subscription, 30-day usage, role change (admin+), payment history |
|
||||
| `/subscriptions` | Subscription ops list + filters; license issuer (super_admin) |
|
||||
| `/subscriptions/new` | Grant VIP subscription (admin+) |
|
||||
| `/subscriptions/[id]` | Subscription detail: edit (manager+) / delete (admin+) |
|
||||
| `/ads` | Ad mediation console (10 networks, all fail_closed) + reward stats |
|
||||
| `/support` | **Stub** — explicit "not configured" panel |
|
||||
| `/usage` | Combined LLM + STT usage/cost analytics |
|
||||
| `/audit-log` | Supabase audit log list + target filter + pagination |
|
||||
| `/audit-log/[id]` | Audit detail with before/after diff |
|
||||
|
||||
---
|
||||
|
||||
## 2. API route handlers (`src/app/api/`)
|
||||
|
||||
| Route | Methods | Behavior |
|
||||
|---|---|---|
|
||||
| `/api/auth/login` | POST | Validate body, reject honeypot `trap`, in-memory rate limit/lockout, proxy to `.NET /api/auth/login` (7s timeout, HTTPS in prod), validate token/role/email/expiry, sign HMAC session cookie `d3ro_admin_session` |
|
||||
| `/api/auth/logout` | POST/GET | Clear cookie; GET redirects `/login` |
|
||||
| `/api/admin/backend/[...segments]` | GET/POST/PUT/DELETE | Allow-list proxy to `.NET /api/admin/*`; required role by path; same-origin for non-GET; ≤64KB; UUID idempotency-key for mutations |
|
||||
| `/api/admin/license` | POST | Same-origin + `requireVerifiedBackendSession('super_admin')`; sign Ed25519 key with `ADMIN_LICENSE_PRIVATE_KEY` (`@d3ro/core/utils/crypto-license`); best-effort audit |
|
||||
| `/api/admin/supabase/[operation]` | GET/POST/PATCH/DELETE | `admin-users`, `admin-subscriptions`, `admin-payments` via RPCs; strict allow-lists; Payple live history returns `501` |
|
||||
| `/auth/callback` | GET | Supabase OAuth exchange |
|
||||
|
||||
---
|
||||
|
||||
## 3. Libraries (`src/lib/`)
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `admin-session.ts` | Session types, secret validation (≥32 bytes), strict cookie parse, `adminCookieSecure()` escape hatch |
|
||||
| `security.ts` | server-only HMAC-SHA256 sign/verify, in-memory rate limit/lockout, runtime security validation |
|
||||
| `admin-guard.ts` | RSC guards `requireManager`/`requireAdmin`/`requireSuperAdmin`, role helpers |
|
||||
| `edge-session.ts` | Edge-runtime HMAC verify via WebCrypto (used by `proxy.ts`) |
|
||||
| `backend-session.ts` | `requireApiServerOrigin`, `requireVerifiedBackendSession(minRole)` (verifies cookie + `.NET /api/auth/me`), `fetchAdminBackend` |
|
||||
| `api-server.ts` | server-only data access to .NET backend (stats, users, endpoints, usage reports) |
|
||||
| `backend-admin-client.ts` | client CRUD for model/STT endpoints with auto idempotency keys |
|
||||
| `admin-api.ts` | client `callAdminApi` for Supabase admin operations |
|
||||
| `supabase-admin.ts` | service-role client, actor resolution RPC, product user fetch |
|
||||
| `supabase-browser.ts` / `supabase-server.ts` | client/server Supabase wrappers |
|
||||
| `ad-monetization.ts` | `MEDIATION_ROSTER` (fail_closed) + ad reward stats |
|
||||
| `subscription-metrics.ts` | MRR/ARR/active/tier breakdown |
|
||||
| `audit-sanitize.ts` | recursive redaction of sensitive keys in audit snapshots |
|
||||
| `forgejo-releases.ts` | Forgejo release feed parser (`RELEASE_REPO_URL`) |
|
||||
| `console-theme.ts` | design tokens + MUI style presets |
|
||||
|
||||
Root files: `instrumentation.ts` (startup security validation), `proxy.ts` (edge middleware: public paths, auth redirect, security headers), `robots.ts` (disallow all).
|
||||
|
||||
---
|
||||
|
||||
## 4. Components (`src/components/`)
|
||||
|
||||
`admin-sidebar` (nav island: Core Platform / Customer & Revenue / Intelligence & Security), `unavailable-admin-panel` (reusable "NOT CONNECTED", no sample data), `audit-diff-viewer`, `payment-history`, `subscription-form`, `role-change-dialog` + `role-change-button`, `memo-dialog`, `license-issuer-button` + `license-issuer-dialog`, `checksum-copy`, charts (`dau-chart`, `feature-usage-chart`, `top-users-chart`).
|
||||
|
||||
---
|
||||
|
||||
## 5. Admin status summary
|
||||
|
||||
- Dashboard, models, releases, users, subscriptions, usage, audit log, ads: **implemented** against real backend/Supabase data.
|
||||
- Security: HMAC signed sessions, RSC + edge guards, rate limit/lockout, honeypot, strict origin/allow-list, no-store, robots disallow, audit redaction. Red-team scenarios were exercised (see `memory/project_status.md`).
|
||||
- Explicit fail-closed / not-configured states (by design, not bugs):
|
||||
- `/support` stub — no ticket/SLA/diagnostics contract.
|
||||
- `/ads` — all 10 networks `fail_closed`; no live bids.
|
||||
- `admin-payments` Payple live history → `501`.
|
||||
- `UnavailableAdminPanel` whenever Supabase env absent; writes disabled, no sample metrics.
|
||||
- `/pipelines` and dashboard node/error sections render only measured data.
|
||||
- Deploy: `Dockerfile.admin` / `apps/admin/Dockerfile` → GHCR + NAS compose; GitLab admin NAS deploy job disabled.
|
||||
101
docs/map/09-supabase-backend.md
Normal file
101
docs/map/09-supabase-backend.md
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# 09 — Backend: Supabase + Cloudflare Map
|
||||
|
||||
> Surfaces: `server/supabase` (Postgres + Deno Edge Functions), `server/cloudflare-worker` (edge gateway)
|
||||
> Role: canonical product data, auth, RLS, storage, AI proxies, billing, notifications
|
||||
|
||||
---
|
||||
|
||||
## 1. Supabase project (`server/supabase/`)
|
||||
|
||||
- `config.toml` — project_id `d3ro-voice`; local ports API 55321 / DB 55322 / Studio 55323 / Inbucket 55324; DB major v17; storage 50 MiB; auth `site_url` localhost:5173, redirects include `https://d3ro.chanpaca.net` and `d3ro-voice://auth-callback`; external providers Google/GitHub/Apple; per-function `verify_jwt` settings; analytics off.
|
||||
- `seed.sql`, `migrations/` (63), `functions/` (~27), `functions/_shared/`, `tests/`, `deno.json`.
|
||||
|
||||
> Note: root `supabase/` contains only empty scaffolding (`.branches/`, `snippets/`). The real project lives under `server/supabase/`.
|
||||
|
||||
### 1.1 Migrations (62) — thematic groups
|
||||
|
||||
| Theme | Examples |
|
||||
|---|---|
|
||||
| Core schema + RLS + auth triggers | initial tables, profiles, triggers |
|
||||
| Storage buckets | audio, meeting documents, exports |
|
||||
| Teams | team invites, membership, roles, `team_activities` feed (`20260913000033`) |
|
||||
| Knowledge / RAG | `knowledge_documents`, `knowledge_chunks`, pgvector |
|
||||
| Notifications / push | push tokens, durable outbox |
|
||||
| Billing | Payple, Stripe, subscriptions, payment provider events/operations |
|
||||
| Admin | admin roles, audit log, atomic admin RPCs |
|
||||
| Mobile platform | mobile platform/monetization/runtime integrity |
|
||||
| Commands | atomic command reorder |
|
||||
| Devices | device registration + revocation |
|
||||
| Content reporting | report reasons, generation receipts |
|
||||
| Meetings | meeting documents |
|
||||
| STT quota | atomic quota reservations (00026) |
|
||||
| Ads | ad reward receipt replay protection (00028) |
|
||||
|
||||
Migration numbering referenced in SSOT goes up to `00028`; CI verifies `migration-up` + shadow replay.
|
||||
|
||||
### 1.2 Edge Functions (~27)
|
||||
|
||||
| Function | Purpose |
|
||||
|---|---|
|
||||
| `stt-proxy` | User STT gateway: auth, atomic quota reservation/refund, provider fallback, fail-closed |
|
||||
| `llm-proxy` | LLM gateway (Claude/OpenAI) |
|
||||
| `realtime-token` | OpenAI Realtime ephemeral token (tier-gated, session quota) |
|
||||
| `generate-meeting-document` | AI document generation (minutes/report/idea-note/mindmap) |
|
||||
| `embed-chunks` / `search-knowledge` | RAG embeddings + semantic search |
|
||||
| `content-report` | AI content reporting |
|
||||
| `team-invite` / `team-accept` | Team invitations |
|
||||
| `send-push` | Push delivery |
|
||||
| `account-delete` | Account deletion cascade + provider unlink |
|
||||
| `admin-users` / `admin-subscriptions` / `admin-payments` / `admin-audit-log` | Admin operations |
|
||||
| `billing-catalog` | Server pricing catalog |
|
||||
| `stripe-checkout` / `stripe-portal` / `stripe-webhook` | Stripe billing |
|
||||
| `payple-checkout` / `payple-manage` / `payple-renew` / `payple-webhook` | Payple billing (Korea) |
|
||||
| `iap-verify` | Google Play / App Store purchase verification |
|
||||
| `admob-ssv` | AdMob server-side verification + reward ledger |
|
||||
| `google-play-rtdn` | Play Real-time Developer Notifications |
|
||||
|
||||
Shared contracts in `functions/_shared/`: admin, auth, audit, cors, quota, payple, push, llm, stt, team, generation-receipt, google-play, pubsub, generative-ai-safety (+ `*.test.ts`).
|
||||
|
||||
### 1.3 Tests (`server/supabase/tests/`)
|
||||
|
||||
Integration/E2E: content-report red e2e, content-reporting (ps1/sql), mobile platform/recording/reward-race, payment provider, mobile release preflight, public mobile runtime, push claim/outbox, team push security, STT quota.
|
||||
|
||||
---
|
||||
|
||||
## 2. Cloudflare worker (`server/cloudflare-worker/`)
|
||||
|
||||
- `wrangler.toml` — worker `d3ro-voice-api`, compat 2024-04-01, `BACKEND_ORIGIN=http://192.168.0.39:5050`, optional custom domain route (commented).
|
||||
- `src/index.ts` — CORS preflight, `/worker-health`, forwards to backend origin with `X-Forwarded-*` / `X-D3RO-Edge-Proxy` headers.
|
||||
|
||||
Cloudflare Tunnel `kd-nas` maps public hostnames to NAS services.
|
||||
|
||||
---
|
||||
|
||||
## 3. Data model (product tables, high level)
|
||||
|
||||
Canonical product data lives in Supabase Postgres with RLS:
|
||||
|
||||
- **Identity:** `auth.users` + `profiles`, roles/claims, identity links.
|
||||
- **Content:** `history`, `meetings`, `meeting_memos`, `meeting_documents`, `memos`, `dictionary`, `commands`/instructions, `templates`.
|
||||
- **Knowledge:** `knowledge_documents`, `knowledge_chunks` (pgvector).
|
||||
- **Teams:** teams, members, invites, activity feed (`team_activities`, RPC-only writes, realtime-enabled).
|
||||
- **Delivery:** `devices`, `push_tokens`, push outbox.
|
||||
- **Monetization:** `subscriptions`, `payment_provider_events/operations`, `ad_reward_claims`, IAP receipts, generation receipts.
|
||||
- **Ops:** `audit_log` + admin operation records.
|
||||
- **Portability:** `portable_exports` (+ storage).
|
||||
|
||||
Shared TS types for these live in `packages/api-client` (SSOT).
|
||||
|
||||
---
|
||||
|
||||
## 4. Backend status summary
|
||||
|
||||
- Auth (email + Google/GitHub/Apple), RLS, storage, realtime: **implemented**; production Auth + Google provider entry verified GREEN; GitHub/Apple provider secrets and mobile consent callback pending (external).
|
||||
- STT/LLM proxies: **implemented** and fail-closed (no synthetic transcripts); atomic quota reservations verified with 20-way concurrency.
|
||||
- Billing (Stripe + Payple + IAP verify + webhooks/RTDN): **implemented**; live provider end-to-end and Payple webhook signature verification pending.
|
||||
- Ads (AdMob SSV, rewarded ledger, replay protection): **implemented** (Edge v13 ACTIVE); production AdMob serving blocked externally (review/serving limits/store link/payment profile).
|
||||
- Push: Supabase owns tokens/devices/outbox/retries. Transports implemented for **FCM, Web Push (VAPID + RFC 8291), and APNs (.p8 token)**; the Cloudflare Worker cron drains the outbox every minute. Android still requires FCM at the device. Details: `docs/deployment/push-transport-without-firebase.md`.
|
||||
- Content safety: generation receipts + `content-report` **implemented**.
|
||||
- Data portability (`account-delete`, export/restore): **implemented**.
|
||||
|
||||
External gates are enumerated in `docs/v3/MOBILE_APP_COMPLETION_SSOT.md` §0/§6 and mirrored in `11-gap-backlog.md` (`EXT-*`, `BE-*`).
|
||||
205
docs/map/10-feature-catalog.md
Normal file
205
docs/map/10-feature-catalog.md
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
# 10 — Feature Catalog (Feature Map)
|
||||
|
||||
> The canonical feature map. One row = one user-facing capability.
|
||||
> Status is per surface. Legend in [`00-index.md`](./00-index.md) §2.
|
||||
> Surfaces: D = desktop (`apps/desktop`), W = web (`apps/web`), M = mobile (`apps/mobile-rn`), B = backend (Supabase/.NET).
|
||||
|
||||
**How to use an ID:** cite it in commits, plans, and backlog. Example: "CAP-03 is `[~]` on mobile (external OAuth pending)".
|
||||
|
||||
Status quick-reference: `[x]` done+verified · `[~]` partial/unverified · `[ ]` planned/absent · `[!]` blocked externally · `[-]` N/A.
|
||||
|
||||
---
|
||||
|
||||
## CAP — Capture & Transcribe
|
||||
|
||||
| ID | Feature | D | W | M | B | Anchors / notes |
|
||||
|---|---|---|---|---|---|---|
|
||||
| CAP-01 | Push-to-talk dictation (hold/release) | [x] | [-] | [x] | [-] | Desktop `VoiceModeService`; mobile RecordScreen via app CTA/notification action (no global hotkey) |
|
||||
| CAP-02 | Hands-free toggle dictation | [x] | [-] | [x] | [-] | Desktop double-press; mobile toggle |
|
||||
| CAP-03 | Live partial transcript while recording | [x] | [ ] | [ ] | [-] | Desktop `voice:partialTranscript` + recording-tip |
|
||||
| CAP-04 | Recording waveform + level meter | [x] | [x] | [x] | [-] | Desktop 9-bar cos distribution; mobile audio level |
|
||||
| CAP-05 | Device/mic selection | [x] | [ ] | [~] | [-] | Desktop config; mobile uses system default |
|
||||
| CAP-06 | System/loopback audio capture | [x] | [-] | [ ] | [-] | Desktop only (caption source); mobile policy-limited |
|
||||
| CAP-07 | Local Whisper STT | [x] | [-] | [x] | [-] | Desktop sidecar; mobile on-device Whisper (supported devices) |
|
||||
| CAP-08 | Cloud STT (multi-provider) | [x] | [x] | [x] | [x] | Desktop 6 providers + D3RO Cloud; web/mobile via `stt-proxy`; .NET internal gateway |
|
||||
| CAP-09 | STT auto-fallback + fail-closed | [x] | [x] | [x] | [x] | `STTManager`; SSOT R-021/R-022 GREEN |
|
||||
| CAP-10 | STT model download/management UI | [x] | [-] | [~] | [-] | Desktop model manager + onboarding; mobile bundled model |
|
||||
| CAP-11 | File transcription (audio/video) | [x] | [ ] | [x] | [~] | Desktop ffmpeg chunking; mobile import picker; web deferred |
|
||||
| CAP-12 | Audio import from other apps (share intent) | [-] | [-] | [x] | [-] | Mobile Android `ACTION_SEND`/`ACTION_VIEW` (SSOT R-016 GREEN) |
|
||||
| CAP-13 | Live captions overlay | [x] | [-] | [-] | [-] | Desktop `CaptionService` + caption-overlay popup |
|
||||
| CAP-14 | Recording persistence / crash recovery | [x] | [ ] | [x] | [-] | Desktop WAV persist; mobile durable queue + process-kill WAV recovery |
|
||||
| CAP-15 | Android foreground recording service | [-] | [-] | [x] | [-] | Mobile API 34 FGS + persistent notification (SSOT R-005 GREEN) |
|
||||
|
||||
---
|
||||
|
||||
## AI — AI Processing
|
||||
|
||||
| ID | Feature | D | W | M | B | Anchors / notes |
|
||||
|---|---|---|---|---|---|---|
|
||||
| AI-01 | Local LLM (Ollama) | [x] | [-] | [ ] | [-] | Desktop bundled Ollama |
|
||||
| AI-02 | Cloud LLM (Claude/OpenAI) | [x] | [x] | [x] | [x] | Desktop `PremiumLLMService`; web/mobile via `llm-proxy`; .NET `LlmProxyService` |
|
||||
| AI-03 | Auto Polish (cleanup/filler removal) | [x] | [~] | [~] | [x] | Desktop built-in; web/mobile via commands |
|
||||
| AI-04 | Translate / summarize / rephrase | [x] | [x] | [x] | [x] | Built-in instructions |
|
||||
| AI-05 | Custom instructions (user commands) | [x] | [x] | [x] | [x] | Desktop `CommandsPage` (Red Team RT-03 verified); web `commands`; mobile `CommandsScreen` |
|
||||
| AI-06 | Voice keyword commands | [x] | [-] | [ ] | [-] | Desktop `VoiceCommandService` + command popup |
|
||||
| AI-07 | LLM Chains (multi-step pipelines) | [x] | [ ] | [ ] | [-] | Desktop `ChainService` |
|
||||
| AI-08 | Screen/context capture for prompts | [x] | [-] | [ ] | [-] | Desktop `ScreenContextService` |
|
||||
| AI-09 | Streaming responses | [x] | [x] | [x] | [x] | SSE/NDJSON streaming |
|
||||
| AI-10 | Dictation templates (voice form fill) | [x] | [ ] | [x] | [~] | Desktop `DictationTemplateService`; mobile `TemplatesScreen` |
|
||||
|
||||
---
|
||||
|
||||
## MEM — Memory & Knowledge
|
||||
|
||||
| ID | Feature | D | W | M | B | Anchors / notes |
|
||||
|---|---|---|---|---|---|---|
|
||||
| MEM-01 | History list + search | [x] | [x] | [x] | [x] | Desktop SQLite; web/mobile Supabase |
|
||||
| MEM-02 | History detail + edit | [x] | [x] | [x] | [x] | Mobile `HistoryDetailScreen` |
|
||||
| MEM-03 | History favorites | [x] | [x] | [x] | [x] | |
|
||||
| MEM-04 | History export / share | [x] | [~] | [x] | [x] | Desktop export; web limited; mobile share sheet |
|
||||
| MEM-05 | History audio playback | [x] | [x] | [x] | [x] | Signed URLs on web/mobile |
|
||||
| MEM-06 | Dictionary (custom vocabulary) | [x] | [x] | [x] | [x] | All surfaces CRUD; Desktop Red Team RT-02 & RT-18 fuzzed/verified |
|
||||
| MEM-07 | Dictionary import/export | [x] | [x] | [x] | [-] | Desktop `dictionary:import/export` JSON+CSV (file dialogs, `DictionaryService`); web `serializeDictionary`/`importDictionaryFile` + header buttons; mobile CSV/TXT export + CSV/JSON/TXT import via `data-portability` |
|
||||
| MEM-08 | Memos (tags over history) | [x] | [ ] | [x] | [x] | Desktop `MemoService`; mobile `MemosScreen`; web none |
|
||||
| MEM-09 | Knowledge base / RAG add+index | [x] | [x] | [x] | [x] | Desktop local RAG (DEF-008 infinite chunking loop resolved, RT-08 verified); web/mobile cloud RAG |
|
||||
| MEM-10 | Semantic search over knowledge | [x] | [x] | [x] | [x] | Web `KnowledgeSearch` calls `search-knowledge` (was mislabeled deferred); mobile + Edge `search-knowledge` |
|
||||
| MEM-11 | Knowledge file upload | [x] | [x] | [x] | [x] | Web `.txt`/`.md` picker + newline-aware chunking + `embed-chunks`; desktop txt/md/pdf/docx; mobile file picker |
|
||||
| MEM-12 | Voice actions (OS automation) | [x] | [x] | [x] | [x] | Desktop `VoiceActionService`; web `ActionRunner` (simulated); mobile `ActionsScreen` |
|
||||
| MEM-13 | Cross-surface data sync | [~] | [x] | [x] | [x] | Desktop Supabase sync (V2-4); web/mobile native |
|
||||
| MEM-14 | Memo tag search | [x] | [ ] | [x] | [x] | |
|
||||
|
||||
---
|
||||
|
||||
## MTG — Meetings
|
||||
|
||||
| ID | Feature | D | W | M | B | Anchors / notes |
|
||||
|---|---|---|---|---|---|---|
|
||||
| MTG-01 | Meeting recording + live transcript | [x] | [~] | [x] | [x] | Desktop `MeetingModeService`; web realtime view; mobile |
|
||||
| MTG-02 | Meeting creation (title/attendees/language/template) | [x] | [x] | [x] | [x] | SSOT H-006 GREEN |
|
||||
| MTG-03 | Timestamped memos during meeting | [x] | [x] | [x] | [x] | |
|
||||
| MTG-04 | AI summary generation | [x] | [x] | [~] | [x] | Desktop `MeetingSummaryService`; web `generate-document-button`; mobile via Edge |
|
||||
| MTG-05 | Document generation (minutes/report/idea-note/mindmap) | [x] | [x] | [x] | [x] | Edge `generate-meeting-document`; SSOT F-011 GREEN |
|
||||
| MTG-06 | Document edit (Markdown) | [x] | [x] | [x] | [x] | Desktop editor; web `document-editor` |
|
||||
| MTG-07 | Export PDF/DOCX/TXT/Markdown | [x] | [~] | [x] | [x] | Desktop `ExportMenu`; web markdown; mobile print/DOCX chooser (SSOT data portability GREEN) |
|
||||
| MTG-08 | Speaker diarization | [~] | [ ] | [ ] | [ ] | Desktop `phase-15.5` (LLM estimate + pyannote prep); mobile SSOT H-014 pending |
|
||||
| MTG-09 | Audio seek ↔ transcript timestamp | [ ] | [ ] | [ ] | [ ] | SSOT H-011 pending |
|
||||
| MTG-10 | Meeting list search/filter/sort | [~] | [ ] | [~] | [x] | Basic lists; advanced filters pending |
|
||||
| MTG-11 | Meeting AI chat over transcript | [x] | [ ] | [ ] | [x] | Desktop `MeetingChatPanel` + `MEETING_CHAT` |
|
||||
| MTG-12 | Content reporting for generated docs | [-] | [ ] | [x] | [x] | `content-report` Edge + generation receipts |
|
||||
|
||||
---
|
||||
|
||||
## CV — Conversation
|
||||
|
||||
| ID | Feature | D | W | M | B | Anchors / notes |
|
||||
|---|---|---|---|---|---|---|
|
||||
| CV-01 | Local duplex voice conversation (STT→LLM→TTS) | [x] | [ ] | [x] | [-] | Desktop `VoiceConversationService`; mobile Talk |
|
||||
| CV-02 | Realtime voice (OpenAI gpt-realtime, Premium) | [x] | [ ] | [ ] | [x] | Desktop `useRealtimeConversation` + `realtime-token` Edge |
|
||||
| CV-03 | Text AI chat | [x] | [x] | [x] | [x] | Desktop chat, web `chat-panel`, mobile `TalkScreen` |
|
||||
| CV-04 | TTS playback + controls | [x] | [ ] | [x] | [-] | Desktop SAPI/`say`; mobile Android TTS |
|
||||
| CV-05 | Voice selection / backend selection | [x] | [ ] | [~] | [-] | Desktop settings `conversationBackend` |
|
||||
|
||||
---
|
||||
|
||||
## ACC — Accounts, Sync, Devices, Portability
|
||||
|
||||
| ID | Feature | D | W | M | B | Anchors / notes |
|
||||
|---|---|---|---|---|---|---|
|
||||
| ACC-01 | Email sign-up/login | [ ] | [x] | [x] | [x] | Desktop uses separate online-auth; SSOT A-001..A-005 `[ ]` rows are mobile checklist granularity |
|
||||
| ACC-02 | OAuth Google | [~] | [x] | [~] | [x] | Mobile full consent→callback pending (external) |
|
||||
| ACC-03 | OAuth GitHub / Apple | [~] | [~] | [~] | [~] | GitHub/Apple provider secrets pending |
|
||||
| ACC-04 | Password reset / recovery deep link | [ ] | [ ] | [x] | [x] | Mobile ForgotPassword/UpdatePassword |
|
||||
| ACC-05 | Account profile / identity management | [~] | [~] | [x] | [x] | Desktop `LicenseTab`; mobile `AccountScreen` |
|
||||
| ACC-06 | Logout + local sensitive purge | [x] | [x] | [x] | [x] | Mobile central purge GREEN |
|
||||
| ACC-07 | Account deletion (server cascade + local purge) | [ ] | [ ] | [~] | [x] | `account-delete` Edge; mobile device E2E pending |
|
||||
| ACC-08 | Cloud sync (per-user data) | [x] | [x] | [x] | [x] | Desktop `CloudSyncService`; SSOT D-* largely `[ ]` granular |
|
||||
| ACC-09 | Device registration + revocation | [-] | [ ] | [x] | [x] | Mobile `DevicesScreen` |
|
||||
| ACC-10 | Offline queue + retry | [~] | [ ] | [x] | [x] | Mobile durable queue |
|
||||
| ACC-11 | Data export/import (portability) | [~] | [ ] | [x] | [x] | Mobile canonical JSON E2E GREEN; desktop has export files |
|
||||
| ACC-12 | Notification / push | [ ] | [~] | [~] | [x] | Backend transports for FCM + Web Push (VAPID) + APNs (.p8) + outbox cron drain implemented. Web/mobile client registration for webpush/apns still pending; Android delivery needs FCM project. |
|
||||
|
||||
---
|
||||
|
||||
## TEAM — Teams & Admin
|
||||
|
||||
| ID | Feature | D | W | M | B | Anchors / notes |
|
||||
|---|---|---|---|---|---|---|
|
||||
| TEAM-01 | Team create / rename / delete | [-] | [x] | [x] | [x] | Desktop N/A |
|
||||
| TEAM-02 | Invite by email / link + accept deep link | [-] | [x] | [x] | [x] | `team-invite`/`team-accept` |
|
||||
| TEAM-03 | Members + roles (admin/member/viewer) + leave | [-] | [x] | [x] | [x] | |
|
||||
| TEAM-04 | Team meetings/docs sharing + RLS isolation | [-] | [x] | [~] | [x] | Cross-user isolation tested |
|
||||
| TEAM-05 | Team comments / activity feed | [-] | [x] | [x] | [x] | `team_activities` migration + `create_team_activity` RPC + realtime; web `ActivityFeed`, mobile TeamDetail activity card (2026-09-13) |
|
||||
| TEAM-06 | Admin back office (users/subs/models/usage/audit) | [-] | [-] | [x] | [x] | `apps/admin` + mobile `AdminScreen` |
|
||||
| TEAM-07 | Role-based destructive action confirm + audit | [-] | [x] | [x] | [x] | SSOT T-006..T-008 GREEN |
|
||||
| TEAM-08 | Desktop admin surface | [ ] | [-] | [-] | [-] | None; N/A by design |
|
||||
|
||||
---
|
||||
|
||||
## MON — Monetization & Ads
|
||||
|
||||
| ID | Feature | D | W | M | B | Anchors / notes |
|
||||
|---|---|---|---|---|---|---|
|
||||
| MON-01 | Tier gating (Free/Pro/Pro+/Team/Enterprise) | [x] | [x] | [x] | [x] | `LicenseService`, entitlement provider |
|
||||
| MON-02 | Usage quotas (daily_usage) | [x] | [x] | [x] | [x] | |
|
||||
| MON-03 | Desktop offline license (Ed25519) | [x] | [-] | [-] | [x] | `crypto-license` + admin issuer |
|
||||
| MON-04 | Web checkout (Stripe) | [-] | [x] | [~] | [x] | Stripe checkout/portal/webhook |
|
||||
| MON-05 | Web checkout (Payple) | [-] | [x] | [~] | [~] | Payple checkout/manage/renew/webhook; webhook signature pending |
|
||||
| MON-06 | Paywall / upgrade prompts | [x] | [x] | [x] | [x] | `UpgradePromptModal`, `ProPaywallScreen` |
|
||||
| MON-07 | Mobile IAP purchase + restore | [-] | [-] | [~] | [x] | `iap-verify` + `billing-context`; live store E2E blocked |
|
||||
| MON-08 | Billing catalog / pricing display | [x] | [x] | [x] | [x] | Server catalog SSOT; hardcoded prices removed |
|
||||
| MON-09 | Free-tier banner ads | [~] | [-] | [x] | [x] | Desktop adapters fail-closed; mobile AdMob test GREEN, prod serving blocked |
|
||||
| MON-10 | Rewarded ads → quota credits | [~] | [-] | [x] | [x] | Desktop `RewardedQuotaModal` (stub adapters); mobile SSV GREEN |
|
||||
| MON-11 | Ad mediation engine + settlement | [~] | [-] | [~] | [x] | Engine + settlement built. `DirectHouseSponsorAdapter` is now a **real configurable REST adapter** (bid/impression/click/reward via `endpointUrl`, fail-closed when unconfigured, unit-tested). Other 9 networks remain `UnavailableAdAdapter` stubs pending official SDKs. |
|
||||
| MON-12 | Subscription management (portal/store) | [-] | [x] | [x] | [x] | Stripe portal / Payple manage / Play manage |
|
||||
|
||||
---
|
||||
|
||||
## SHELL — Platform Shell, Settings, Onboarding, Support
|
||||
|
||||
| ID | Feature | D | W | M | B | Anchors / notes |
|
||||
|---|---|---|---|---|---|---|
|
||||
| SHELL-01 | Settings / preferences | [x] | [~] | [x] | [x] | Desktop tabbed modal; web theme/i18n; mobile `SettingsScreen` |
|
||||
| SHELL-02 | Theme system (6 themes) | [x] | [x] | [x] | [-] | `theme.ts` SSOT |
|
||||
| SHELL-03 | i18n (12 locales) | [x] | [x] | [x] | [-] | `@d3ro/i18n`; ko/en fully translated, others partial |
|
||||
| SHELL-04 | Onboarding / first-run | [x] | [ ] | [x] | [-] | Desktop model bootstrap; mobile audience/theme/locale |
|
||||
| SHELL-05 | Accessibility / reduced motion | [~] | [~] | [~] | [-] | Desktop reduced-motion honored; mobile a11y rows pending |
|
||||
| SHELL-06 | System tray / background | [x] | [-] | [-] | [-] | Desktop tray |
|
||||
| SHELL-07 | Auto-launch on login | [x] | [-] | [-] | [-] | Desktop only |
|
||||
| SHELL-08 | Auto-update | [x] | [-] | [!] | [-] | Desktop electron-updater; Forgejo canonical feed; channels + mandatory/major-vs-delta policy (`release/update-policy.json`); mobile store updates |
|
||||
| SHELL-09 | Support / diagnostics | [x] | [ ] | [ ] | [~] | Desktop `SupportModal`; admin `/support` stub |
|
||||
| SHELL-10 | Download center / releases | [-] | [x] | [-] | [x] | Web `/download`, admin `/releases`, Forgejo |
|
||||
| SHELL-11 | Landing site / legal pages | [-] | [-] | [-] | [-] | `site/` — privacy/terms/delete-account live |
|
||||
| SHELL-12 | Notifications (in-app / desktop) | [x] | [ ] | [x] | [x] | Desktop events; mobile push |
|
||||
|
||||
---
|
||||
|
||||
## INFRA — Build, CI, Release, Quality
|
||||
|
||||
| ID | Feature | Status | Anchors |
|
||||
|---|---|---|---|
|
||||
| INFRA-01 | Monorepo + workspaces + turbo | [x] | `package.json`, `turbo.json` |
|
||||
| INFRA-14 | Unified entitlement resolver (`@d3ro/core/entitlement`) | [x] | `EntitlementSnapshot` + `resolveEntitlement` map Supabase/desktop-license/.NET sources to one contract; desktop `isPro` fixed, `syncFromCloud` normalized; mobile/web adoption incremental (see `11` GAP-ID-02) |
|
||||
| INFRA-02 | Shared packages | [x] | `packages/*` |
|
||||
| INFRA-03 | Desktop build + signed packaging | [x] | `electron-builder.yml`, GitLab `package-windows/macos` |
|
||||
| INFRA-04 | Mobile CI (debug/E2E/release) | [~] | `.github/workflows/ci.yml`, `.gitlab-ci.yml`; production AAB external |
|
||||
| INFRA-05 | .NET API tests | [x] | `apps/api-server.Tests` |
|
||||
| INFRA-06 | Edge function tests (Deno) | [x] | `server/supabase/functions`, `tests/` |
|
||||
| INFRA-07 | E2E desktop (playwright) | [x] | `apps/desktop/tests`, `apps/desktop/playwright.config.ts` |
|
||||
| INFRA-08 | E2E web (playwright) | [x] | `apps/web/e2e` |
|
||||
| INFRA-09 | E2E mobile (Maestro + instrumentation) | [~] | `.maestro/`, `androidTest`; emulator API 35 gate in CI |
|
||||
| INFRA-10 | Secret scanning / release boundaries | [x] | `scripts/ci/check-no-hardcoded-secrets.mjs`, `verify-mobile-release-*.mjs` |
|
||||
| INFRA-11 | Docker + NAS deploy | [x] | `docker-compose.nas.yml`, `scripts/deploy-nas.*` |
|
||||
| INFRA-12 | Cloudflare edge + tunnel | [x] | `server/cloudflare-worker`, Cloudflare Tunnel `kd-nas` |
|
||||
| INFRA-13 | Site deploy (Cloudflare Pages + GitHub Pages) | [x] | `.forgejo/workflows/deploy-site.yml`, `.github/workflows/deploy-site.yml` |
|
||||
| INFRA-15 | Update & release system | [x] | Canonical Forgejo feed + channels/policy (`release/update-policy.json`, `src/main/update-policy.ts`), canonical publisher `scripts/ci/publish-forgejo-release.mjs`, legacy GitLab mirror; `npm run release:metadata:test`. v1.1.0 published to Forgejo & official download centers active on web (`/download`, `/releases`) and site (`#download`). |
|
||||
|
||||
---
|
||||
|
||||
## Coverage summary (by surface)
|
||||
|
||||
| Surface | `[x]` | `[~]` | `[ ]` | Notable strength | Notable weakness |
|
||||
|---|---|---|---|---|---|
|
||||
| Desktop | ~40 | 3 | ~8 | Local AI pipeline, meetings, RAG, conversation, hotkeys | Ads stubs, no team admin, no email account |
|
||||
| Web | ~22 | 6 | ~14 | Server-shared data UX, billing, meetings, teams | No local AI, limited knowledge upload/search |
|
||||
| Mobile | ~40 | 12 | ~18 | Cloud + native recording, portability, admin, IAP/ads | External store/console gates, a11y, deep E2E pending |
|
||||
| Backend | ~45 | 6 | ~4 | RLS, Edge functions, billing, fail-closed AI | Payple webhook signature, some external provider keys |
|
||||
135
docs/map/11-gap-backlog.md
Normal file
135
docs/map/11-gap-backlog.md
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
# 11 — Gap & Backlog Register
|
||||
|
||||
> The maintained list of what is **under-developed, deferred, or externally blocked**.
|
||||
> Status: living document. Every feature change updates this file (see [`12-update-protocol.md`](./12-update-protocol.md)).
|
||||
> External items are marked `EXT`; they block "done" but must not block code, tests, or local fixtures.
|
||||
|
||||
Legend: `[ ]` open · `[~]` in progress · `[!]` blocked externally · `[x]` resolved (keep for one cycle, then prune).
|
||||
|
||||
---
|
||||
|
||||
## 0. How to read this
|
||||
|
||||
- An item here is **not** a failure. It is a known state with an owner and a next step.
|
||||
- When you close an item, flip it to `[x]`, add the date + evidence path, and also update `10-feature-catalog.md`.
|
||||
- Grandfathered detail lives in `docs/v3/MOBILE_APP_COMPLETION_SSOT.md`; this file is the cross-surface roll-up. When the two disagree, the SSOT wins for mobile and must be reconciled here.
|
||||
|
||||
---
|
||||
|
||||
## 1. High impact — real capability gaps (no external blocker)
|
||||
|
||||
| ID | Area | Gap | Evidence | Suggested next step |
|
||||
|---|---|---|---|---|
|
||||
| GAP-QA-01 | Quality | Extreme Red Team: headful end-to-end bug hunting across real desktop Electron, Web Next.js, and CI pipelines. | `red_team_log.md`, `tests/e2e/red_team_cycle*.spec.ts`, `apps/web/e2e/red_team_cycle4_web.spec.ts` | `[x]` 2026-09-15: 18 scenarios executed, 14 defects caught and 100% resolved (infinite chunking loop DEF-008, IPC signature mismatch DEF-004, markdown editor typing rollback DEF-006, Web RSC Link serialization DEF-012, secret scanner lookahead DEF-013, etc.). All 18 scenarios GREEN with zero regressions. |
|
||||
| GAP-REL-01 | Release | Official v1.1.0 release publication to Forgejo and active public download center deployment. | `scripts/ci/publish-forgejo-release.mjs`, `apps/web/src/app/download/page.tsx`, `site/src/sections/Download.tsx`, `apps/web/e2e/red_team_cycle4_web.spec.ts` | `[x]` 2026-09-15: v1.1.0 release assets (`D3RO-Voice-Setup-1.1.0-x64.exe`, `.blockmap`, `latest.yml`, `update-policy.json`) published to canonical Forgejo registry and release hub. Public download centers in `apps/web` (`/download`, `/releases`) and `site` (`#download`) activated with direct 1.1.0 installer download, SHA-256 verification, and mirror links. Playwright E2E tests verified GREEN. |
|
||||
| GAP-ADS-01 | Ads | 9 of 10 desktop ad adapters still extend `UnavailableAdAdapter` (`provider_not_integrated`). | `apps/desktop/src/main/services/ads/*` | `[~]` 2026-09-13: `DirectHouseSponsorAdapter` is now a real configurable REST adapter (bid/impression/click/reward via `endpointUrl`; fail-closed when unconfigured; 22 unit tests GREEN). Remaining 9 need official SDKs/authenticated endpoints. |
|
||||
| GAP-ADS-02 | Ads | Desktop mediation reward accounting is not wired to license quota (`claimReward` still returns no tokens). | `AdMediationEngine.ts`, `AppLayout.tsx` | Wire verified `reportRewardCompletion` to `LicenseService` quota after the direct sponsor endpoint exists. |
|
||||
| GAP-ID-01 | Identity | Supabase, .NET JWT/SQLite, and the desktop offline license each had their own tier/role shape. | `@d3ro/core/entitlement`, `LicenseService`, `entitlement-context` | `[~]` 2026-09-13: canonical `EntitlementSnapshot` + `resolveEntitlement` added with tests; desktop tier normalization + `isPro` fixed. Full adoption tracked as GAP-ID-02. |
|
||||
| GAP-ID-02 | Identity | Web and mobile still hand-roll tier/role normalization instead of consuming the canonical resolver; .NET identity is still a separate store. | `apps/web/src/lib`, `apps/mobile-rn/src/lib/entitlement-context.tsx` | Adopt `resolveEntitlement` in web/mobile; decide whether to retire the .NET user store or keep explicit mapping. |
|
||||
| GAP-TEAM-01 | Teams | Team comments / activity feed was not implemented. | `server/supabase/migrations/20260913000033_team_activities.sql`, web `activity-feed.tsx`, mobile `team-service.ts` | `[x]` 2026-09-13: `team_activities` table + `create_team_activity` RPC + RLS + realtime publication; web + mobile UI. |
|
||||
| GAP-MEM-01 | Knowledge | Web file upload was deferred and semantic search was mislabeled future. | `apps/web/src/components/knowledge/*` | `[x]` 2026-09-13: `.txt`/`.md` picker, newline-aware chunking, `embed-chunks` on submit, `search-knowledge` confirmed live. |
|
||||
| GAP-MEM-02 | Dictionary | No dictionary import/export on any surface. | catalog MEM-07 | `[x]` 2026-09-13: desktop `dictionary:import/export` (JSON/CSV), web serialize/parse + download/upload, mobile via `data-portability`; 8 new unit tests. |
|
||||
| GAP-MTG-01 | Meetings | Audio seek ↔ transcript timestamp sync missing. | SSOT H-011 | Store segment timestamps; wire player seek. |
|
||||
| GAP-MTG-02 | Meetings | Speaker diarization only partially done on desktop; absent web/mobile. | `docs/phases/phase-15.5-speaker-diarization.md`, SSOT H-014 | Finish desktop pyannote path; expose speaker labels cross-surface. |
|
||||
| GAP-INFRA-01 | Build | `apps/mobile-rn` is outside npm workspaces, so root `typecheck`/`test`/`lint` skip it. `typecheck:mobile`/`lint:mobile`/`test:mobile`/`verify:all` root scripts added 2026-09-13 (`package.json`), but membership/CI integration is still open. | `package.json` | Decide: add mobile to workspaces, or wire `verify:all` into CI. |
|
||||
| GAP-MOB-01 | Legacy | `apps/mobile` Expo skeleton duplicated auth/data code and got version-sync edits. | SSOT G-002 | `[x]` 2026-09-13: deleted `apps/mobile`, removed from `sync-version.mjs` and `package-lock.json`; `version:check` GREEN. |
|
||||
| GAP-INFRA-02 | CI | GitLab admin NAS deploy job is disabled; admin deploy is manual/GHCR. | `.gitlab-ci.yml` (admin job comments) | Re-enable with a protected environment, or document the manual runbook as canonical. |
|
||||
| GAP-INFRA-03 | Release | Desktop auto-update was single-channel and pointed at GitLab while the public hub was Forgejo; no channel, mandatory-update, major-vs-delta, staging, or kill-switch policy. | `apps/desktop/src/main/update-feed.ts`, `electron-builder.yml`, `.forgejo/workflows` | `[x]` 2026-09-13: canonical Forgejo feed + legacy GitLab mirror, `release/update-policy.json` + runtime policy, `publish-forgejo-release.mjs` + Forgejo release workflow, 21 policy tests, verifier self-test 13 cases. See `docs/deployment/update-system-assessment.md`. |
|
||||
| GAP-INFRA-04 | Quality | Desktop `typecheck` is a no-op: `tsconfig.json` is `files: []` + references, so `tsc --noEmit` checks nothing. Real `tsc -p tsconfig.node.json --noEmit` surfaces many pre-existing errors. | `apps/desktop/package.json`, `apps/desktop/tsconfig.json` | Switch to `tsc -b` (or per-project `-p`) and clear the existing errors in a dedicated workstream; do not treat "typecheck GREEN" as evidence until then. |
|
||||
| GAP-SHELL-01 | Support | Admin `/support` is a stub panel; desktop-only `SupportModal`. No shared ticket contract. | `apps/admin/src/app/(admin)/support/page.tsx` | Define a ticket/diagnostics contract or keep stub and mark N/A in catalog. |
|
||||
| GAP-PUSH-01 | Push | `send-push` accepted `webpush`/`apns` but marked them `push_provider_not_supported`. | `_shared/webpush.ts`, `_shared/apns.ts`, `send-push/index.ts` | `[x]` 2026-09-13: VAPID Web Push (RFC 8291) + APNs `.p8` transports implemented and routed; 10 new tests incl. an encryption round-trip. Client registration for those providers still pending (see GAP-PUSH-03). |
|
||||
| GAP-PUSH-02 | Push | Nothing triggered `send-push?mode=drain`; enqueued notifications never left the outbox. | `server/cloudflare-worker/src/push-drain.ts`, `wrangler.toml` | `[x]` 2026-09-13: Cloudflare Cron Trigger (`* * * * *`) drains the outbox; tests in CI. Requires `SUPABASE_URL` + `SUPABASE_SERVICE_ROLE_KEY` secret on the worker. |
|
||||
| GAP-PUSH-03 | Push | Mobile/web clients register only `fcm`; no service worker subscription or APNs device token. | `apps/mobile-rn/src/features/notifications/*`, `apps/web` | Add web service worker + `pushManager.subscribe` (store JSON subscription) and iOS APNs token registration. |
|
||||
| GAP-PUSH-04 | Push | Android still depends on FCM (`google-services.json`). | `apps/mobile-rn/android`, `send-push` | Decide: minimal Firebase project, or UnifiedPush/ntfy. See `docs/deployment/push-transport-without-firebase.md`. |
|
||||
|
||||
---
|
||||
|
||||
## 2. Mobile checklist roll-up (from `MOBILE_APP_COMPLETION_SSOT.md` §4)
|
||||
|
||||
These are the mobile SSOT rows still `[ ]` / `[~]`. Do not duplicate the full text here; open the SSOT for detail.
|
||||
|
||||
| Group | Open rows | Theme |
|
||||
|---|---|---|
|
||||
| G (governance) | G-002, G-006, G-007, G-008, G-009, G-010, G-011 | Type/error/identity consolidation, legacy bundle separation, credential rotation |
|
||||
| A (auth/account) | A-001..A-013, A-018; A-014..A-017 `[~]` | Session restore, signup, deep links, OAuth, profile, provider E2E |
|
||||
| O (onboarding/a11y) | O-001..O-012 | Onboarding branches, permissions, tutorial, a11y, full ko/en |
|
||||
| D (data/sync/offline) | D-001..D-014 | Schema/RLS, devices, cross-surface read/write, offline queue, conflict policy |
|
||||
| R (record/transcribe) | R-001..R-009, R-011..R-015, R-017..R-020; R-016 `[x]` | Permissions, recorder, FGS, upload queue, job state, sharing |
|
||||
| H (history/meetings) | H-001..H-005, H-007..H-015; H-006 `[x]` | Pagination, filters, detail, meeting timeline, docs, diarization, cross-app |
|
||||
| F (feature parity) | F-001..F-010, F-013, F-014; F-011/F-012 `[x]` | Dashboard, dictionary, commands, actions, chat, conversation, knowledge |
|
||||
| T (teams/admin/notify) | T-001..T-005, T-009..T-012; T-006..T-008, T-013 `[x]` | Team CRUD/roles, push delivery/deep links, notification settings |
|
||||
| M (monetization) | M-025, M-027; M-013 `[~]` | Play Billing license test, Payple webhook signature |
|
||||
| Q (quality/release) | Q-012..Q-014, Q-019..Q-022, Q-026; Q-010/Q-011/Q-023/Q-027/Q-028 `[~]` | Emulator scripts, OAuth E2E, billing E2E, visual/a11y gates, env unification, production AAB |
|
||||
|
||||
---
|
||||
|
||||
## 3. External blockers (`EXT`) — require action outside the repo
|
||||
|
||||
| ID | Blocker | What is needed | Where tracked |
|
||||
|---|---|---|---|
|
||||
| EXT-FIREBASE-01 | No production Firebase project | Android FCM only; web/iOS can avoid Firebase (see push transport doc). Create project + Android app + Play fingerprint + FCM, or adopt UnifiedPush for Android. | SSOT EXT-011, `docs/deployment/push-transport-without-firebase.md` |
|
||||
| EXT-ADMOB-01 | AdMob `검토 필요` / `광고 게재 제한` / store not linked / payment profile incomplete | Complete console review + store link + payment profile. Playwright tooling ready: `scripts/admob-login.mjs` (one interactive login on a visible desktop) then `scripts/admob-automate.mjs --apply` creates/verifies units and reports store link. Neither persisted profile is signed in yet. | SSOT §0, EXT-006 |
|
||||
| EXT-PLAY-01 | Play Billing license tester + test payment method | Configure license testers | SSOT EXT-004 |
|
||||
| EXT-PLAY-02 | Play product/offer/base-plan + tracks | Create Pro/Pro+ products and tracks | SSOT EXT-003 |
|
||||
| EXT-PLAY-03 | Production AAB + CI secret injection + recovery backups | Inject Firebase/AdMob/signing/evidence CI secrets | SSOT EXT-008 |
|
||||
| EXT-PLAY-04 | Closed test 0/12 members, 14 days; production access disabled | Run closed test, request production | SSOT EXT-010 |
|
||||
| EXT-OAUTH-01 | GitHub/Apple provider secrets; real mobile Google consent→callback | Configure providers, verify consent | SSOT EXT-001 |
|
||||
| EXT-APPSIGN-01 | Live App Links still old certificate | Deploy updated `assetlinks.json`, re-verify live | SSOT App Links row |
|
||||
| EXT-PHYS-01 | Physical Fold6 install/OAuth/purchase evidence | User runs the artifact on device | SSOT EXT-009 |
|
||||
| EXT-PAY-01 | Payple live history + webhook signature verification | Provider contract + signature scheme | SSOT M-027 |
|
||||
| EXT-STRIPE-01 | Production Stripe/Payple cross-verification | Live payment E2E | SSOT M-013 |
|
||||
| EXT-STT-01 | Production provider keys (Groq/OpenAI/Deepgram/Gemini) | Inject provider secrets | `apps/api-server/Program.cs` env docs |
|
||||
|
||||
---
|
||||
|
||||
## 4. Documentation & drift watch
|
||||
|
||||
| ID | Item | Note |
|
||||
|---|---|---|
|
||||
| DOC-01 | `CLAUDE.md` describes only Phase 1-15.5 desktop; does not mention web/mobile/admin/api-server. | This map supersedes it for IA; consider trimming CLAUDE.md to rules + map pointer. |
|
||||
| DOC-02 | `docs/design/*` reflects an older desktop-only architecture and contains known naming drift (`06-gap-analysis.md`). | Treat this map + code as current; design docs are historical. |
|
||||
| DOC-03 | `memory/project_status.md` is a chronological log, not current state. | Use `docs/map/*` for current state. |
|
||||
| DOC-04 | `docs/v2/00-v2-master-plan.md` targets Expo for mobile. | Actual mobile is RN CLI (`apps/mobile-rn`); the Expo app was removed 2026-09-13. v2 plan is historical. |
|
||||
| DOC-05 | This map itself must be regenerated after large refactors. | See update protocol. |
|
||||
|
||||
---
|
||||
|
||||
## 5. Quick "is X done?" lookup
|
||||
|
||||
- **Desktop local dictation / LLM / history / meetings / RAG / conversation:** yes, tested. Ads: one real adapter, rest stubs.
|
||||
- **Web console:** yes, feature-complete for server-shared data; knowledge upload/search and team feed implemented.
|
||||
- **Mobile:** code complete for most flows and tested locally; blocked mainly by external store/console gates, plus a11y and some E2E depth.
|
||||
- **Backend:** fail-closed AI proxies, RLS, billing, ads SSV implemented; push transports (FCM + webpush + APNs) and cron drain implemented.
|
||||
- **Admin:** complete with deliberate "unavailable" states; support page is a stub.
|
||||
|
||||
---
|
||||
|
||||
## 6. Immediate TODO — push transports, drain, AdMob (2026-09-13)
|
||||
|
||||
Actionable checklist for the work started this session. Fields to fill are blank in
|
||||
`.env` (git-ignored) and mirrored in `.env.example`.
|
||||
|
||||
**Push — server (code done, config pending)**
|
||||
- [ ] Set Supabase Edge secrets for the transports you deploy: `WEBPUSH_VAPID_PUBLIC_KEY`, `WEBPUSH_VAPID_PRIVATE_KEY`, `WEBPUSH_SUBJECT` (web); `APNS_KEY_ID`, `APNS_TEAM_ID`, `APNS_PRIVATE_KEY`, `APNS_TOPIC`, `APNS_ENVIRONMENT` (iOS); `FCM_SERVICE_ACCOUNT_JSON`, `FCM_PROJECT_ID` (Android).
|
||||
- [ ] Deploy the updated `send-push` (`supabase functions deploy send-push`).
|
||||
- [ ] Generate a VAPID keypair (P-256) and store the private/public pair; subject must be `mailto:` or `https:`.
|
||||
- [ ] Create the APNs `.p8` key in the Apple Developer portal and record Key ID + Team ID.
|
||||
|
||||
**Push — Cloudflare cron drain**
|
||||
- [ ] Set worker vars: `SUPABASE_URL` (`wrangler secret`/`[vars]`) and batch limit.
|
||||
- [ ] Set worker secret: `wrangler secret put SUPABASE_SERVICE_ROLE_KEY`.
|
||||
- [ ] `wrangler deploy` from `server/cloudflare-worker` and confirm the `scheduled` runs (Cloudflare dashboard → Cron Triggers).
|
||||
- [ ] Verify end-to-end: enqueue a test event (e.g. team invite) → drain → delivery row `delivered`.
|
||||
|
||||
**Push — clients**
|
||||
- [ ] Web: add a service worker + `pushManager.subscribe`, store the JSON subscription as the registration id, register `provider: 'webpush'`. (GAP-PUSH-03)
|
||||
- [ ] iOS: register the APNs device token with `provider: 'apns'`. (GAP-PUSH-03)
|
||||
- [ ] Android: decide FCM vs UnifiedPush/ntfy. (GAP-PUSH-04)
|
||||
|
||||
**AdMob (Playwright tooling ready)**
|
||||
- [ ] Run `run-admob-login.bat` (or `node scripts/admob-login.mjs`) once on a visible desktop to persist the Google session.
|
||||
- [ ] Run `node scripts/admob-automate.mjs --apply` to create/verify the banner + rewarded units and report the Play-store link.
|
||||
- [ ] Complete AdMob console gates externally: review, serving limits, store link, payment profile. (EXT-ADMOB-01)
|
||||
|
||||
**Docs**
|
||||
- [ ] Keep `docs/deployment/push-transport-without-firebase.md` and this file in sync when transports or clients change.
|
||||
105
docs/map/12-update-protocol.md
Normal file
105
docs/map/12-update-protocol.md
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# 12 — Map Update Protocol (Mandatory)
|
||||
|
||||
> This is not optional. If a change alters what the product can do, which
|
||||
> infrastructure exists, or how developed something is, the map must be updated
|
||||
> **in the same unit of work**. A feature is not "done" until the map reflects it.
|
||||
>
|
||||
> The agent obligation is stated in [`../../AGENTS.md`](../../AGENTS.md).
|
||||
|
||||
---
|
||||
|
||||
## 1. The rule in one line
|
||||
|
||||
> **Feature change ⇒ map change, in the same commit / PR.**
|
||||
|
||||
No feature work is complete if `docs/map/10-feature-catalog.md` (and, when relevant,
|
||||
`docs/map/11-gap-backlog.md`) is stale.
|
||||
|
||||
---
|
||||
|
||||
## 2. When to trigger an update
|
||||
|
||||
Trigger on any of these events:
|
||||
|
||||
| Event | Must update |
|
||||
|---|---|
|
||||
| **New feature** added on any surface | Feature catalog row (`10`), surface doc (`04`–`09`) if infra changed, remove matching backlog row (`11`) |
|
||||
| **Feature changed** (behavior, platform coverage, tier, provider) | Feature catalog status/notes, surface doc if interfaces changed |
|
||||
| **Feature deleted / de-scoped** | Flip catalog row to reflect removal (delete row or mark `[-]` with reason), surface doc cleanup, note in `11` §4 if documentation moved |
|
||||
| **Feature deferred to backlog** | Add row to `11-gap-backlog.md` (§1–3) and mark catalog `[ ]` |
|
||||
| **Backlog item resolved** | Flip `11` row to `[x]` with date + evidence, update catalog to `[x]`, prune after one cycle |
|
||||
| **External blocker cleared** | Flip `EXT-*` to `[x]` with evidence, update the affected catalog rows |
|
||||
| **New app / package / service / Edge Function / CI workflow** | `02-infrastructure.md` and the relevant surface doc (`04`–`09`) |
|
||||
| **Version bump** (`release/product-version.json`) | `00-index.md` header "Last full audit", `02` §9 |
|
||||
| **Surface architecture change** (new IPC group, new route, new provider) | Surface doc + `03-shared-packages.md` if shared |
|
||||
|
||||
---
|
||||
|
||||
## 3. The update checklist
|
||||
|
||||
Run this before declaring any feature task complete:
|
||||
|
||||
1. **Locate the feature** in `10-feature-catalog.md`. If it has no ID, add a row with a new ID in the right domain (`CAP/AI/MEM/MTG/CV/ACC/TEAM/MON/SHELL/INFRA`).
|
||||
2. **Set status per surface** (`D/W/M/B`) using the legend (`00-index.md` §2). Status is per platform, not global.
|
||||
3. **Add file anchors** in the row notes (short `path:line` where useful) so the next agent can verify.
|
||||
4. **Update the surface doc** (`04`–`09`) if you added/removed a service, route, screen, IPC channel, table, or function.
|
||||
5. **Update `02-infrastructure.md`** if you touched build, CI, Docker, deploy, scripts, or release identity.
|
||||
6. **Update `11-gap-backlog.md`**:
|
||||
- Closing an open gap → `[x]` + date + evidence path.
|
||||
- Creating a newly deferred item → new row with ID, gap, evidence, next step.
|
||||
- Clearing external blocker → `[x]` + evidence.
|
||||
7. **Reconcile with the mobile SSOT** if the change touches mobile: `docs/v3/MOBILE_APP_COMPLETION_SSOT.md` remains authoritative for mobile checklist rows. If the SSOT and this map disagree, fix the SSOT first, then this map.
|
||||
8. **Bump the header**: update `00-index.md` "Last full audit" date only for a full re-audit; for incremental changes update the per-file `> Last updated` line if you add one.
|
||||
9. **Commit the docs with the code** (same commit or same PR), with a clear message.
|
||||
|
||||
---
|
||||
|
||||
## 4. Status semantics (do not abuse)
|
||||
|
||||
| Status | Requires |
|
||||
|---|---|
|
||||
| `[x]` | Code exists **and** is verified (tests/evidence in repo or an evidenced manual run recorded in the map/SSOT). |
|
||||
| `[~]` | Code exists but is partial, unverified, or blocked. Say *what* is missing in the notes. |
|
||||
| `[ ]` | Planned or absent. If planned, ensure a `11` backlog row exists. |
|
||||
| `[!]` | Code is done but "done" is blocked by something outside the repo. Name the external gate. |
|
||||
| `[-]` | Genuinely N/A for that surface. Add a one-line reason. |
|
||||
|
||||
Never mark `[x]` to reflect "typecheck passed" alone. Typecheck ≠ runtime ≠ verified feature.
|
||||
|
||||
---
|
||||
|
||||
## 5. Ownership & cadence
|
||||
|
||||
- **Every feature task** updates its own rows (no batching).
|
||||
- **Every refactor wave / phase close** triggers a reconcile pass over `10` and `11`.
|
||||
- **Weekly or per-release** do a light sweep: scan for rows whose status no longer matches code; fix drift.
|
||||
- **Per release** (`release/product-version.json` bump) do a full re-audit of `02`, `09`, and the header dates.
|
||||
|
||||
---
|
||||
|
||||
## 6. Anti-drift rules
|
||||
|
||||
- Do not create a second feature list elsewhere. This catalog is the SSOT for "what exists and how done".
|
||||
- Do not describe status in prose only. Use the tables and the legend.
|
||||
- Do not leave a `[~]`/`[!]` row without a note explaining the remaining work.
|
||||
- Do not add a feature to the product without adding it here.
|
||||
- If you genuinely cannot determine status, mark `[~]` and add a backlog row "verify status of X" rather than guessing or leaving it blank.
|
||||
|
||||
---
|
||||
|
||||
## 7. Quick templates
|
||||
|
||||
**New feature row (catalog):**
|
||||
```
|
||||
| CAP-16 | Feature name | [x] | [ ] | [~] | [x] | short anchors; what's partial |
|
||||
```
|
||||
|
||||
**New gap row (backlog §1):**
|
||||
```
|
||||
| GAP-<AREA>-NN | Area | What's missing | file anchors | Suggested next step |
|
||||
```
|
||||
|
||||
**New external blocker (backlog §3):**
|
||||
```
|
||||
| EXT-<SYSTEM>-NN | Blocker | What is needed | where tracked |
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue