Skip to content

OnePlatform — User Stories Friction Point Analysis

Date: 2026-06-10 Status: Complete. 108 friction points identified, 22 new ADR decisions required. Method: Three parallel architect agents analyzed three user stories against the 23 approved ADR decisions.

Summary

The 23 approved architecture decisions are excellent on security, reliability, and infrastructure. They are thin on user-facing surfaces: the developer experience, the API contracts, the data flow, the app platform, and the plugin system. The architecture designs the engine well but leaves the interfaces to the engine almost entirely unspecified.

Coverage Gaps By Area

Area Specification Level Impact
Infrastructure & Security ~95% specified Low gap
Reliability & Observability ~90% specified Low gap
End-to-End Data Flow ~20% specified Critical gap
App Platform (hosting, editor, BFF, SDK) ~5% specified Critical gap
Plugin System (interfaces, packaging, lifecycle) ~10% specified Critical gap
API Contracts (URLs, errors, pagination) ~0% specified Critical gap
CLI Design (commands, storage, profiles) ~5% specified Critical gap
SDK Architecture (typing, generation, modules) ~10% specified High gap
First-Run Experience ~0% specified Critical gap
Outbound Events (webhooks, event catalog) ~0% specified Critical gap

User Story 1: "I Want to Build an App on the Platform"

Personas

  • Alex — data engineer building a dashboard on ingested data
  • Blake — developer building an internal CRUD tool for their team
  • Casey — non-expert with a spreadsheet wanting a simple viewer

CRITICAL Friction Points

ID Description Missing ADR
APP-C01 No first-run experience. docker compose up leaves user with no URL, no wizard, no initial admin creation. Bootstrap auth problem (who creates the first user when no users exist?) is unresolved. ADR-24
APP-C02 OP_MASTER_KEY chicken-and-egg. Key must exist before services start but is generated by setup wizard that runs after services start. ADR-24
APP-C03 App hosting infrastructure entirely undefined. Where do app builds live? How served? Container per app vs static bundle vs in-process? ADR-25
APP-C04 App-SDK API surface entirely undefined. No method signatures, no query syntax, no response shapes. ADR-26
APP-C05 BFF mechanics undefined. App Service as BFF stated but not designed. Request flow from browser → App Service → internal services not traced. ADR-26
APP-C06 OAuth client lifecycle for platform-hosted apps undefined. Who creates OAuth clients? When? How? ADR-27
APP-C07 In-browser code editor entirely undefined. No editor library, file structure, dependency management, or build trigger mechanism. ADR-28
APP-C08 Build pipeline undefined. What builds app code? Where do artifacts go? How long does it take? ADR-25
APP-C09 End-to-end data flow undefined. Path from Ingestion → mapping → storage → queryable via app has no design. This is the #1 value proposition. ADR-29
APP-C10 Real-time event pipeline undefined. Who emits events on data change? How do browser apps subscribe? Where does fan-out happen? ADR-30
APP-C11 Non-expert persona (Casey) entirely blocked. No auto-infer, no drag-drop, no CSV-to-chart path. ADR-25
APP-C12 App-level access control undefined. Who can access deployed apps? How does the developer configure it? External users? ADR-27

HIGH Friction Points

ID Description
APP-H01 Token storage in browser not specified (httpOnly cookies vs localStorage vs sessionStorage)
APP-H02 Dashboard information architecture undefined. What does user see after login?
APP-H03 Connector interface not defined. Connector type referenced but never specified.
APP-H04 Data sync model undefined. Full vs incremental, cursor/watermark, large dataset handling.
APP-H05 App rollback not designed. Users can deploy but cannot safely roll back.
APP-H06 Object storage gap. App build artifacts (binary bundles) have no storage destination. No MinIO/S3 in architecture.
APP-H07 App versioning undefined. No versioning model for app code.
APP-H08 Ontology auto-inference missing. No auto-detect from CSV headers or database introspection.
APP-H09 WebSocket lifecycle undefined. Connection management, load balancing, reconnection.
APP-H10 App debugging experience undefined. No console panel, error overlay, or breakpoints.
APP-H11 Service startup ordering undefined. No depends_on health check strategy.
APP-H12 External app user access undefined. Can non-platform users access apps?
APP-H13 Password reset/email verification not mentioned. Table-stakes auth features.

