This repo is a macOS app built with Swift + SwiftUI (Xcode project).
Quick facts:
- Primary project:
Checkpoint.xcodeproj - Primary scheme:
Checkpoint(xcodebuild -list) - Tests: none currently (no
*Teststargets/schemes) - No Cursor rules (
.cursor/rules/,.cursorrules) or Copilot rules (.github/copilot-instructions.md) found
- Build/run from Xcode using scheme
Checkpoint. - Signing: copy
Config.xcconfig.template->Config.xcconfigand setDEVELOPMENT_TEAM = <YOUR_TEAM_ID>(don’t commit personal/team changes unless asked).
# List schemes/targets
xcodebuild -list -json
# Build (Debug)
xcodebuild -scheme Checkpoint -configuration Debug -destination 'platform=macOS,name=Any Mac' build
# Build (Release)
xcodebuild -scheme Checkpoint -configuration Release -destination 'platform=macOS,name=Any Mac' build
# Clean
xcodebuild -scheme Checkpoint clean
# Static analysis (Xcode “Analyze”)
xcodebuild -scheme Checkpoint analyzeIf you see “multiple matching destinations”, add -destination 'platform=macOS,name=Any Mac'.
No repo-configured SwiftLint/SwiftFormat found.
Guidance:
- Match existing formatting/style near your changes.
- If adding lint/format tooling, do it as a dedicated change.
Typical (only if those tools get added):
swiftlint lint --strict
swiftformat .No unit/UI test targets are present today.
When tests exist:
# Run all tests
xcodebuild test -scheme Checkpoint -destination 'platform=macOS,name=Any Mac'
# Run a single test class
xcodebuild test -scheme Checkpoint -destination 'platform=macOS,name=Any Mac' -only-testing:CheckpointTests/MyTestClass
# Run a single test method
xcodebuild test -scheme Checkpoint -destination 'platform=macOS,name=Any Mac' -only-testing:CheckpointTests/MyTestClass/testExampleHigh-level structure under Checkpoint/:
Views/: SwiftUI views.ViewModels/: ObservableObject view models (MVVM).Services/: stateful services and app orchestration.Models/: small value types and documents.Protocols/: abstractions for dependency injection/testing.
Dependency style:
- Prefer depending on protocols (e.g.,
DataManagingProtocol) and injecting them. - Use singletons sparingly; the repo currently has
LogEntryStore.sharedandAppEventPublisher.shared.
Concurrency & threading:
- Many types are annotated
@MainActor(e.g., view models,DataManagerService). - Prefer
Task {}from UI actions to call async methods. - If a service owns concurrent state, isolate it (see
CountdownTimerService.Stateactor). - When bridging async work back to Combine/UI, publish on the main actor.
State management (SwiftUI):
- For new code, prefer Observation (
@Observable) overObservableObject. - Own an
@Observablemodel with@State; inject it and bind via@Bindablewhen the child needs writable bindings. - Keep
@State/@StateObjectpropertiesprivate.
Async work (SwiftUI):
- Keep
bodypure; avoid side effects inbodyor initializers. - Prefer
.task {}/.task(id:)for async work so it cancels automatically when the view disappears or the id changes.
Formatting:
- Indentation: 4 spaces.
- One statement per line; wrap argument lists vertically when they get long.
- Keep SwiftUI modifier chains readable; break lines at major modifier boundaries.
Imports:
- Import the minimum needed modules.
- Typical order (match file context):
Foundation,Combine, then UI modules (SwiftUI,UniformTypeIdentifiers).
Modern SwiftUI APIs (prefer):
foregroundStyle()overforegroundColor().clipShape(.rect(cornerRadius:))overcornerRadius().ButtonoveronTapGesture()unless you need gesture details.
Naming:
- Types:
PascalCase(LogWorkViewModel,DataManagerService). - Vars/functions:
lowerCamelCase(saveLogEntry,loadLogEntries). - Enums for domain events/errors:
PascalCasewith descriptive cases (ValidationError.emptyProject). - Prefer verb phrases for actions (
save…,load…,delete…,update…).
Types & access control:
- Prefer
structfor models/value types (LogEntry,CSVDocument). - Prefer
final classfor services unless subclassing is intended. - Default to the narrowest visibility that works (
privatehelpers,private(set)for published state).
Error handling:
- Prefer
LocalizedErrorenums for user-facing errors (seeValidationError). - Preserve root error context when rethrowing (e.g., wrap with a domain error that includes
localizedDescription). - Avoid force unwraps (
!) in new code; if unavoidable, justify with invariants.
Performance:
- Avoid creating expensive objects (e.g.,
DateFormatter()) inbodyor frequently-called computed properties; cache/static where it matters. - For user-entered search, prefer
localizedStandardContains()over plaincontains().
Logging:
- Debug logging is commonly guarded by
#if DEBUG. - Avoid logging sensitive data.
- If you introduce structured logging, prefer
os.Loggerand keep messages concise.
SwiftUI patterns:
- Views should be mostly declarative; keep business logic in view models/services.
- Use
@StateObjectfor owned view models,@ObservedObjectfor injected ones. - Use
@Environmentfor system actions (dismiss,openWindow). - Prefer
#Previewblocks for local view previews.
Combine usage:
- Store cancellables in a
Set<AnyCancellable>. - Use
.receive(on: DispatchQueue.main)when binding to UI state. - Prefer
assign(to:on:)for simple bindings; usesinkwhen side effects are needed.
Data & persistence:
- Current persistence uses
UserDefaultswith JSON encoding/decoding. - Keep keys stable (
checkpoint_interval,checkpoint_log_entries). - When changing model encoding, consider migrations/backwards compatibility.
- Don’t change signing/team IDs (
DEVELOPMENT_TEAM) unless explicitly requested. - Avoid broad reformatting; keep diffs focused.
- If you add tests or tooling (SwiftLint/SwiftFormat), isolate to a dedicated change set.