Nextcloud Native documentation

Repository documentation

Adaptive app architecture

How verified contracts, semantic inference and reusable native components turn app APIs into useful interfaces.

Reading time 6 minutesRepository file ADAPTER_ARCHITECTURE.md View source

This document defines the durable boundaries for integrating independently versioned Nextcloud server apps without embedding their web interfaces. It is for contributors changing transport, discovery, repositories, caching, sync, or native feature adapters.

Last reviewed: 2026-08-20. Architecture rules may have changed. The default-branch document is the source of truth for the maintained contract.

Current product status belongs in COMPATIBILITY.md. Planned delivery belongs in ROADMAP.md. This document contains rules that must remain true as those documents change.

Core invariant

The native UI consumes stable, typed product models. It does not parse protocol payloads, build endpoint URLs, infer permissions from navigation, or execute an operation that lacks verified provenance.

Compose UI
    |
Feature state holders and repositories
    |
Typed adapters and semantic runtime
    |
Authenticated transport and persistence
    |
Platform services

Each layer owns one kind of change. A server API change should not force a Compose screen to parse new JSON. A platform credential-store change should not alter repository policy. A layout change should not alter mutation safety.

Ownership boundaries

Compose UI

  • Renders immutable state and sends explicit user intents.
  • Owns presentation state, focus, accessibility semantics, and adaptive layout.
  • Does not own network requests, protocol parsing, persistence, retry loops, or conflict policy.
  • Reuses semantic components for shared interaction patterns. App-specific UI is justified only by behavior that cannot be represented safely by a shared component.
  • Keeps composables small enough to review. Extract state holders, pure models, and reusable surfaces before adding another independent responsibility to a large screen.

Repositories and feature state

  • Provide the single source of truth for cached and remote feature state.
  • Own refresh, pagination, ETags, dirty state, retries, conflicts, and cache invalidation.
  • Expose typed loading, ready, stale, partial-failure, and blocking-failure states instead of throwing protocol exceptions into the UI.
  • Merge successful remote responses transactionally.
  • Keep usable cached content visible when a refresh fails.

Adapters

  • Translate one verified protocol or app-version family into shared models.
  • Remain stateless apart from immutable capability and version configuration.
  • Validate required capabilities, versions, endpoint paths, permissions, and response shapes before enabling an action.
  • Preserve unknown response fields only through an explicit typed extension value. Do not use Any as a compatibility strategy.
  • Fall back to a supported generic adapter when an optimized app-specific path is unavailable. Never fall back to a hidden web view.

Transport

  • Owns authentication, product identification, TLS, redirect policy, bounded bodies, case-insensitive response headers, and same-origin enforcement.
  • Accepts typed request data from adapters. The UI never constructs requests.
  • Supports standard HTTP and required WebDAV methods without placing DAV parsing in platform launchers.
  • Rejects DTDs and external entities in XML.
  • Allows an external origin only through a feature designed as an explicit browser or application handoff.

Persistence and sync

  • Scope every record, cache key, queued operation, and diagnostic identifier to an opaque local account ID.
  • Keep credential material out of metadata databases and diagnostics.
  • Publish files atomically after complete writes.
  • Preserve originals unless the user explicitly chooses replacement.
  • Bound automatic caches; keep offline files and unresolved conflict copies durable until their documented lifecycle permits removal.
  • Queue only operations with defined idempotency and conflict behavior.

Platform services

Platform source sets own operating-system behavior: credentials, lifecycle, background scheduling, filesystem providers, notifications, media sessions, external handoff, packaging, and accessibility integration. Protocol policy and parsing belong in shared code even when execution uses a platform client.

NextcloudPlatformServices is an integration boundary, not a place to collect every product feature. When Android and desktop implementations repeat protocol logic, extract a shared adapter or repository. Keep separate implementations when lifecycle or operating-system semantics are genuinely different.

Capability and discovery rules