MEDIUM Friction Points

ID Description
APP-M01 "Ontology" is jargon. Non-experts confused. Should be configurable alias.
APP-M02 CSV parsing configuration undefined. Delimiter auto-detect, malformed row handling.
APP-M03 Real-time backpressure unspecified. Fan-out strategy for high-frequency events.
APP-M04 App preview vs production undefined. Separate "preview" mode? Real data?
APP-M05 Data envelope contract undefined. JSON format for ingested records not specified.
APP-M06 Rate limits for ingestion undefined. What about 50M-row databases?
APP-M07 Ontology code generation timing unclear. When runs? Blocks UI?
APP-M08 App slug uniqueness scope. Per-tenant or global?
APP-M09 Cross-tenant app sharing undefined.
APP-M10 No getting-started content (tutorials, example apps, sample datasets).

User Story 2: "I Want to Build a Plugin to Extend Functionality"

Personas

  • Connector author — adding Shopify data ingestion
  • Transformer author — adding custom data masking
  • Destination author — adding Snowflake export
  • AuthProvider author — adding SAML SSO
  • Widget author — adding a custom chart type

CRITICAL Friction Points

ID Description Missing ADR
PLG-C01 No interface method signatures for ANY of the 5 plugin types. A developer cannot write a conforming plugin because no contract exists. ADR-31
PLG-C02 No plugin.manifest.json schema. No canonical declaration of what a plugin is. ADR-32
PLG-C03 No package format decision. "How do I ship this?" completely unanswered. ADR-32
PLG-C04 No op plugin create scaffold command. No entry point for developers. ADR-35
PLG-C05 Connector plugin type conflated with pipeline hooks. A source connector IS the data source, not a before/after hook. Architecture needs a distinct integration point. ADR-36
PLG-C06 No outbound URL allowlist mechanism for plugin-initiated network calls. Connector plugins can't call external APIs. ADR-32
PLG-C07 No per-tenant scoping for injected db API in plugin sandboxes. Security gap — plugin could read other tenants' data. ADR-33

HIGH Friction Points

ID Description
PLG-H01 No plugin installation mechanism. op plugin install not specified.
PLG-H02 No code signing or integrity verification for plugin artifacts.
PLG-H03 No credential vault access pattern for plugins. Connectors need external service credentials.
PLG-H04 No plugin configuration schema format. No way to declare what fields user fills in.
PLG-H05 No list of available hook stages. Developers can't know what to register for.
PLG-H06 No plugin error taxonomy. Platform can't distinguish rate limit from auth failure.
PLG-H07 No timeout model for Connector plugins. 30s hook timeout inappropriate for full historical sync.
PLG-H08 Service RBAC matrix missing Plugin Service entries (Ingestion→Plugin, Plugin→Execution).
PLG-H09 No local dev server specification. Named but not designed.
PLG-H10 No hook simulation tool. Testing requires triggering real pipelines.
PLG-H11 No sandbox-consistent local execution. Code may pass locally but fail in production.
PLG-H12 No plugin update/rollback mechanism.
PLG-H13 Widget plugin sandbox model undefined. iframe vs same-origin has major security implications.

MEDIUM Friction Points

ID Description
PLG-M01 No plugin versioning/coexistence model.
PLG-M02 Plugin disable/uninstall state undefined. What happens to mid-execution jobs?
PLG-M03 Data orphan handling on uninstall undefined.
PLG-M04 No plugin-level audit trail.
PLG-M05 Plugin errors don't have defined path to DLQ.
PLG-M06 No OTEL span injection for plugin code. Plugin performance invisible.
PLG-M07 No per-tenant plugin configuration.

User Story 3: "I Want to Use the API/CLI/SDK"

Personas

  • DevOps engineer — infrastructure-as-code, CI/CD
  • Data engineer — trigger pipelines from Airflow
  • App developer — external app using OnePlatform data
  • Platform admin — manage everything via CLI

CRITICAL Friction Points

