Disciplines · Decisions (ADRs)

ADR-0009: Deep-Linking and Cross-Domain Routing Model

OSHUN must support reliable, shareable, and measurable navigation across:

Accepted · 2026-02-16
11sections5 minread

On this page

Status: Accepted Date: 2026-02-16 Authors: OSHUN Mobile Engineering, OSHUN Web Engineering, OSHUN Platform Engineering Reviewers: Domain Mobile/Web Leads Supersedes: N/A Superseded by: N/A

Context and Problem Statement#

OSHUN must support reliable, shareable, and measurable navigation across:

  • mobile app (apps/oshun/mobile)
  • web/PWA (apps/oshun/web)
  • domain-specific entry points (Tara, Veritas, Nyx, Arete)

Current domain implementations use domain-specific schemes and routes:

  • Tara: tara://... + https://tara.app/... with custom parser/route mapping.
  • Veritas: veritas://... + app links to https://www.veritas.news/....
  • Nyx: web/PWA route model (Vite) with installable behavior.

Without a unified route contract, OSHUN risks:

  • inconsistent deep-link behavior across platforms
  • broken cross-domain navigation semantics
  • difficult analytics attribution and debugging
  • brittle migration from domain-specific links to shell links

Decision Drivers#

  • Single routing language across shell and domains.
  • Cross-platform parity between mobile app links and HTTPS links.
  • Backward compatibility with existing Tara/Veritas links.
  • Safety: strict validation and predictable fallback behavior.
  • Observability: consistent link lifecycle telemetry.
  • Extensibility for future domains and route expansions.

Considered Options#

Description: OSHUN accepts only existing domain link formats and forwards to per-domain handlers.

Pros:

  • ✅ Minimal migration effort initially
  • ✅ Reuses existing domain handlers directly

Cons:

  • ❌ No canonical OSHUN link format
  • ❌ Inconsistent analytics and routing behavior
  • ❌ Hard to enforce shared security and fallback rules

Option 2: HTTPS-Only Routing, No Custom Scheme#

Description: all links use HTTPS and rely on universal/app links only.

Pros:

  • ✅ Simpler link shape for sharing
  • ✅ Browser-friendly by default

Cons:

  • ❌ Less reliable in app-to-app and native-only contexts
  • ❌ Harder local/dev linking and push/deep navigation ergonomics
  • ❌ Requires perfect associated-domain support from day one

Option 3: Canonical OSHUN Scheme + HTTPS Equivalents (Chosen)#

Description: define one canonical OSHUN deep-link contract with deterministic HTTPS equivalents and resolver rules.

Pros:

  • ✅ Explicit, versionable route contract
  • ✅ Strong mobile and web parity
  • ✅ Cleaner analytics and debugging
  • ✅ Supports legacy link migration path

Cons:

  • ❌ Requires route registry and resolver implementation discipline
  • ❌ Requires migration bridge for old domain links

Decision Outcome#

Chosen option: Option 3 - canonical oshun:// links with HTTPS equivalents.

Primary deep-link format:

  • oshun://{target}

Domain-specific target format:

  • oshun://{domain}/{path}

where domain is one of:

  • tara
  • veritas
  • nyx
  • arete

Shell surface format:

  • oshun://home
  • oshun://explore
  • oshun://activity
  • oshun://profile
  • oshun://search

HTTPS equivalent formats:

  • Shell routes: https://oshun.app/app/{surface}
  • Domain routes: https://oshun.app/d/{domain}/{path}

Canonical Examples#

  • oshun://tara/meditation/abc123
  • oshun://veritas/article/claim-42
  • oshun://nyx/events/meteor-shower-2026
  • oshun://arete/check-in/today
  • https://oshun.app/d/tara/meditation/abc123
  • https://oshun.app/app/home

Route Resolution Model#

  1. Parse and validate URI/URL against OSHUN allowlist.
  2. Normalize to canonical route descriptor.
  3. Resolve descriptor through @oshun/navigation route registry.
  4. Dispatch to shell surface or domain adapter launch contract.
  5. If unavailable/fails, route to safe fallback with user-visible recovery.

Normative Route Descriptor#