Capabilities and versioned API descriptions are authoritative. Navigation entries and successful guesses are not proof that an operation is safe.

  • Preserve a typed capability snapshot per account with its fetch time and server/app versions.
  • Revalidate cached descriptors when the server version, app version, capability fingerprint, OpenAPI fingerprint, or adapter version changes.
  • Treat response-shape inference as read-only evidence.
  • Require advertised OpenAPI or a reviewed adapter for writes.
  • Keep dynamic endpoints relative and inside approved same-origin prefixes.
  • Omit behavior whose provenance or permission model is ambiguous.

See DYNAMIC_APP_DESCRIPTOR.md and NATIVE_SCHEMA.md for the serialized trust boundaries.

Mutation policy

Every operation declares its risk before it reaches the UI:

Level Meaning Required behavior
Read No intended remote mutation May run for loading or explicit refresh.
Reversible Small, visible, reversible write Direct user intent and rollback on failure.
Guarded Content change with concurrency risk Permission check, revision guard, conflict UI.
Destructive Delete, overwrite, or hard-to-reverse change Target-specific confirmation and no blind background retry.
Privileged handoff Server administration or primary-password confirmation Explain the effect and open authenticated server administration.

Runtime evidence may raise the risk level, such as when a move would overwrite an existing target. It must never lower the declared level silently.

Stored Login Flow app passwords must not be treated as primary passwords for strict administrator confirmation. The client must not collect or retain a primary account password to bypass that boundary.

Error and cancellation rules

Errors must retain enough structured context to support recovery and safe diagnostics without exposing private data.

  • Map transport, authentication, permission, validation, conflict, capacity, cancellation, and unexpected failures into distinct typed outcomes.
  • Never convert coroutine cancellation into an ordinary failed request. Rethrow cancellation before broad exception handling.
  • Do not use getOrNull() or an empty catch when the caller must distinguish unavailable data from a failed operation.
  • Add operation and stage identifiers at subsystem boundaries. Do not include server URLs, paths, filenames, payloads, credentials, or response bodies.
  • Preserve the original cause internally while presenting an actionable, non-technical message to the user.
  • A retry must be bounded and safe for the operation. Ambiguous delivery of a mutation requires reconciliation before another submission.

Offline and conflict rules

Repositories use stale-while-revalidate behavior:

  1. Emit usable cached data immediately.
  2. Mark it as refreshing when remote work starts.
  3. Commit a successful response transactionally.
  4. Keep cached data and expose a non-blocking error when refresh fails.
  5. Show a blocking error only when no usable state exists.

Writes require an explicit conflict contract. ETag-protected text or note saves may be queued when their base revision and payload are durable. Deletes, administrator actions, Talk messages, and hard-to-reverse recognition changes must not be queued by default.

Test contract

Each boundary has a corresponding test responsibility:

  • Protocol fixtures cover parsing, omitted and unknown fields, version gates, same-origin checks, size limits, and hostile XML.
  • Repository tests cover cache refresh, pagination, transactional merge, cancellation, retry limits, conflicts, and process restart recovery.
  • Compose tests cover semantics, loading, empty, stale, partial failure, permission denial, confirmation, adaptive layout, and keyboard/touch access.
  • Platform tests cover credential stores, filesystem paths and providers, background scheduling, external handoff, packaging, and lifecycle recovery.
  • Live-server audits use synthetic disposable accounts, record exact tested versions, and remain separate from deterministic unit and integration tests.

A bug fix adds the smallest regression test at the layer where the invariant failed. Tests should assert public behavior, not copied implementation details.

Review checklist

Before merging an adapter or repository change, confirm:

  • The responsibility is in the correct layer.
  • Shared behavior is implemented once without hiding platform differences.
  • Every write has provenance, permission, conflict, and confirmation policy.
  • Cancellation survives all broad exception boundaries.
  • Cache and queued-operation state survives interruption safely.
  • Diagnostics identify the failed stage without private content.
  • Tests cover success, empty, partial, offline, denied, malformed, cancelled, conflict, and retry-exhausted paths that apply.

Primary protocol references