ID Description Missing ADR
API-C01 Outbound webhook system completely absent. Platform can receive webhooks but cannot push events. Every integration pattern (Airflow, Slack, mobile push) requires push-based notifications. ADR-37
API-C02 API contract entirely unspecified. Zero request/response schemas, URL conventions, error format, status codes defined for any endpoint. ADR-38
API-C03 Config export/import is one sentence with no specification. Entire IaC use case blocked. ADR-42
API-C04 API key scoping unspecified. Every programmatic client gets full admin access, violating least privilege. ADR-41
API-C05 CLI credential storage unspecified. Path, format, encryption all undefined. ADR-39
API-C06 Ontology-typed SDK unspecified. "Ontology-typed data access" mentioned but mechanism (static codegen? runtime validation?) undefined. ADR-40
API-C07 No Terraform provider or Kubernetes operator. Modern DevOps don't use CLIs for infra. Roadmap

HIGH Friction Points

ID Description
API-H01 OpenAPI spec URL not defined. No /api/v1/openapi.json well-known endpoint.
API-H02 Multi-profile CLI support unspecified. No dev/staging/prod management.
API-H03 Pipeline trigger API contract undefined. Most common programmatic operation has no spec.
API-H04 Real-time event catalog not defined. Event types, schemas, filter options unknown.
API-H05 Browser OAuth flow details missing. Auth endpoint URL, scopes, CORS, token storage.
API-H06 Pagination contract not specified. Every service will implement differently.
API-H07 Error response format not specified. No standard error envelope.
API-H08 No standalone CLI binary. Non-Node.js environments blocked.
API-H09 API versioning communication undefined. No deprecation/sunset headers.
API-H10 Bulk API operations missing. Creating 100 records requires 100 API calls.
API-H11 Rate limit UX incomplete. Users can't discover limits or request higher tier.

MEDIUM Friction Points

ID Description
API-M01 Plugin install source format unspecified.
API-M02 Email delivery dependency not specified (SMTP or fallback).
API-M03 op logs tail --follow not specified.
API-M04 App environment variables not specified.
API-M05 DLQ management CLI not specified.
API-M06 Version pinning for CLI in CI not addressed.
API-M07 SDK error classification (retryable vs not) unspecified.
API-M08 SDK pagination iterator API unspecified.
API-M09 op config diff command missing.
API-M10 Pipeline run cancellation not specified.
API-M11 Connector credential update workflow undefined.
API-M12 OnePlatform as OAuth authorization server not specified.

Required New ADR Decisions (Consolidated)

The 22 identified gaps consolidate into 13 new architecture decisions (ADR 24–36):

ADR-24: First-Run Experience and Bootstrap

  • OP_MASTER_KEY generation via init service before other services start
  • Bootstrap endpoint POST /api/v1/auth/bootstrap (auto-disables after first use)
  • Initial admin + tenant creation flow
  • Setup wizard screens and URL
  • Docker Compose service startup ordering with health checks

ADR-25: App Platform Design (Hosting, Build, Editor)

  • App code storage (MinIO/S3-compatible object store, add to Docker Compose)
  • Build pipeline (esbuild in Execution Service sandbox for security)
  • Build artifact storage and versioning
  • App rollback (pointer change to previous version)
  • In-browser editor (Monaco Editor, MIT licensed)
  • Virtual file system for apps
  • Hot-reload preview mechanism
  • External IDE support (op app dev local workflow)
  • Auto-generated starter app from ontology
  • Minimum viable non-expert experience (auto-infer schema, starter app)

ADR-26: App-SDK and BFF Design

  • Complete API surface of @oneplatform/app-sdk:
  • useQuery(entity, options) — typed data access
  • useMutation(entity) — write operations
  • useSubscription(entity, options) — real-time
  • useUser() — current user context
  • usePermission(action, resource) — permission check
  • useAppStorage(key, default) — per-app/per-user KV
  • BFF request flow: browser app → App Service proxy → internal services
  • Token handling: httpOnly cookies via App Service BFF
  • User identity in app context
  • RBAC enforcement at BFF layer

