DOC-024: Canonical implementations
Estado
Accepted — 2026-08-23 · Amendment 2026-08-24: gold solo en este repo. IVPrior es muestra para copiar, no dependencia.
Norma: ADR-062. Toda fila de Mirror es un path dentro de IVPrior. Prohibido importar, submoduliar o instruir a un agente a abrir ../IVPrior (u otra máquina) para implementar.
IVPrior se usó una vez (SLICE-001-00) para portar patterns/rules/packages hacia packages/ui, packages/admin-layout y estos docs. Después de ese copy, IVPrior se construye solo.
UI admin — gold en este repo
| Tipo | Mirror (IVPrior) | Notas |
|---|---|---|
| Átomos / data-table | packages/ui (src/components/ui/button.tsx, input.tsx, textarea.tsx, src/components/data-table/) | Port SLICE-001-00; Textarea = mismo chrome que Input, min-h + rows |
| Page toolbar, shell, wizard shell | packages/admin-layout/src/admin-page-toolbar.tsx · admin-shell.tsx · admin-wizard-shell.tsx | Port SLICE-001-00 |
| List page + toolbar | apps/web/features/shared/components/AdminCrudListPage.tsx | Lista simple. Catalogos (Users/Roles/Permissions/Audit) usan AdminEntityTable. Organizations y Plans tienen Card table propia. |
| Active sessions | apps/web/features/shared/components/ActiveSessionsPage.tsx | Platform and Organization. Device/IP/current badge when the API has them; tenant tokens today expose created/expires only. |
Table + AdminMobileList | AdminCrudListPage + @ivprior/ui/admin-mobile-list | Cards <lg, table lg+ |
| Wizard full-page | apps/web/features/tenant-access/components/TenantRolesWizard.tsx | 2 pasos Details + matrix; Next outline |
| Auth card (Organization) | apps/web/features/tenant-auth/components/OrganizationAuthShell.tsx | Backdrop + glowing card; login/signup/invite/forgot/reset/verify |
| Organization tenant login | apps/web/features/tenant-auth/components/OrganizationLoginPage.tsx | /t/{organizationSlug}/login. No global /login (Customer portal not in V1). |
| Organization signup wizard | apps/web/features/tenant-auth/components/OrganizationSignupWizard.tsx | 3 steps: plan picker + org name/slug, OWNER account, review. Dialog: OrganizationSignupDialog. No Location. |
| Organization contact (address) | apps/web/features/tenant-org/components/OrganizationContactPage.tsx | Route /t/{organizationSlug}/settings. Places autocomplete + map + phone E.164 + support email. Gold atoms in features/shared/address and features/shared/maps. |
| Tenant admin chrome | apps/web/features/tenant-access/components/TenantShell.tsx | Workspace /t/{organizationSlug}/…. Settings + Billing. Support = User Help only (Developer Docs is platform). Header Search = command palette (searchMode="palette"). Bell Inbox + Audit tab (onViewAllLogs). Help ? = resolveContextualHelpUrl. Profile = EntityAvatar + /account/profile. |
| Organization branding | apps/web/features/tenant-org/components/OrganizationBrandingPage.tsx | Mirror PlatformBrandingPage: crop logo/favicon, dual colors, workspace preview. No Location table. |
| Organization dashboard | apps/web/features/tenant-org/components/OrganizationDashboardPage.tsx | KPI sparklines, Cash Recovered trend, aging donut, top Customers, recent invoices. Demo orgs seed Customer/Invoice. |
| Clear-on-edit | apps/web/features/shared/lib/clear-field-errors.ts | Copiar a este path en el primer slice UI |
| FormCloseDialog | apps/web/features/shared/components/FormCloseDialog.tsx | Idem |
Marketing landing / | apps/web/features/platform-homepage/components/PlatformMarketingLanding.tsx | Header, site-links, legal footer, store badges |
| Public plan cards | apps/web/features/platform-homepage/components/PublicPlanCards.tsx | Catalog via GET /api/v1/public/plans; empty until published |
| Platform social links (S-094) | apps/web/features/platform-admin/social-links/components/PlatformSocialLinksPage.tsx | Catalogo fijo 6 redes; API platform/settings/social-links |
| Help Center chrome | apps/help/features/help-center/components/HelpShell.tsx | Sidebar colapsable + iconos, ⌘K, locale bandera |
| Help article body | apps/help/mdx-components.tsx + HelpArticlePage.tsx | ReactMarkdown: native <img> for /help/S-xxx/*.svg, HelpCallout from >, breadcrumb + prev/next pager |
| Developer Docs chrome | apps/docs/features/dev-docs/components/DocsShell.tsx | Sidebar módulos, ⌘K, bandera, catálogo ADR con filtro, artículos + pager |
| Platform admin chrome | apps/web/features/platform-admin/components/PlatformShell.tsx | Factory menu: Dashboard, Analytics, Organizations, Plans, Access, Compliance, sessions/branding/social. Header shortcut = Organizations (analog of Tenants; Plans is sidebar-only). Header Search = command palette. Session gate + JWT refresh. Bell Inbox + Audit tab. Help ? = contextual article. |
| Platform plans list | apps/web/features/platform-admin/plans/PlatformPlansListPage.tsx | AdminPageToolbar + Add plan + Card table: search, Filter, Export, checkboxes + DataTableBulkBar, ⋮ Edit/Duplicate/Delete. Wizard: PlatformPlanWizard.tsx. |
| Platform data sources list | apps/web/features/platform-admin/data-sources/components/PlatformDataSourcesListPage.tsx | Mirror Plans list. Modal wizard: PlatformDataSourceFormDialog (Mirror ScheduledJobFormDialog). ⋮ Edit/Deactivate/Delete; bulk Delete. Help S-205. |
| Subscriber scheduled scans | apps/web/features/scanner/components/ScannerSchedulesListPage.tsx (P0 Spec Kit 006) | Mirror jobs list. Modal wizard ScannerScheduleFormDialog ← ScheduledJobFormDialog + AdminWizardModalShell. Sin /new ni /{id}. Help S-208. |
| Platform ticker catalog list | apps/web/features/platform-admin/tickers/components/PlatformTickersListPage.tsx | Mirror Data sources / Analyze list. Modal form (no credentials wizard). Search · Filter · Export. ⋮ Edit/Activate/Deactivate/Delete; bulk Delete. Help S-207. Subscriber watchlist Add = catálogo activo. |
| Subscriber watchlist list | apps/web/features/scanner/components/WatchlistPage.tsx | Mirror Analyze list. Columns Symbol · Name · Status (name from platform catalog). Add modal = catálogo platform. Checkboxes + bulk + ⋮ Activate/Deactivate/Delete. Analyze combobox = esta lista. |
| Subscriber paper diary list | apps/web/features/scanner/components/PaperDiaryPage.tsx | Mirror Watchlist / Scanner jobs. Columns Date · Symbol · Name · Type · Summary (signal · IV regime · strategy from snapshot). Search · Filter (type + date) · Export. Checkboxes + bulk delete · ⋮ View (ficha snapshot modal) / Analyze now / Delete. No Add. Help S-204. |
| Scan job running progress | apps/web/features/scanner/components/ScanJobProgressPanel.tsx | Barra role=progressbar (chrome LimitMeter) + fase + ticker actual + lista N de M. Processor escribe resultSummary.phase por ticker. No skeleton datatable mientras QUEUED/RUNNING. |
| Run scan ticker subset | apps/web/features/scanner/components/RunScanDialog.tsx | Mirror SearchableMultiCombobox (Permission form / Plan scanner sources). Default = watchlist activa; POST params.symbols (API ya filtra vs watchlist). Resultados: miss hint con símbolos (listMissedScanSymbols). |
| Opportunity ficha copy | apps/web/features/scanner/lib/opportunity-copy.ts | Copy de ficha (dirección, por qué, estrategia, checklist, disclaimer) en el locale de la UI (next-intl). Motor persiste directionFacts + buckets; jobs viejos con prosa CLI en español se re-renderizan. No mezclar labels EN con cuerpo ES. Estrellas = prioridad relativa; no mostrar el rankingScore numérico. |
| Analyze context chart | apps/web/features/scanner/components/AnalyzeContextChart.tsx | FEAT-012. lightweight-charts (Apache, no iframe TradingView). Solo S-202 Analyze sheet. Snapshot as-of; presets 1M·3M·6M·1A; Bollinger diario. MUST NOT usarse fuera de Analyze. |
| Directional scan result rows | apps/web/features/scanner/components/ScanResultRowPanel.tsx | Mirror OpportunityResultPanel. SCAN/SCREENER/BACKTEST: ticker + badge de señal + métricas etiquetadas (precio, RSI, motivo SMA i18n). No JSON crudo, no rowKind/sortKey/signalScore sueltos. |
| Platform organizations list | apps/web/features/platform-admin/organizations/PlatformOrganizationsListPage.tsx | Mirror Plans list. Card table: avatar (EntityIdentityCell), slug <code>, status Badge, Plan chip, Created, Filter status+date, Export, checkboxes + bulk Suspend/Activate, ⋮ Impersonate/Suspend. No Location column. |
| Platform permissions catalog | apps/web/features/platform-admin/access/PlatformPermissionsListPage.tsx | AdminEntityTable. Add permission + PermissionFormDialog (Resource/Action comboboxes, Textarea description, status Switch). ⋮ Edit/Delete, bulk delete. 409 if assigned to roles. No Location/orders. |
| Platform roles catalog | apps/web/features/platform-admin/access/PlatformRolesListPage.tsx | AdminEntityTable + URL wizard PlatformRoleWizard (Basics + grouped RolePermissionsMatrix). /platform/access/roles/new · /platform/access/roles/{id}. ⋮ Edit/Delete on custom roles. System roles locked. |
| Platform command palette | apps/web/features/platform-admin/command-palette/PlatformCommandPalette.tsx | ⌘K / Search icon. Query ≥2 chars searches Organizations; Impersonate → /t/{slug}/dashboard. No orders/locations/menu. |
| Tenant command palette | apps/web/features/tenant-org/command-palette/TenantCommandPalette.tsx | ⌘K / Search icon. Nav + actions (dashboard, settings, branding, users, billing). No Location/orders. |
| Platform auth split layout | apps/web/features/platform-admin/components/PlatformAuthLayout.tsx | /platform/login + forgot/reset — hero + form card |
| Platform branding (S-119) | apps/web/features/platform-admin/branding/components/PlatformBrandingPage.tsx | Logo/favicon crop, dual ColorPicker, Organization workspace preview |
| Platform profile | apps/web/features/platform-admin/profile/components/PlatformMyProfilePage.tsx | Hero + details + password |
| Tenant profile | apps/web/features/tenant-access/components/TenantMyProfilePage.tsx | Twin of Platform profile. /t/{slug}/account/profile. User.avatarUrl. |
| Image crop upload | apps/web/features/shared/components/ImageCropUploadField.tsx | react-easy-crop dialog; layouts branding / inline / dropzone. Profile POST /api/v1/platform/me/upload-avatar or /api/v1/me/upload-avatar. |
Contextual Help ? | apps/web/lib/screen-help-map.ts | Header helpHref = article for the current path. Unmapped /platform/* → S-017; unmapped /t/{slug}/* → S-010. Scanner: S-010 dashboard, S-200 results, S-201 watchlist, S-202 analyze, S-204 diary, S-206 jobs, S-207 tickers. |
| Admin KPI grid | apps/web/features/shared/components/admin-kpi/AdminKpiGrid.tsx | Compact density + sparkline; ops home / analytics |
| Dashboard feed panel | apps/web/features/shared/analytics-dashboard/components/DashboardFeedPanel.tsx | h-[22rem] + scroll interno. Ops home: orgs/sessions/audit |
| Entity identity cell | apps/web/features/shared/components/EntityIdentityCell.tsx | Avatar + name. Organization squircle, Customer circle |
| Dashboard invoices table | apps/web/features/shared/analytics-dashboard/components/DashboardInvoicesTable.tsx | Recent invoices: sort headers, badges, EntityIdentityCell, pagination, AdminMobileList. Harbor + /platform/analytics |
| Plan mix donut | apps/web/features/shared/analytics-dashboard/components/DashboardDistributionChart.tsx | Recharts pie; no order-type labels |
| Platform ops home | apps/web/features/platform-admin/ops-home/components/PlatformOpsHomePage.tsx | KPI grid + donut + feeds (orgs/sessions/audit) at /platform |
| Platform analytics | apps/web/features/platform-admin/dashboard/components/PlatformDashboardPage.tsx | /platform/analytics — Cash Recovered trend, aging, AR by Organization, invoices. Not the ops home. |
| Transactional email layout | apps/api/src/infrastructure/email/templates/transactional-email-layout.ts | Card shell; rich header via email-chrome.ts |
| Transactional email templates | apps/api/src/infrastructure/email/email-template.service.ts | Reset, invite, verify, welcome — hero + social footer + Help/Docs. Scheduled scan result: subscriberScheduledScanAlert (meta list + disclaimer) |
| Platform web analytics (GTM) | apps/web/features/shared/analytics/PlatformMarketingAnalytics.tsx | Consent Mode + banner; GTM off si NEXT_PUBLIC_GTM_ID vacío |
| Document metadata / SEO | apps/web/lib/seo/build-public-page-metadata.ts + robots-policy.ts · Help apps/help/lib/seo/build-help-page-metadata.ts · Docs apps/docs/lib/seo/build-docs-page-metadata.ts · DocumentTitle en AdminPageToolbar · patrón docs/ux/patterns/document-metadata.md | Título %s | IVPrior (Help/Docs sufijo propio). Indexables: / /pricing. Paneles /t /platform + auth: noindex. |
Hasta que una fila TBD exista: no inventar chrome; componer desde @ivprior/ui / @ivprior/admin-layout (ya copiados al repo) y los patrones en docs/ux/patterns/. El primer ejemplar se registra aquí en el mismo PR.
Patrones: docs/ux/patterns/platform-admin-crud.md · admin-wizard.md · admin-ui-coherence.md.
Qué NO entra en IVPrior (ni como path)
- Entidad Location,
X-Location-Id, courier, QR/menu, marketplace, KDS. - Cualquier
importo referencia de filesystem a otro producto. Paleta: copiar valores IVPrior enpackages/ui/tokens/tokens.css(no remapear a light/negro).
API
| Tipo | Mirror | Desde |
|---|---|---|
| List + pagination | apps/api/src/modules/iam/tenant-access.service.ts (listUsers) | Invite/disable + max_users |
| Dialog confirm | apps/web/features/tenant-access/components/TenantUsersListPage.tsx (Invite dialog) | |
| Prometheus scrape | apps/api/src/infrastructure/metrics/metrics.controller.ts | ADR-028; bearer METRICS_BEARER_TOKEN |
| JSON logger | apps/api/src/infrastructure/logging/json-logger.service.ts | correlation id + redact PII |
| Public plan catalog | apps/api/src/plans/public-plans.service.ts | ensureCatalog + published self-serve list |
| Organization profile | apps/api/src/modules/organization/application/organization-profile.service.ts | GET/PATCH /api/v1/organization — address, phone E.164, supportEmail |
| Scanner engine (CLI) | apps/scanner-engine/src/scanner_engine/main.py + cli_bridge.py | Thin FastAPI over apps/cli. Compose: scanner-engine (make local-up). Host fallback: make engine-dev. |
| Subscriber scanner audit | apps/api/src/modules/scanner/presentation/subscriber-scanner.controller.ts (recordAudit) | Mirror AuditService.record (CreateScheduledJobUseCase). Mutations write SCANNER_* with subscriberId so the shell Logs tab is not empty. |
| Screener CLI → SaaS rows | apps/cli/saas_contract.py (screener_payload) + apps/scanner-engine/src/scanner_engine/main.py | SCREENER calls fundamentals.evaluar. 0 hits is a valid miss (mega-caps/ETFs). Copy: emptyScreener, not the generic wait empty. |
| Backtest CLI → SaaS rows | apps/cli/saas_contract.py (backtest_trade_payload) + apps/cli/backtest.py | BACKTEST calls backtest.run (long-only, no lookahead). Stats strip = trades / win rate / vs buy&hold — no dump of unsupported keys, no IV miss hint. |
| Bollinger CLI → SaaS rows | apps/cli/saas_contract.py (bollinger_payload) + apps/cli/bollinger.py | BOLLINGER calls collect_tabla (%B, squeeze, trend-filtered signal). One row per ticker, not a trade log. Copy: emptyBollinger, not the IV miss hint. |
| Scanner job complete notify | apps/api/src/modules/scanner/application/services/scan-job-processor.service.ts (emitFinished) | Mirror DispatchSubscriberNotificationUseCase. Inbox+email honor /app/notifications. Actor is not skipped (shouldSkipActor SCANNER_* = false). Deep link /scanner?job= / /scanner/analyze?job= (Mirror PaperDiary ?entry=). |
Ops / DX
| Concern | Canónico | Notas |
|---|---|---|
| Git pre-push (docs/ops-only) | scripts/pre-push-gate.sh + .husky/pre-push | Skip pnpm typecheck + pnpm test cuando el push solo toca docs/, memory/, openspec/, specs/, agents/, .specify/, .github/, .cursor/, etc. Cualquier apps/ o packages/ → gate completo. make check = pre-PR. |
Session ship (/cierre-session) | scripts/sd-ship.sh + make ship | --skip-check + --no-wait para slices docs/ops; pre-push ligero acelera el push. |
Cómo usar
Mirror: apps/web/features/…/UsersListPage.tsx
Path relativo a IVPrior. Leer ese archivo antes del primer edit. Si aún no hay gold de ese tipo, el slice en curso lo crea aquí y añade la fila.
Schedules y Billing — SLICE-006-06 (2026-09-13)
- Validación cron API:
apps/api/src/modules/scanner/application/utils/scan-schedule-cron.utils.ts; el formularioapps/web/features/scanner/lib/scan-schedule-form.tsrefleja ese contrato numérico sin importar servidor. Tests de ambas fronteras cubren la misma matriz de entradas. - Billing scanner:
apps/web/features/subscriber-admin/billing/components/SaasBillingCurrentPlanCard.tsx/CompactUsageStat; cupos finitos con barra, null/cero sin barra; uso real en aria-valuetext. - Modal schedules:
ScannerScheduleFormDialog.tsxconservaScheduledJobFormDialogcomo Mirror; validación por paso con React Hook Form y errores inline en los FormField existentes.