Weaknesses of Current Development
vv-iOS and vv-web double code bases
vv-web
- Web application
- Runs in browsers
- Likely built with React, Vue, or another JS framework
- Uses the same backend APIs, Amplify services, or GraphQL endpoints as vv-ios
- Possibly includes admin tools the mobile app doesn’t need
vv-ios
- Mobile application
- Built with a mobile framework (React Native)
- Uses Amplify backend
- Lives in App Store land
- User-facing or crew-facing mobile experience
- Because React Native and React Web do not share UI components, in practice:
- UI code is duplicated
- State management is duplicated
- Business logic is often duplicated
- API calls are sometimes duplicated
- Offline logic is duplicated
- Navigation logic is duplicated
Solution: Capacitor
Business logic in the front-end
Both the web app and the iOS app do a lot of the thinking (logic) on the user’s device. When the app starts, it downloads all the records the user is allowed to see from the server. On the web, those records go into a sort of “local storage box” (Redux) in the background. iOS does something similar with DataStore.
Once the records are on the device, each app then runs its own set of rules to calculate things like:
- Which tasks are due
- How many tasks match a filter
- What should show on dashboard tiles
In other words, each app is doing its own maths on the same downloaded data, which is why they can behave differently.
Solution: Fetch counts directly from the server
Offline
The Core Problem: Amplify DataStore is not designed for our scale or data shape
DataStore + AppSync + DynamoDB works ONLY when:
- Data models are small
- Relationships are minimal
- Sync is uni-directional and low-volume
- Users have small datasets
- Conflicts are rare
- No large relational queries are needed
- Offline-first behavior is simple (not multi-user, multi-role)
- Our app violates all of these:
- We have large datasets
- Highly relational data (vessels → docs → tasks → users → roles → approvals)
- Many users editing shared documents
- Lots of incremental updates
- Multi-platform apps duplicating logic
- Navigation logic is duplicated
- Heavy GraphQL models
- Dirty sync state when iOS stalls
This means our architecture is fighting DataStore. Not because we implemented it wrong — because DataStore is just the wrong tool for a complex offline-first enterprise system.
Fixing DataStore Won’t Solve the Root Problems
Even if we:
- Add conflict resolvers
- Optimise sync expressions
- Fix the iOS sync stall
- Move relational data to Postgres
- Rewrite the GraphQL schema
- Reduce the collection size
- Rebuild business logic
We’re still left with:
- A sync engine designed for small offline apps
- A heavy enterprise dataset
- Thousands of records per user
- Complex relationships
- Many-to-many user interactions
- Strict offline consistency requirements
Solution: Capacitor
Can Capacitor replace React Native to unify code?
Explore a detailed analysis of Capacitor as a solution to the dual codebase
problem
Slow Loading Times
Vessel Vanguard’s current dashboard is built as a Single Page Application (SPA) that loads almost the entire system’s data immediately after the user logs in. This was done to simplify UI interactions but has created serious performance issues.
- What's going wrong
- The dashboard loads all tasks, all equipment, all documents, all maintenance, for all vessels, every time a user logs in.
- The UI uses inline expansions, meaning individual tasks/documents expand inside the same page rather than loading a dedicated page
- Because everything is synced upfront, the initial load can be very slow — often 10–40 seconds depending on vessel count and dataset size.
- This creates a poor first-impression and prevents scaling to large fleets
Solution: Create multi-page application that loads only the data needed for the page the user is viewing
GitHub Processes Need Love - Workflow Pain
The current GitHub structure is close, but it contains typical “single-developer legacy architecture”. A lot of the pain we are experiencing is not technical — it’s workflow. Amplify, Cognito, DynamoDB, and model generation are all solid when the Git and environment workflow is correct.
- Right now the issues came from:
- Feature branches are not deleted
- No clear long-lived develop branch
- Release candidates nested under odd names
- No clear rules about when to branch, merge, freeze, or delete
- PR flow depends on one dev knowing the unwritten rules
- Multiple repos modifying the same backend
- No single source of truth for schema or auth
- Devs pushing backend changes from different machines
- Inconsistent Amplify environments (dev/stg/prod)
- Dead database tables, user-pools, code left hanging around
- No branch strategy
- CI/CD not enforcing backend ownership
- Schema drift between apps
- Environments being overwritten unintentionally
Solution:
- Git branching strategy - simple and scalable
- Single backend-owner repo
- Allowed actions per repo
- Environment lifecycle
- Backend deploys only from CI/CD
- Frontend repos only pull
- Capacitor replaces native iOS
- Model/codegen defined and consistent
If we can eliminate 90% of the prior chaos. The platform becomes predictable, stable, and easy to reason about. And everything else (models, Auth, schema, push conflicts) will just work.