ADR-27: App Access Control and OAuth Client Lifecycle

  • OAuth client auto-registration on app deploy
  • Client ID scheme, redirect URI management
  • Token binding to app+user pairs
  • Two access modes: Platform-User Only (default) and Public/Guest Access
  • Guest role with limited ontology RBAC
  • App-level roles separate from platform roles
  • Cross-tenant sharing rules

ADR-28: End-to-End Data Flow

  • Canonical path: Ingestion → raw staging → Ontology mapping → tenant data tables
  • Raw data storage (separate from ontology-mapped data)
  • Data envelope format (source metadata, ingestion timestamp, record ID)
  • Incremental vs full sync (cursor-based with watermark tracking)
  • Large dataset handling (batching, backpressure, progress tracking)
  • Connector interface specification (methods, configuration schema)
  • Auto-inference of ontology from uploaded data / database introspection

ADR-29: API Contract Standard

  • URL convention: /api/v1/{resource}/{id}
  • HTTP method semantics (PATCH for partial, PUT for full replace)
  • Request/response envelope: {data: T, meta?: {...}}
  • Error format: {error: {code: string, message: string, details?: {}, requestId: string}}
  • Pagination: cursor-based {items: T[], nextCursor: string | null, total?: number}
  • Filter/sort DSL: ?filter[field]=value&sort=-createdAt&fields=id,name
  • Bulk operations: POST /api/v1/{resource}/bulk
  • OpenAPI spec at GET /api/v1/openapi.json
  • Deprecation/Sunset headers (RFC 8594)
  • Health check standard: GET /healthz (liveness), GET /readyz (readiness)

ADR-30: Outbound Event System

  • Outbound webhook registration CRUD API
  • Event catalog (data., pipeline., ingestion., ontology., app., plugin., auth., system.)
  • Event schema: {eventId, eventType, tenantId, timestamp, actor, data}
  • HMAC-SHA256 signature verification
  • Delivery guarantees (at-least-once via BullMQ)
  • Retry policy (exponential backoff, max 24h, then dead-letter)
  • SSE event replay on reconnection
  • Real-time subscription filter syntax
  • Connection lifecycle and backpressure

ADR-31: Plugin Interface Specifications

  • Complete TypeScript interfaces for all 5 plugin types:
  • Connector: connect, fetchBatch, subscribeToEvents, disconnect, declareOutputSchema, declareConfigSchema
  • Transformer: transform, transformBatch, declareInputSchema, declareOutputSchema
  • Destination: write, writeStream, declareAcceptedSchema, declareDeliveryGuarantee
  • AuthProvider: validateToken, getAuthorizationUrl, handleCallback, refreshToken, mapClaimsToRoles
  • Widget: render, declareDataRequirements, declareSlot (iframe sandbox with postMessage)
  • Injected context APIs: CredentialAccessor, FetchProxy, CacheAccessor, PluginLogger, TenantContext, OntologyAccessor
  • Plugin error taxonomy: PluginError base + AuthError, RateLimitError, TimeoutError, DataError subtypes
  • Complete list of hook stages across all services
  • Hook registration API

ADR-32: Plugin Package Format and Distribution

  • Format: signed tarball (bundle.js + plugin.manifest.json + bundle.js.sha256)
  • Manifest schema: name, version, type, entrypoint, configSchema, hooks, requiredExternalUrls, requiredApis, minPlatformVersion, permissions
  • Code signing: SHA-256 hash in manifest, optional GPG signing
  • Outbound URL allowlist (declared in manifest, admin approves on install)
  • Plugin instance model (multiple instances with different configs)
  • Per-tenant vs platform-wide configuration
  • Plugin registry design (deferred but manifest format compatible)

ADR-33: Plugin Lifecycle and Installation

  • Installation mechanism: op plugin install accepts local tarball, URL, or registry slug
  • Plugin storage after install (Plugin Service database + volume)
  • Code distribution: Execution Service fetches from Plugin Service on demand, LRU cache
  • Authorization model (platform admin installs, tenant admin configures)
  • State machine: draft → installed → enabled → disabled → deprecated → uninstalled
  • Graceful disable (in-flight jobs complete, new jobs skip)
  • Uninstall requirements (no active jobs, orphaned data prompt)
  • Version coexistence (old version held in disabled for 24h rollback window)
  • Connector plugin as primary source (separate from hook integration)
  • Connector timeout model (configurable per-connector, separate from 30s hook timeout)
  • Service RBAC matrix additions: Ingestion→Plugin.listConnectors(), Plugin→Execution.runPlugin()

