Native Mobile Clients and Shared Contracts
Culina's SwiftUI client shows what can be shared with a web app, while Muninn highlights the limits of that reuse.
Share the product model, respect the platform
Culina has a React web application and a native SwiftUI iOS client backed by the same ASP.NET Core API. The native client covers recipes, cookbooks, ingredients, allergens and account settings. Its screens are organized around observable view models and service interfaces.
The shared backend centralizes business rules and data access. The clients can then present the same domain through platform-specific navigation and interaction patterns. Shared data does not require a shared rendering layer.
An API contract is a boundary, not an entire interface
Culina’s web application consumes a generated TypeScript client from OpenAPI. The iOS application uses its own service interfaces and MSAL identity integration. These are different client structures around a common backend.
An API can define the shape of a recipe or cookbook without deciding how a screen loads, presents an error or preserves an unfinished interaction. Those concerns still need a home in each client. View models and services give the native application places to organize them without embedding networking throughout the view hierarchy.
The distinction matters for feature scope too. Recipe authoring and administrative review are documented web workflows; the presence of a native client should not be read as a claim of complete web/iOS feature parity.
Encryption makes future client work broader
Muninn currently focuses on its React web app and backend. SwiftUI for iOS and Jetpack Compose for Android are planned, not shipped native clients.
Its intended reuse includes both API and encryption contracts. A native journal client would need to interpret encrypted entry formats, participate in synchronization and handle recovery consistently. Browser-specific implementations such as WebCrypto and IndexedDB cannot simply be treated as native UI code to reuse unchanged.
That is a roadmap constraint rather than an implementation claim. The shared contract can describe interoperability while leaving cryptography, storage and interaction implemented appropriately for each platform.
Test at the boundaries users cross
Culina includes iOS unit and integration tests and XCUITest alongside backend and web quality tooling. That combination reflects the different responsibilities involved: application behavior, service integration and an actual user journey through the native interface.
The value of a common backend is a consistent product model. Delivering a native experience still requires explicit client engineering around that model.
