Merge pull request 'fix: remove CocoaPods references breaking build' (#26) from koda/remove-cocoapods-refs into main
This commit is contained in:
commit
928c5ff28f
2 changed files with 101 additions and 75 deletions
101
CLAUDE.md
Normal file
101
CLAUDE.md
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# Payfrit Beacon iOS
|
||||
|
||||
Native Swift iOS app for provisioning iBeacon hardware at restaurant tables. Repo: `payfrit-beacon-ios` on Forgejo.
|
||||
|
||||
## Purpose
|
||||
|
||||
Utility app for restaurant setup staff to:
|
||||
1. Scan for nearby BLE iBeacons (iBeacon + BLE + QR code)
|
||||
2. Check UUID against known bulk manufacturer defaults (ban list)
|
||||
3. Assign table names to beacons (smart-incremented)
|
||||
4. Provision beacon hardware via BLE GATT (DX-Smart, BlueCharm, KBeacon)
|
||||
5. Save beacon + auto-create service point records via API
|
||||
|
||||
## Environment
|
||||
|
||||
- **Server**: dev.payfrit.com (DEBUG) / biz.payfrit.com (RELEASE)
|
||||
- **API Base**: `https://dev.payfrit.com/api` (dev) / `https://biz.payfrit.com/api` (prod)
|
||||
- **Config**: `APIConfig.swift` — uses `#if DEBUG` compiler flag
|
||||
- **OTP**: Dev server uses magic OTP `123456` (no Twilio)
|
||||
|
||||
## Database (via API — no direct SQL)
|
||||
|
||||
| Table | PK | Key Columns |
|
||||
|-------|----|-------------|
|
||||
| Beacons | `ID` | `UUID`, `Name`, `BusinessID`, `IsActive` |
|
||||
| ServicePoints | `ID` | `BusinessID`, `Name`, `TypeID`, `Code`, `SortOrder`, `IsActive`, `BeaconID` |
|
||||
| Businesses | `ID` | `Name`, `ParentBusinessID` |
|
||||
|
||||
**Note**: `POST /api/beacons/save.php` auto-creates a ServicePoint when saving a beacon.
|
||||
|
||||
## API Endpoints Used
|
||||
|
||||
All endpoints are `.php`. Auth = `X-User-Token` header.
|
||||
|
||||
| Method | Endpoint | Auth | Purpose |
|
||||
|--------|----------|------|---------|
|
||||
| POST | /auth/loginOTP.php | No | Send OTP to phone |
|
||||
| POST | /auth/verifyLoginOTP.php | No | Verify OTP, get token |
|
||||
| POST | /businesses/list.php | Yes | List user's businesses |
|
||||
| POST | /servicepoints/list.php | Yes | List service points for business |
|
||||
| POST | /servicepoints/save.php | Yes | Create/update service point |
|
||||
| POST | /servicepoints/delete.php | Yes | Delete service point |
|
||||
| POST | /beacon-sharding/allocate_business_namespace.php | Yes | Allocate UUID+Major shard |
|
||||
| POST | /beacon-sharding/get_beacon_config.php | Yes | Get complete beacon config |
|
||||
| POST | /beacon-sharding/allocate_servicepoint_minor.php | Yes | Auto-assign minor value |
|
||||
| POST | /beacon-sharding/resolve_business.php | Yes | Resolve business by UUID+Major |
|
||||
| POST | /beacons/list.php | Yes | List beacons for a business |
|
||||
| POST | /beacons/lookupByMac.php | Yes | Lookup beacon by MAC address |
|
||||
| POST | /beacons/wipe.php | Yes | Decommission a beacon |
|
||||
| GET | /users/profile.php | Yes | Get user profile |
|
||||
|
||||
## Build & Deploy
|
||||
|
||||
Build in Xcode targeting iOS 17+. No local testing — deploy to device for BLE testing.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
PayfritBeacon/
|
||||
├── App/
|
||||
│ ├── AppPrefs.swift UserDefaults keys
|
||||
│ ├── AppState.swift ObservableObject — auth state, nav, business selection
|
||||
│ └── PayfritBeaconApp.swift App entry point
|
||||
├── Models/
|
||||
│ ├── BeaconConfig.swift Provisioning config (UUID, major, minor, txPower, etc.)
|
||||
│ ├── BeaconType.swift Enum: DXSmart, BlueCharm, KBeacon, Unknown
|
||||
│ ├── Business.swift Business model
|
||||
│ └── ServicePoint.swift Service point model
|
||||
├── Provisioners/
|
||||
│ ├── ProvisionerProtocol.swift Protocol — all provisioners implement this
|
||||
│ ├── DXSmartProvisioner.swift DX-Smart CP28 GATT provisioner (24-step write sequence)
|
||||
│ ├── BlueCharmProvisioner.swift BlueCharm BC037 provisioner
|
||||
│ ├── KBeaconProvisioner.swift KBeacon provisioner
|
||||
│ ├── FallbackProvisioner.swift Unknown device fallback
|
||||
│ └── ProvisionError.swift Shared error types
|
||||
├── Services/
|
||||
│ ├── APIClient.swift Actor-based REST client, all API calls
|
||||
│ ├── APIConfig.swift Base URLs, timeouts, dev/prod toggle
|
||||
│ ├── BLEManager.swift CoreBluetooth scanning + beacon type detection
|
||||
│ └── SecureStorage.swift Keychain-based token storage
|
||||
├── Utils/
|
||||
│ ├── BeaconBanList.swift Known bad UUID prefixes (factory defaults)
|
||||
│ ├── BeaconShardPool.swift 64 Payfrit shard UUIDs
|
||||
│ └── UUIDFormatting.swift UUID string formatting extensions
|
||||
└── Views/
|
||||
├── BusinessListView.swift Business selection screen
|
||||
├── DevBanner.swift Orange "DEV" banner overlay
|
||||
├── LoginView.swift OTP login screen
|
||||
├── QRScannerView.swift Camera-based QR code scanner for beacon pairing
|
||||
├── RootView.swift Root navigation
|
||||
└── ScanView.swift Main scan + provision UI
|
||||
```
|
||||
|
||||
## Key Architecture Notes
|
||||
|
||||
- **Modular provisioners**: Each beacon manufacturer has its own provisioner conforming to `ProvisionerProtocol`. No more monolithic `BeaconProvisioner.swift`.
|
||||
- **Actor-based API**: `APIClient` is a Swift actor (thread-safe by design).
|
||||
- **Secure storage**: Auth tokens stored in Keychain via `SecureStorage`, not UserDefaults.
|
||||
- **BLE scanning**: `BLEManager` handles CoreBluetooth device discovery and beacon type identification.
|
||||
- **DX-Smart protocol**: 24-step write sequence including frames 3-6 disable (full Android parity).
|
||||
- **QR scanner**: Camera-based QR code scanning for beacon pairing workflows.
|
||||
|
|
@ -9,7 +9,6 @@
|
|||
/* Begin PBXBuildFile section */
|
||||
103E16DE41E63F1AD9A7BAEC /* UUIDFormatting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B4971261F86B2A4D7579277 /* UUIDFormatting.swift */; };
|
||||
281CC856DD918C4CFA00EB67 /* ServicePointListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1775119CBC98A753AE26D84 /* ServicePointListView.swift */; };
|
||||
7D757E1341A0143A2E9EBDF4 /* Pods_PayfritBeacon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F6819A0F2BD2E9D84E7EDB4 /* Pods_PayfritBeacon.framework */; };
|
||||
D01000000001 /* PayfritBeaconApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02000000001 /* PayfritBeaconApp.swift */; };
|
||||
D01000000002 /* Api.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02000000002 /* Api.swift */; };
|
||||
D01000000003 /* BeaconBanList.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02000000003 /* BeaconBanList.swift */; };
|
||||
|
|
@ -30,13 +29,9 @@
|
|||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1AD023D1003AAD57ED3DBEAA /* Pods-PayfritBeacon.debug-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PayfritBeacon.debug-dev.xcconfig"; path = "Target Support Files/Pods-PayfritBeacon/Pods-PayfritBeacon.debug-dev.xcconfig"; sourceTree = "<group>"; };
|
||||
2B4971261F86B2A4D7579277 /* UUIDFormatting.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = UUIDFormatting.swift; sourceTree = "<group>"; };
|
||||
7F6819A0F2BD2E9D84E7EDB4 /* Pods_PayfritBeacon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PayfritBeacon.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8710F334FDFE10F0625EB86D /* BLEBeaconScanner.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BLEBeaconScanner.swift; sourceTree = "<group>"; };
|
||||
964B63D1857877BBEE73F1D1 /* BeaconShardPool.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BeaconShardPool.swift; sourceTree = "<group>"; };
|
||||
AFF542870BA2862FAB429A86 /* Pods-PayfritBeacon.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PayfritBeacon.debug.xcconfig"; path = "Target Support Files/Pods-PayfritBeacon/Pods-PayfritBeacon.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
B22C79E28AA521E6347E7F93 /* Pods-PayfritBeacon.release-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PayfritBeacon.release-dev.xcconfig"; path = "Target Support Files/Pods-PayfritBeacon/Pods-PayfritBeacon.release-dev.xcconfig"; sourceTree = "<group>"; };
|
||||
C03000000001 /* PayfritBeacon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PayfritBeacon.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C7C275738594E225BE7D5740 /* BeaconProvisioner.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BeaconProvisioner.swift; sourceTree = "<group>"; };
|
||||
D02000000001 /* PayfritBeaconApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayfritBeaconApp.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -55,7 +50,6 @@
|
|||
D02000000081 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
E1775119CBC98A753AE26D84 /* ServicePointListView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ServicePointListView.swift; sourceTree = "<group>"; };
|
||||
F100AA6D1E41596FCB1C1A39 /* DebugLog.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DebugLog.swift; path = PayfritBeacon/DebugLog.swift; sourceTree = "<group>"; };
|
||||
F1B84CA677516C50F6BE2294 /* Pods-PayfritBeacon.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PayfritBeacon.release.xcconfig"; path = "Target Support Files/Pods-PayfritBeacon/Pods-PayfritBeacon.release.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -63,31 +57,17 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
7D757E1341A0143A2E9EBDF4 /* Pods_PayfritBeacon.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
04996117E2F5D5BB2D86CD46 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AFF542870BA2862FAB429A86 /* Pods-PayfritBeacon.debug.xcconfig */,
|
||||
F1B84CA677516C50F6BE2294 /* Pods-PayfritBeacon.release.xcconfig */,
|
||||
1AD023D1003AAD57ED3DBEAA /* Pods-PayfritBeacon.debug-dev.xcconfig */,
|
||||
B22C79E28AA521E6347E7F93 /* Pods-PayfritBeacon.release-dev.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C05000000001 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D05000000002 /* PayfritBeacon */,
|
||||
C05000000009 /* Products */,
|
||||
04996117E2F5D5BB2D86CD46 /* Pods */,
|
||||
EEC06FED6BE78CF9357F3158 /* Frameworks */,
|
||||
F100AA6D1E41596FCB1C1A39 /* DebugLog.swift */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -126,14 +106,6 @@
|
|||
path = PayfritBeacon;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EEC06FED6BE78CF9357F3158 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7F6819A0F2BD2E9D84E7EDB4 /* Pods_PayfritBeacon.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
|
|
@ -141,11 +113,9 @@
|
|||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = C08000000003 /* Build configuration list for PBXNativeTarget "PayfritBeacon" */;
|
||||
buildPhases = (
|
||||
744B96DEA84C89E13D29B8B7 /* [CP] Check Pods Manifest.lock */,
|
||||
C07000000001 /* Sources */,
|
||||
C04000000001 /* Frameworks */,
|
||||
C09000000001 /* Resources */,
|
||||
66702B40BAEAF5430876D7CE /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
|
@ -202,47 +172,6 @@
|
|||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
66702B40BAEAF5430876D7CE /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-PayfritBeacon/Pods-PayfritBeacon-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-PayfritBeacon/Pods-PayfritBeacon-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PayfritBeacon/Pods-PayfritBeacon-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
744B96DEA84C89E13D29B8B7 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-PayfritBeacon-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
C07000000001 /* Sources */ = {
|
||||
|
|
@ -284,7 +213,6 @@
|
|||
/* Begin XCBuildConfiguration section */
|
||||
064DDD2A9238EC6900250593 /* Release-Dev */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = B22C79E28AA521E6347E7F93 /* Pods-PayfritBeacon.release-dev.xcconfig */;
|
||||
buildSettings = {
|
||||
APP_DISPLAY_NAME = "Payfrit Beacon BETA";
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
|
|
@ -436,7 +364,6 @@
|
|||
};
|
||||
B0D496FEA252D8DDA33F57A0 /* Debug-Dev */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 1AD023D1003AAD57ED3DBEAA /* Pods-PayfritBeacon.debug-dev.xcconfig */;
|
||||
buildSettings = {
|
||||
APP_DISPLAY_NAME = "Payfrit Beacon BETA";
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
|
|
@ -588,7 +515,6 @@
|
|||
};
|
||||
C0B000000003 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = AFF542870BA2862FAB429A86 /* Pods-PayfritBeacon.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
APP_DISPLAY_NAME = "Payfrit Beacon";
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
|
|
@ -623,7 +549,6 @@
|
|||
};
|
||||
C0B000000004 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = F1B84CA677516C50F6BE2294 /* Pods-PayfritBeacon.release.xcconfig */;
|
||||
buildSettings = {
|
||||
APP_DISPLAY_NAME = "Payfrit Beacon";
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue