This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a native iOS application that provides integration between Kia/Hyundai/Genesis electric vehicles and Apple Maps. The app allows users to view their vehicle's battery status and manage their vehicles through Apple's ecosystem, with Siri and Maps integration via Intents extensions.
# Build all targets
xcodebuild -project KiaMaps.xcodeproj -scheme KiaMaps -configuration Debug build
# Build for specific target
xcodebuild -project KiaMaps.xcodeproj -target KiaMaps -configuration Debug build
# Clean build folder
xcodebuild -project KiaMaps.xcodeproj -scheme KiaMaps clean- Apple Developer Account with Porsche team access
- Hand-created provisioning profile with Porsche group ID
- Porsche API credentials configured
-
Open Project in Xcode
open KiaMaps.xcodeproj
-
Configure Signing & Capabilities
- Select
KiaMapsproject in navigator - Go to
Signing & Capabilitiestab - For Main App Target (KiaMaps):
- Uncheck "Automatically manage signing"
- Select your Porsche team from dropdown
- Choose your hand-created provisioning profile
- Set Bundle Identifier with Porsche group ID (e.g.,
com.porsche.kiamaps)
- For Extensions (KiaExtension, KiaExtensionUI):
- Repeat above steps for each extension target
- Use appropriate bundle identifiers:
com.porsche.kiamaps.extensioncom.porsche.kiamaps.extension-ui
- Select
-
App Groups Configuration
- Add App Groups capability to all targets
- Use Porsche group ID:
group.com.porsche.kiamaps - Ensure all targets use the same App Group ID for shared data
-
Intents Configuration
- Verify Siri capability is enabled for main app
- Ensure Intents Extension has proper entitlements
- Check Maps integration entitlements
-
Build and Run
- Select physical device (required for Intents)
- Choose
KiaMapsscheme - Build and run with Cmd+R
- Profile mismatch: Ensure provisioning profile includes your device UDID
- Bundle ID conflicts: Verify bundle IDs match those in provisioning profile
- Entitlements: Check that App Groups and Intents entitlements match profile
- Team selection: Confirm correct Porsche team is selected for all targets
- Physical iOS device (Simulator doesn't support Intents properly)
- iOS 14.0+ for full Intents functionality
- Device must be registered in provisioning profile
- KiaMaps: Main iOS application
- KiaExtension: Intents extension for Siri/Maps integration
- KiaExtensionUI: Intents UI extension for rich interactions
The project follows a clean SwiftUI architecture with these key components:
-
App Layer (
KiaMaps/App/): SwiftUI app entry point and main viewsAppDelegate.swift: App lifecycle using SwiftUI @mainMainView.swift: Primary app UI with vehicle managementVehicleStatusView.swift: Vehicle status display
-
Core Layer (
KiaMaps/Core/): Business logic and data management- Api (
Core/Api/): Network layer for vehicle API communicationApi.swift: Main API client with OAuth2 authentication flowApiConfiguration.swift: API endpoint configurationApiEndpoints.swift: API endpoint definitions
- Authorization (
Core/Authorization/): Authentication and securityAuthorization.swift: Token management and storageKeychain.swift: Secure credential storage
- Vehicle (
Core/Vehicle/): Vehicle-specific logicVehicleManager.swift: Vehicle data caching and parametersKiaParameters.swift,PorscheParameters.swift: Vehicle-specific configs
- Responses (
Core/Responses/): API response models and data structures
- Api (
-
Extensions (
KiaExtension/,KiaExtensionUI/): Siri/Maps integrationIntentHandler.swift: Handles Siri shortcuts and Maps integrationCarListHandler.swift: Manages vehicle list for SiriGetCarPowerLevelStatusHandler.swift: Provides battery status to Maps/Siri
- SwiftUI MVVM: Uses SwiftUI's declarative UI with observable state management
- Async/Await: Modern Swift concurrency for API calls
- OAuth2 Flow: Complex authentication with multiple steps (login, device registration, token exchange)
- Caching Strategy: Vehicle status cached with expiration via
VehicleManager - Multi-brand Support: Configurable API endpoints for different vehicle brands
The app implements a multi-step OAuth2 authentication:
- Login page retrieval and form submission
- Device ID registration with push notification setup
- Authorization code exchange
- Access token retrieval
- User integration setup
- Vehicle data flows from API → VehicleManager (caching) → SwiftUI Views
- Status updates trigger vehicle refresh via API
- Intents extensions access vehicle data for Siri/Maps integration
The app uses compile-time configuration via AppConfiguration protocol:
- API endpoints and credentials
- Vehicle VIN specification
- Brand-specific parameters
This project does not currently have unit tests or a testing framework configured. When adding tests:
- Consider using XCTest framework
- Focus on API layer and VehicleManager logic
- Mock network requests for reliable testing
IMPORTANT: Follow consistent naming conventions for better code readability and Swift conventions.
// ✅ CORRECT: Network calls use "fetch" prefix
func fetchVehicleStatus(_ vehicleId: UUID) async throws -> VehicleStatus
func fetchUserProfile() async throws -> UserProfile
func fetchMQTTDeviceHost() async throws -> MQTTHostInfo
// ✅ CORRECT: Variables use descriptive names without "get"
var userProfile: UserProfile?
var vehicleStatus: VehicleStatus?
var connectionState: ConnectionState?
// ✅ CORRECT: Update/set operations use "update" prefix
func updateVehicleStatus(_ status: VehicleStatus)
func updateConnectionState(_ state: ConnectionState)
// ❌ INCORRECT: Don't use "get" prefix
func getVehicleStatus() // Use fetchVehicleStatus() instead
func getUserProfile() // Use fetchUserProfile() instead
func getMQTTHost() // Use fetchMQTTDeviceHost() instead
// ❌ INCORRECT: Don't use unnecessary prefixes for variables
var getUserProfile: UserProfile? // Use userProfile instead
var getVehicleStatus: VehicleStatus? // Use vehicleStatus insteadNaming Guidelines:
- Network calls: Use
fetchprefix for API calls that retrieve data - Variables: Use descriptive names without prefixes when possible
- Update operations: Use
updateprefix for methods that modify existing data - Boolean properties: Use
is,has,can,shouldprefixes (e.g.,isConnected,hasError) - Computed properties: No prefix needed, use descriptive names (e.g.,
connectionTimeString,statusColor)
Why avoid "get" prefix:
- Swift conventions favor concise, descriptive names
- "get" is redundant - functions naturally "get" or return values
- Better readability:
fetchUserProfile()vsgetUserProfile() - Consistency with Apple's naming conventions
IMPORTANT: Always use the AbstractLogger system for logging instead of print statements in production code.
// ✅ CORRECT: Use AbstractLogger for structured logging
// Import the logging system
import Foundation
// Use global convenience functions with appropriate categories
logDebug("Starting vehicle refresh", category: .vehicle)
logInfo("Vehicle status updated: \(vehicleId)", category: .vehicle)
logError("API request failed: \(error.localizedDescription)", category: .api)
// Alternative: Use the shared logger directly
SharedLogger.shared.logger.debug("MQTT connection established", category: .mqtt)
SharedLogger.shared.logger.warning("Battery level low", category: .vehicle)
SharedLogger.shared.logger.fault("Critical system failure", category: .app)
// ❌ INCORRECT: Don't use print in production code
print("Debug: Vehicle status updated") // Remove or replace with logDebug
// ❌ INCORRECT: Don't use direct os_log calls anymore
os_log(.debug, log: Logger.vehicle, "message") // Use logDebug insteadWhy use AbstractLogger:
- Unified logging system across app and extensions
- Automatic remote logging to development server
- Built-in categorization with predefined categories
- Integration with both os_log and remote logging
- Better debugging capabilities during development
- Consistent logging format across the entire app
Available Log Levels:
logDebug()- Detailed debugging informationlogInfo()- General informational messageslogWarning()- Warning conditions that should be notedlogError()- Recoverable errorslogFault()- Critical errors/system failures
Available Categories:
.api- API calls and network requests.auth- Authentication and authorization.server- Local server operations.app- General app lifecycle and events.ui- User interface events.bluetooth- Bluetooth operations.mqtt- MQTT communication.keychain- Keychain and secure storage.vehicle- Vehicle data and operations.ext- Extension and Siri integration.general- Default category for uncategorized logs
Usage Guidelines:
- Always specify an appropriate category for better log organization
- Use descriptive messages that include context
- Include relevant data in log messages (user IDs, error codes, etc.)
- Use appropriate log levels - don't log everything as
.info - The system automatically handles file/function/line information
CRITICAL RULE: After making ANY code changes, you MUST immediately build the project to verify compilation:
# Required command after every code change
xcodebuild -project KiaMaps.xcodeproj -scheme KiaMaps -configuration Debug build 2>&1 | grep -E "(error|warning|failed):" | grep -v "appintentsmetadataprocessor"Why this is mandatory:
- Swift has strict type checking that catches errors at compile time
- Missing imports, wrong property names, and type mismatches must be fixed immediately
- Enum cases and struct properties change - compilation verifies correctness
- Icon names in
IconNameenum are limited - verify they exist before using - API response structures may not match assumptions - build catches these issues
Process:
- Make code changes
- IMMEDIATELY run build command
- Fix any errors before continuing
- Only proceed to next changes after successful build
This rule prevents:
- Accumulating multiple compilation errors
- Wasting time on non-functional code
- Integration issues when merging changes
- Runtime crashes from basic type errors
- Extend
VehicleParametersprotocol - Add brand-specific parameters file (see
KiaParameters.swift) - Update
VehicleManager.vehicleParamterswitch statement - Add API configuration for new endpoints
- MUST BUILD after each change
- Update
ApiEndpoints.swiftfor new endpoints - Modify
Api.swiftfor new API methods - Update response models in
Core/Responses/ - MUST BUILD after each change
- Add new intent definitions in
KiaExtension/IntentHandler.swift - Create corresponding handler files
- Update
KiaExtensionUI/for rich UI experiences - MUST BUILD after each change
- Main app UI in
KiaMaps/App/MainView.swift - Vehicle status display in
KiaMaps/App/VehicleStatusView.swift - Reusable components in
KiaMaps/App/Views/ - Check IconName enum in
KiaMaps/App/Views/DataRowView.swiftfor available icons - MUST BUILD after each change