This page explains the fundamental concepts that define how TheCompanyApp works. Understanding these concepts is essential for both users and developers.
1. Company-Scoped Multi-Tenancy
Users often need to manage multiple businesses or participate in different organizations — but mixing data between them creates chaos.
Every piece of data in TheCompanyApp (except user credentials) belongs to exactly one Company . The companyID attribute acts as a tenant identifier, ensuring complete data isolation.
Copy User's Device
├── Company A (Owner)
│ ├── Inventory items scoped to Company A
│ ├── Orders scoped to Company A
│ └── Contacts scoped to Company A
├── Company B (Participant)
│ ├── Inventory items scoped to Company B
│ ├── Orders scoped to Company B
│ └── Contacts scoped to Company B
└── Company C (Owner)
└── Data scoped to Company C All queries filter by the currently selected company:
Why This Design Exists
Security : Prevents accidental data leakage between companies
Performance : Queries return only relevant data
Scalability : Support unlimited companies per user
Flexibility : Users can be owners of some companies, participants in others
2. Dual Persistent Store Architecture
The Private Store
File : TheCompanyApp.sqlite
CloudKit Database : Private Database
Contains :
Companies created by this user (as owner)
UserPass credentials for all companies
All company-scoped data for owned companies
The Shared Store
File : TheCompanyApp-shared.sqlite
CloudKit Database : Shared Database
Contains :
Companies shared by other users (as participant)
All company-scoped data for shared companies
Read from the CKShare zone
Why Two Stores?
CloudKit distinguishes between:
Private data : Accessible only by the user across their devices
Shared data : Accessible by multiple users via CKShare
The dual-store architecture mirrors this model, ensuring:
Private credentials never sync to shared zones
Owned companies stay in private database
Shared companies automatically appear in shared database
3. CloudKit Sharing Model
Sharing Lifecycle
Owner Creates Company (Private Store)
User creates a company via CreatCUOC.swift
Company is saved to Private Store
CloudKit syncs to Private Database
UserPass is created for login (never shared)
Owner Shares Company
Owner taps "Share Company" in ShareAppView.swift
App creates a CKShare with Companies as root record
All related entities (inventory, orders, etc.) are enlisted into the share
UICloudSharingController generates a share URL
Owner sends URL to participants via Messages/Email
Participant Accepts Share
Participant opens share URL in Safari
URL opens TheCompanyApp via universal link
App calls acceptShare() on CloudKit
CloudKit adds company to participant's Shared Database
App syncs data to Shared Store
Company appears in participant's company list
Share Permissions
Owner : Full read/write access, can modify share participants
Participant : Read/write access to company data (based on AccessControl)
Read-Only Participant : View-only access (future enhancement)
4. Identity and Authentication
iCloud Identity
Primary authentication via user's Apple ID
No separate account creation required
CloudKit uses CKRecord.Reference for user identification
UserPass Credentials
Secondary authentication for company access
Stored in Private Store only (never shared)
Each user creates their own username/password per company
Enables access control even among invited participants
The AccessControl entity manages:
userID : UUID identifying the user
companyID : Which company this access applies to
isOwner : Boolean flag for company ownership
deptMask : Department-based permissions (bitmask)
managerMask : Manager-level permissions (bitmask)
5. Company Selection and Context
@AppStorage State
The currently selected company is persisted via:
Context Resolution
When the user switches companies, the app:
Reads selectedCompanyIDString from AppStorage
Resolves the Companies object via resolveCompanyAndStore()
Determines if the company is in Private or Shared Store
Sets up filtered fetch requests for all views
Preferred Store Logic
For participants who also own the same company (edge case):
This prefers the Shared Store version to ensure participants see real-time updates from the owner.
6. Data Enlistment
What is Enlistment?
When new records are created for a shared company, they must be enlisted into the CKShare zone so other participants can see them.
This method:
Checks if the company has an associated CKShare
If yes, enlists the new object into that share's zone
If no, it's a no-op (company isn't shared)
When Enlistment Happens
Creating dispatch records
Any company-scoped entity creation
7. Store Assignment
When creating a new object, Core Data must know which persistent store to save it to.
This explicitly assigns the object to the same store as its parent company, ensuring:
Owner-created data stays in Private Store
Participant-created data goes to Shared Store
No cross-store relationship issues
8. Sync and Conflict Resolution
When conflicts occur (same record modified on two devices):
CloudKit's server state wins
Local changes are merged at the property level
Recent writes typically take precedence
Remote Change Handling
When CloudKit pushes changes:
Core Data posts .NSPersistentStoreRemoteChange notification
App refreshes the view context
SwiftUI views automatically update via @FetchRequest
9. Asynchronous Save Strategy
Blocking Saves (Traditional)
Waits for CloudKit sync, blocks UI thread.
Async Saves (Optimized)
Returns immediately, CloudKit syncs in background.
Why This Matters
Prevents UI freezes during save operations
Improves user experience, especially on slow networks
CloudKit sync happens transparently
10. Subscription Tiers and Permissions
tier = "Free" on Companies entity
Owner access only (no sharing)
tier = "Business" on Companies entity
AccessControl enforcement
Enterprise Tier
tier = "Enterprise" on Companies entity
Advanced features (analytics, AI)
Tier limits are checked in:
ShareAppView.swift: Prevents sharing on Free tier
CompanyView.swift: Shows upgrade prompts
Backend validation (future): Server-side enforcement
These core concepts form the foundation of TheCompanyApp's architecture:
Company-Scoped Multi-Tenancy
Data isolation and security
Proper CloudKit private/shared separation
Real-time multi-user collaboration
Identity via iCloud + UserPass
Simple yet secure authentication
Store Assignment & Enlistment
Correct data placement and sharing
Responsive UI without blocking
Understanding these concepts will help you effectively use, extend, and troubleshoot TheCompanyApp.
Last updated 33 minutes ago