# Project Structure KisaniCal (display name **Wenza**) is a personal productivity + fitness iOS app, built with SwiftUI and generated from `project.yml` via [XcodeGen]. It ships an iOS app, a WidgetKit extension, and an optional watchOS companion. ## Build targets Defined in [`project.yml`](project.yml): | Target | Type | Platform | Bundle ID | |---|---|---|---| | `KisaniCal` | application | iOS 16+ | `com.kutesir.KisaniCal` | | `KisaniCalWidgets` | app-extension | iOS 18+ | `com.kutesir.KisaniCal.KisaniCalWidgets` | | `WenzaWatch` | application | watchOS 10+ | `com.kutesir.KisaniCal.watchkitapp` | | `KisaniCalTests` | unit-test | iOS 16+ | — | `WenzaWatch` is built/embedded only when the watchOS platform is installed (see the commented `embed` note in `project.yml`). ## Directory layout ``` KisaniCal/ repo root (Gitea: kutesir/KisaniCal) │ ├── project.yml XcodeGen spec — source of truth for the .xcodeproj ├── KisaniCal.xcodeproj generated (do not hand-edit) │ ├── KisaniCal/ 📱 main iOS app target │ ├── KisaniCalApp.swift @main entry point │ ├── ContentView.swift root view / tab shell │ ├── KisaniCal.entitlements │ ├── LaunchScreen.storyboard │ ├── Views/ SwiftUI screens (13) │ │ ├── TodayView, CalendarView, MatrixView tasks │ │ ├── WorkoutView, AddExerciseSheet fitness │ │ ├── AuthView, OnboardingView, ProfileSetupView, SplashView │ │ ├── SettingsView, TutorialView │ │ └── TaskContextMenu, TodayMenuFeatures │ ├── Managers/ stateful service singletons (10) │ │ ├── AuthManager, CloudSyncManager auth + iCloud KVS │ │ ├── HealthKitManager, SpeechRecognizer system frameworks │ │ ├── NotificationManager, LiveActivityManager, ShortcutHandler │ │ ├── TutorialManager │ │ └── AppGroup, TaskActivityAttributes shared with widgets │ ├── Models/ TaskItem, ExerciseModels, CalendarGrid │ ├── Components/ SharedComponents, FloatingTabState │ └── Theme/ DesignTokens │ ├── KisaniCalWidgets/ 🧩 WidgetKit extension (iOS 18+) │ ├── KisaniCalWidgets.swift, MyTasksWidget, EventCountdownWidget │ ├── TaskLiveActivity, WidgetViews, WidgetData │ └── Info.plist, .entitlements │ ├── WenzaWatch/ ⌚️ watchOS companion (build-optional) │ └── WenzaWatchApp.swift, Info.plist, .entitlements │ ├── KisaniCalTests/ 🧪 unit tests (the CI test target) │ └── CalendarGridTests, RecurrenceTests, NLRecurrenceParseTests │ ├── .gitea/workflows/ 🔧 CI/CD (Gitea Actions) │ ├── ci.yml build + test on PRs into main/develop │ └── release.yml archive + export IPA on push to main │ ├── scripts/gitea-setup.sh Gitea branch-protection / default-branch setup ├── ExportOptions.plist IPA export template │ ├── CONTRIBUTING.md branch workflow + PR gate rules ├── PRODUCT.md product brief, users, design principles ├── SERVICES.md backing services / infra notes ├── ISSUES.md running issue log (KC-## ids) └── Sanctum-Auto-FailOver-Uptime-Kuma.md ``` ## Architecture A flat SwiftUI **MVVM-lite** layout, organized by role rather than by feature: - **Views** — SwiftUI screens, one file per screen. - **Managers** — `ObservableObject` service singletons holding cross-cutting state (auth, iCloud sync, HealthKit, notifications, speech, Live Activities). - **Models** — plain data types (`TaskItem`, exercise/workout models, calendar grid math). - **Components / Theme** — shared UI and design tokens. Three product domains coexist in one app: 1. **Tasks** — Today list, Calendar, Eisenhower Matrix; natural-language quick add (with voice via `SpeechRecognizer`). 2. **Fitness** — workout logging with weighted/bodyweight sets; reads/writes Health via `HealthKitManager`. 3. **Calendar / events** — surfaced on the dashboard, in **widgets**, and as **Live Activities**. ### Cross-target code sharing `KisaniCal/Managers/AppGroup.swift` and `TaskActivityAttributes.swift` are compiled into **both** the app and the widget extension (see the widget target's `sources` in `project.yml`), so task/activity data is shared through the App Group container. ### Persistence & sync State is persisted locally and mirrored to **iCloud key-value store** via `CloudSyncManager`. Restore-on-launch rehydrates data after reinstall/update (see ISSUES.md KC-39 for the save/restore symmetry the sync layer must keep). [XcodeGen]: https://github.com/yonaskolb/XcodeGen