ADR-34: CLI Design Specification

  • ~85 commands across 12 groups (auth, profile, user, ontology, data, ingestion, webhook-out, pipeline, exec, app, plugin, logs, config, status, service)
  • Credential storage: ~/.config/op/credentials.json, encrypted via system keychain (keytar) with plain-text fallback + warning
  • Multi-profile system: ~/.config/op/profiles/
  • Environment variable precedence: --flag > OP_* env vars > profile config > defaults
  • Output formats: --output json|table|tsv
  • Auto-retry on 429 with backoff and progress indicator
  • Non-interactive mode flags (--no-input, --yes)
  • Tab completion (op completion bash|zsh|fish)
  • Standalone binary distribution (GitHub Releases: op-linux-amd64, op-darwin-arm64, etc.)
  • Version pinning recommendation for CI

ADR-35: SDK Architecture

  • OpenAPI code generator: @hey-api/openapi-ts (typed, tree-shakeable)
  • Ontology-typed SDK via op sdk generate command (tenant-specific codegen)
  • Module format: ESM primary, CJS secondary, dual-package exports
  • Browser vs Node detection (auto-select auth strategy)
  • Error taxonomy: typed errors with isRetryable, statusCode, code
  • Async iterator pagination: sdk.data.list() returns AsyncIterable<Page<T>>
  • Auto-retry: configurable RetryPolicy (retry on 429/503, 3 attempts, exponential backoff)
  • Real-time subscriptions: sdk.realtime.subscribe(filter, handler) with reconnect/replay

ADR-36: Supporting Infrastructure

  • API key scoping (data:read, data:write, pipelines:trigger, admin scopes)
  • API key rotation workflow with overlap period
  • Email delivery: SMTP via OP_SMTP_* env vars, fallback "link-copy" mode
  • Predefined role taxonomy (admin, editor, viewer, custom)
  • Config export/import specification (YAML, topological sort, conflict resolution modes, dry-run)
  • MinIO (MIT, S3-compatible) added to Docker Compose for app builds + file uploads
  • CORS policy (OP_ALLOWED_ORIGINS)

Key Recommendations

Immediate (before service design begins)

  1. Write ADR-29 (API Contract Standard) first. Every service implementation bakes in URL conventions, error format, and pagination. Changing later is a platform-wide breaking change.

  2. Write ADR-28 (Data Flow) second. This is the #1 value proposition. Without the path from ingestion to queryable data, nothing else matters.

  3. Write ADR-31 (Plugin Interfaces) third. The architecture says "built-in features use same interfaces as third-party plugins." Those interfaces must exist before ANY service is implemented.

  4. Write ADR-24 (First-Run) early. The bootstrap problem (first user creation, master key generation, startup ordering) must be solved before Docker Compose works.

UX Improvements (beyond fixing gaps)

  1. Progressive disclosure for ontology editor. Simple mode (table view) + Advanced mode (ER diagram).
  2. Instant preview with hot reload. Every save triggers incremental esbuild compile (~100ms).
  3. One-command local dev: op app dev --app my-dashboard for external IDE workflow.
  4. Guided first-app experience: Sample data → auto-infer schema → generate starter app → deploy in 5 min.
  5. Query builder panel in app editor for non-coders.
  6. Connection status indicators throughout the platform (data source sync status, pipeline failures, DLQ).
  7. Plugin scaffold with sandbox-consistent local dev — if it works locally, it works in production.

Files Reference

File Purpose
docs/decisions/001-architecture-decisions.md L0 architecture (23 decisions, APPROVED)
docs/USER-STORIES-ANALYSIS.md THIS FILE — friction point analysis
docs/HANDOFF.md Comprehensive project context
DEVELOPMENT-PROCESS.md Development pipeline
docs/WORKING-STATE.md Current state tracker