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.
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-rnis not an npm workspace member, so roottypecheck/testskip it; usetypecheck:mobile/lint:mobile/test:mobilefrom the repo root.- No versioned publishing of packages (private, source-only); all consumers are in-repo.