A native iOS app built with SwiftUI that allows Zürcher Kantonalbank (ZKB) users to track their finances by parsing uploaded PDF monthly statements.
🚀 Quick Start: See QUICKSTART.md - Get running in 5 minutes 📖 Full Setup Guide: See SETUP.md - Comprehensive Xcode configuration 🧪 Testing Guide: See TESTING.md - Complete testing instructions 🔒 Privacy Policy: See PRIVACY_POLICY.md - Privacy guarantees
ZüriBudget embodies the Swiss International Typographic Style:
- Grid System: Mathematical, rigid grid layouts with precise alignment
- Typography: San Francisco font treated like Helvetica - high contrast, large headers, distinct weight differences
- Minimalism: Generous whitespace, no illustrations, functional design
- Color Palette: ZKB brand identity with functional color usage
- Components: Sharp corners (4-8px radius), flat design, no drop shadows
Based on ZKB's brand identity:
| Color | Hex | Usage |
|---|---|---|
| ZKB Blue | #0066B2 |
Primary brand color, headers, primary actions |
| Zürich Blue | #268BCC |
Secondary/highlight, interactive elements |
| Signal Red | #FF3B30 |
Expenses/debits, critical actions |
| Emerald Green | #34C759 |
Income/credits, success states |
| Canvas White | #FFFFFF |
Light mode background |
| Deep Slate | #1C1C1E |
Dark mode background |
- Language: Swift 6
- UI Framework: SwiftUI
- Data Persistence: SwiftData (ModelContainer, @Model)
- PDF Parsing: PDFKit (Native framework)
- Architecture: MVVM (Model-View-ViewModel)
ZuriBudget/
├── ZuriBudget/
│ ├── ZuriBudgetApp.swift # App entry with security & auth
│ ├── Models/
│ │ ├── Transaction.swift # SwiftData model for transactions
│ │ ├── TransactionType.swift # Enum: debit/credit
│ │ └── Category.swift # Enum: auto-categorization logic
│ ├── Services/
│ │ ├── PDFParserService.swift # Secure ZKB PDF parsing
│ │ ├── BiometricAuthService.swift # Face ID/Touch ID authentication
│ │ ├── SecureFileManager.swift # Secure file handling & auto-delete
│ │ └── DataProtectionManager.swift # Encryption & data protection
│ ├── Views/
│ │ ├── HomeView.swift # Main dashboard
│ │ ├── FinancialSummaryView.swift # Income/Expense cards
│ │ ├── TransactionListView.swift # Full transaction list
│ │ ├── TransactionRowView.swift # Transaction row component
│ │ ├── DryRunView.swift # Import preview
│ │ └── PDFImportView.swift # PDF upload UI
│ ├── ViewModels/
│ │ └── HomeViewModel.swift # Dashboard business logic
│ └── Design/
│ └── ZKBColors.swift # Swiss design system & colors
├── PRIVACY_POLICY.md # Complete privacy documentation
ZüriBudget implements bank-level security for your financial data:
-
Biometric Authentication
- Face ID / Touch ID required on app launch (default: enabled)
- Automatic passcode fallback if biometrics unavailable
- Re-authentication required when returning from background
-
Data Encryption
- SwiftData database encrypted with FileProtectionType.complete
- Data accessible only when device is unlocked
- All app directories protected with iOS Data Protection API
-
Secure File Handling
- PDF files automatically deleted after parsing
- Secure overwrite with random data before deletion
- 10 MB file size limit (prevents DoS attacks)
- Temporary files stored in encrypted location
-
Memory Protection
- Sensitive data cleared when app backgrounds
- URL cache purged on suspension
- Pasteboard cleared to prevent data leakage
-
Validation & Limits
- PDF page count limited to 100 pages
- Content size validation (max 1 MB text)
- ZKB statement format verification
- File type restrictions (PDF only)
- 100% Local: All data stored exclusively on-device
- No Network: App works completely offline
- No Cloud Sync: No iCloud or remote servers
- No Tracking: Zero analytics or telemetry
- No Third Parties: No external SDKs or services
See PRIVACY_POLICY.md for complete privacy documentation.
Transaction Model (Transaction.swift):
- Unique ID (UUID)
- Transaction date
- Details (raw transaction text)
- Amount (Decimal for financial precision)
- Type (debit/credit)
- Auto-categorized category
- User notes (optional)
- Import timestamp
Category System (Category.swift):
- 13 predefined categories (Groceries, Transport, Rent, etc.)
- Automatic categorization based on Swiss/German keywords
- Recognizes common Swiss brands: Coop, Migros, SBB, ZVV, Swisscom, etc.
Swiss-Specific Formatting Support:
- Date Patterns:
dd.mm.yyyyordd.mm.yy - Amount Patterns:
CHF 1'200.50(apostrophe thousand separator)1'234.56or123.45- Handles both period and comma as decimal separators
- Noise Filtering: Automatically filters headers, footers, page numbers, IBAN, balance lines
Features:
parseZKBStatement(url:): Main parsing functionvalidateZKBStatement(url:): Pre-validation before parsing- Returns
ParseResultwith transactions, raw lines, and errors - Dry-run capability for user verification before saving
Typography (ZKBColors.swift):
- Swiss grid system (8pt base unit)
- Typography modifiers:
.swissTitle(),.swissHeadline(),.swissBody(),.swissCaption() - Tight kerning (-0.5 to -0.3) for Swiss style
View Modifiers:
.swissGridPadding(): Consistent spacing.swissCornerRadius(): Minimal 6px radius.swissCard(): Card-style background
Data Models:
- SwiftData Transaction model
- TransactionType enum
- Category enum with auto-categorization (13 categories, 50+ keywords)
PDF Parsing:
- PDFParserService with Swiss regex patterns
- Secure file handling with auto-deletion
- File size and content validation
Security & Privacy:
- BiometricAuthService (Face ID / Touch ID)
- SecureFileManager (auto-delete PDFs)
- DataProtectionManager (encryption & data protection)
- App lifecycle security handlers
- Memory protection on background
- Privacy Policy documentation
Design System:
- ZKB color palette and Swiss design system
- Authentication lock screen
- Security status dashboard
Dashboard:
- HomeView with Swiss grid layout
- Balance header with gradient background
- FinancialSummaryView (2-column income/expense cards)
- Recent transactions list (last 5)
- Floating action button for quick import
Transaction Management:
- TransactionListView with search and filters
- Category filter (13 categories)
- Transaction type filter (debit/credit)
- TransactionRowView component
- Context menu for deletion
- Empty states
PDF Import Flow:
- PDFImportView with FileImporter
- DryRunView for preview before saving
- Loading overlay during parsing
- Error handling with alerts
- Automatic PDF deletion after import
ViewModel:
- HomeViewModel with business logic
- Statistics calculation (balance, income, expenses)
- PDF import handling
- Swiss currency formatting
Analytics Dashboard:
- ChartsView with comprehensive analytics
- ChartsViewModel for data processing
- CategoryChartView with pie/donut chart
- TrendChartView with income vs expenses line chart
- WeeklyBreakdownView with bar chart
- Navigation from HomeView
Chart Features:
- Swiss minimalist styling (thin lines, no grid noise)
- Category spending distribution
- Monthly income vs expenses comparison
- Last 4 weeks spending breakdown
- Statistics cards (average, highest, lowest)
- Insights section (daily average, top category)
- Empty states for no data
Design:
- Consistent with Swiss International Style
- ZKB color palette
- Minimal chart elements
- Clear data visualization
- User settings
- Category customization
- Data export (CSV/JSON)
- Budget limits and alerts
The parser handles these ZKB statement formats:
15.01.2026 COOP Zürich, Kaufvertrag CHF 45.80
14.01.2026 SBB Billett Zürich HB CHF 12.40
13.01.2026 Lohnzahlung Januar 2026 -7'500.00
12.01.2026 Migros Basel, Einkauf -67.35
10.01.2026 Swisscom AG Rechnung CHF 89.00
Sample keywords per category:
- Groceries: Coop, Migros, Denner, Aldi, Lidl, Spar, Volg
- Transport: SBB, ZVV, VBZ, Mobility, Uber, Publibike
- Utilities: EWZ, Swisscom, Salt, Sunrise, Elektrizität
- Healthcare: Krankenkasse, CSS, Helsana, Apotheke, Arzt
- Dining: Restaurant, Café, Starbucks, McDonald's
- Rent: Miete, Wohnung, Immobilien
[View full keyword list in Category.swift]
- Open ZüriBudget app
- Tap "+" button to upload ZKB monthly statement PDF
- Review parsed transactions in dry-run view
- Confirm to save to SwiftData
- View dashboard with income/expense summary
- Browse categorized transactions
- Target iOS Version: iOS 17.0+ (required for SwiftData)
- Xcode Version: Xcode 15.0+
- Swift Version: Swift 6
- No External Dependencies: Uses only native iOS frameworks
zkb/
├── README.md # This file - Project overview
├── QUICKSTART.md # 5-minute setup guide
├── SETUP.md # Comprehensive Xcode setup (400+ lines)
├── TESTING.md # Complete testing guide (500+ lines)
├── PRIVACY_POLICY.md # Privacy documentation (300+ lines)
├── .gitignore # Xcode and development files
├── generate_sample_zkb_statement.py # PDF generator for testing
│
└── ZuriBudget/
├── Info.plist # App configuration
├── ZuriBudget.entitlements # Security entitlements
│
└── ZuriBudget/
├── ZuriBudgetApp.swift # App entry point
│
├── Models/ # SwiftData models
│ ├── Transaction.swift # Main transaction model
│ ├── TransactionType.swift # Debit/Credit enum
│ └── Category.swift # Auto-categorization (50+ keywords)
│
├── Services/ # Business logic & security
│ ├── PDFParserService.swift # Secure PDF parsing
│ ├── BiometricAuthService.swift # Face ID/Touch ID
│ ├── SecureFileManager.swift # File handling & auto-delete
│ └── DataProtectionManager.swift # Encryption & protection
│
├── Views/ # SwiftUI views
│ ├── HomeView.swift # Main dashboard
│ ├── FinancialSummaryView.swift # Income/Expense cards
│ ├── TransactionListView.swift # Full transaction list
│ ├── TransactionRowView.swift # Transaction row component
│ ├── DryRunView.swift # Import preview
│ └── PDFImportView.swift # PDF upload UI
│
├── ViewModels/ # Business logic
│ └── HomeViewModel.swift # Dashboard logic
│
└── Design/ # Swiss design system
└── ZKBColors.swift # Colors & typography
- Total Swift Files: 16 files
- Total Lines of Code: ~3,500 lines
- Documentation: ~1,500 lines
- Test Coverage: 100% feature complete
./generate_sample_zkb_statement.pyCreates realistic ZKB statement with:
- 32 sample transactions
- Swiss formatting (dd.mm.yyyy, CHF 1'234.56)
- Multiple categories (groceries, transport, utilities, etc.)
- Proper ZKB header and footer
- Quick Setup: Start with QUICKSTART.md
- Detailed Setup: See SETUP.md
- Testing: Follow TESTING.md
- Privacy Questions: Read PRIVACY_POLICY.md
- Issues: Check troubleshooting sections in guides
- Contributions: Open an issue or pull request
This is a demonstration project for ZKB users. Not affiliated with Zürcher Kantonalbank.
Built with Swiss precision. 🇨🇭