ts
export type OshunDomain = 'tara' | 'veritas' | 'nyx' | 'arete';

export interface OshunRouteDescriptor {
  kind: 'shell' | 'domain';
  surface?: 'home' | 'explore' | 'activity' | 'profile' | 'search';
  domain?: OshunDomain;
  pathSegments: string[];
  query: Record<string, string>;
  sourceUrl: string;
}

Backward Compatibility Rules#

OSHUN link resolver must support legacy links and normalize them:

  • tara://... and https://tara.app/... -> oshun://tara/...
  • veritas://... and https://www.veritas.news/... -> oshun://veritas/...

Legacy support is mandatory for migration period and should emit legacy_link_redirected telemetry.

Query and Attribution Rules#

  • Preserve utm_*, ref, campaign, and invite metadata through normalization.
  • Reject or sanitize unknown dangerous parameters.
  • Normalize key casing to lowercase for canonical internal handling.

Fallback Behavior (Mandatory)#

If route cannot be resolved:

  • open shell-safe fallback (/app/home equivalent)
  • present contextual message (content moved, content unavailable, or login required)
  • log structured failure event with error category

Security and Validation Rules#

  • Accept only allowlisted schemes (oshun, https) and known domains.
  • Reject unknown hosts for HTTPS deep links unless explicitly mapped.
  • Block executable/script payloads in path/query fields.
  • Gate sensitive routes behind auth and entitlement checks.
  • Never execute navigation side-effects before route validation completes.

Implementation Plan#

Phase 1: Contracts#

  • Define route contracts in libs/oshun/navigation.
  • Define route registry and canonical path builders/parsers.
  • Define canonical redirect map for legacy domain links.

Phase 2: Platform Integration#

  • Configure Expo linking for oshun:// scheme and associated domains.
  • Configure web middleware/handlers for /app/* and /d/* URL forms.
  • Implement resolver shared logic for mobile and web.

Phase 3: Domain Adapter Binding#

  • Bind canonical domain descriptors to adapter launch() actions.
  • Add typed fallbacks for unavailable domain/module/content states.

Phase 4: Migration and Hardening#

  • Add legacy link normalization tests.
  • Add push-notification and shared-link E2E coverage.
  • Add telemetry dashboards for resolution success/failure and latency.

Success Metrics#

  • Deep-link resolution success rate >= 99.5% for valid links.
  • p95 route resolution time <= 150ms before first navigation dispatch.
  • 100% canonicalization coverage for known legacy Tara/Veritas links.
  • No unresolved-link crash in production sessions.

Consequences#

Positive Consequences#

  • ✅ One understandable route contract across mobile/web/PWA.
  • ✅ Cleaner analytics for attribution and funnel analysis.
  • ✅ Safer validation and fallback handling.
  • ✅ Easier onboarding for new domain adapters.

Negative Consequences#

  • ❌ Adds central governance burden to route contract changes.
  • ❌ Requires migration work for legacy domain URL ecosystems.
  • ❌ Requires close coordination with auth/entitlement checks.

Risks and Mitigations#

Risk Probability Impact Mitigation
Legacy links missed during normalization Medium High Maintain explicit mapping table + production error sampling
Domain adapter rejects canonical route shape Medium Medium Contract tests between resolver and each adapter
Route contract drift between mobile and web Medium High Shared parser/builder package in libs/oshun/navigation
Open redirect/security gaps Low High Strict allowlist, validation, and security tests

Monitoring and Observability#

Track:

  • oshun.link_received
  • oshun.link_normalized
  • oshun.link_resolved
  • oshun.link_failed
  • oshun.legacy_link_redirected

Each event must include platform, source, route kind, domain (if present), and error category (if failed).

  • docs/adr/ADR-0013-oshun-shell-architecture-and-domain-adapters.md
  • docs/adr/ADR-0014-oshun-web-and-pwa-strategy.md
  • Future ADR dependencies: auth model, offline strategy, analytics taxonomy

References#

  • apps/tara/mobile/src/services/deepLinks.ts
  • apps/tara/mobile/app.json
  • apps/veritas/mobile/src/services/widget.ts
  • apps/veritas/mobile/src/services/oauth.ts
  • apps/veritas/mobile/app.json