d3ro-voice/docs/map/03-shared-packages.md
Yun Chan eedd127ea7
Some checks failed
ci / 정본·보안·린트·타입·테스트 (push) Failing after 1m13s
ci / 워크스페이스 빌드 검증 (push) Has been skipped
ci / 모바일 린트·타입·Jest (push) Failing after 1m4s
ci / Supabase Edge Functions + Cloudflare Worker (push) Successful in 37s
ci / .NET API 서버 테스트 (push) Successful in 27s
deploy-site / deploy (push) Failing after 20s
refactor(billing): remove Stripe; payments are Payple (web) and Google Play (mobile)
Stripe is not used. Keeping its checkout, portal and webhook paths meant a
second payment provider, a second return-URL format and dead UI.

- Delete the stripe-checkout, stripe-portal and stripe-webhook functions and
  their config; billing-catalog serves Payple prices only, and the web parser
  rejects a catalog that still mixes in Stripe prices.
- Web: drop the Stripe checkout/portal buttons, provider toggle and return
  notices; billing shows Payple only. Past rows with provider='stripe' are
  still displayed ("Stripe (종료)") with a support contact instead of a portal.
- Desktop: delete the Stripe checkout modal, payment IPC channels, preload
  namespace and their types; "Remove ads with Pro" opens the web billing page
  via license.openBilling. Support/refund copy names Payple.
- billingUrl() loses the Stripe-only success/canceled result option; the
  Deno contract is regenerated.
- Migrations and the DB's accepted provider values are untouched (history).
- Docs and the backlog record the removal (MON-04, EXT-STRIPE-01, GAP-BILL-03).

Verified: typecheck (desktop/web/admin/api-client/mobile), contract:check,
deno check all functions, deno test 80/80, desktop 1478/1480 on the Electron
runtime (2 known environment failures), web and admin builds, release
metadata and mobile boundary self-tests, eslint on changed files.
2026-09-26 20:56:18 +09:00

6.6 KiB

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.2.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, KEYBINDING, 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, INPUT_TELEMETRY, SUGGESTION, POPUP_SUGGESTION)
Key bindings ./keybinding SSOT for every global shortcut in the app: KeyBinding (device/code/ctrl/alt/shift/meta), KEY_CATALOG (10 selectable groups incl. mouse), KEYBINDING_ACTIONS (9 rebindable actions incl. the three suggestion actions), bindingKey/normalizeBinding/validateBinding/detectBindingConflicts/formatBindingSegments/searchKeyCatalog/parseBindingMap. Persisted as AppConfig.keyBindings. i18n keys are exposed as plain string so core stays independent of @d3ro/i18n; consumers narrow at the boundary (asTranslationKey) and a contract test guards the keys — accepted constraint, 11 §7 CONSTRAINT-I18N-01. Tests: __tests__/keybinding*.test.ts via vitest.config.ts (npm run test --workspace=@d3ro/core), 117 cases as of 2026-09-21
Input intelligence ./input-intelligence SSOT for the input-telemetry and next-sentence-suggestion domain (added 2026-09-21): key classification (classifyKeyStroke), text metrics (countWords/countSentences/endsSentence/textBeforeCaret), computeTypedDelta (UIA snapshot diff — the IME-safe way to count typed text), decideSuggestion + isAppExcluded (when to request / skip / clear), parseSuggestionCandidates/sanitizeSuggestionLine (prompt-leak and prefix-echo defence), anchorFloatingPanel (caret-anchored overlay placement), mergeActivityBucket/summarizeActivity/pixelsToMeters, extractPhrases/selectPhraseHints, INPUT_TELEMETRY_DEFAULTS/SUGGESTION_DEFAULTS
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.