Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
9e87de5ce9
commit
a164669cf2
20
README.md
20
README.md
@ -71,12 +71,15 @@ The iPhone app syncs card data to the paired Apple Watch via App Groups. When yo
|
|||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
- SwiftUI views are presentation only
|
- **Clean Architecture**: Clear separation between Views, State, Services, and Models
|
||||||
- Shared app state uses `@Observable` classes on `@MainActor`
|
- **Views are dumb**: Presentation only, no business logic
|
||||||
- SwiftData for persistence with CloudKit sync
|
- **State is smart**: `@Observable` classes with all business logic
|
||||||
- Protocol-oriented design for card data, sharing, and contact tracking
|
- **Protocol-oriented**: Interfaces for services and stores
|
||||||
- String Catalogs (`.xcstrings`) for localization (en, es-MX, fr-CA)
|
- **SwiftData + CloudKit**: Persistent storage with iCloud sync
|
||||||
- **Bedrock package** for shared design constants and utilities
|
- **One type per file**: Lean, maintainable files under 300 lines
|
||||||
|
- **Reusable components**: Shared UI in `Views/Components/`
|
||||||
|
- **Bedrock package**: Shared design system and utilities
|
||||||
|
- **String Catalogs**: Localization for en, es-MX, fr-CA
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
@ -101,7 +104,10 @@ BusinessCard/
|
|||||||
├── Resources/ # String Catalogs (.xcstrings)
|
├── Resources/ # String Catalogs (.xcstrings)
|
||||||
├── Services/ # Share link service, watch sync
|
├── Services/ # Share link service, watch sync
|
||||||
├── State/ # Observable stores (CardStore, ContactsStore)
|
├── State/ # Observable stores (CardStore, ContactsStore)
|
||||||
└── Views/ # SwiftUI screens and components
|
└── Views/
|
||||||
|
├── Components/ # Reusable UI components (AvatarBadgeView, etc.)
|
||||||
|
├── Sheets/ # Modal sheets (RecordContactSheet, etc.)
|
||||||
|
└── [Feature].swift # Feature screens
|
||||||
|
|
||||||
BusinessCardWatch/ # watchOS app target
|
BusinessCardWatch/ # watchOS app target
|
||||||
BusinessCardTests/ # Unit tests
|
BusinessCardTests/ # Unit tests
|
||||||
|
|||||||
@ -11,6 +11,8 @@ BusinessCard is a SwiftUI app for building and sharing digital business cards wi
|
|||||||
- iOS 26+, watchOS 12+, Swift 6.2.
|
- iOS 26+, watchOS 12+, Swift 6.2.
|
||||||
- SwiftUI with `@Observable` classes and `@MainActor`.
|
- SwiftUI with `@Observable` classes and `@MainActor`.
|
||||||
- Protocol‑oriented architecture is prioritized.
|
- Protocol‑oriented architecture is prioritized.
|
||||||
|
- Clean Architecture with separation of concerns.
|
||||||
|
- One public type per file, keep files under 300 lines.
|
||||||
- No UIKit unless explicitly requested.
|
- No UIKit unless explicitly requested.
|
||||||
- String Catalogs only (`.xcstrings`).
|
- String Catalogs only (`.xcstrings`).
|
||||||
- No magic numbers in views; use Bedrock's `Design` constants.
|
- No magic numbers in views; use Bedrock's `Design` constants.
|
||||||
@ -45,68 +47,109 @@ App-specific extensions are in `Design/DesignConstants.swift`:
|
|||||||
|
|
||||||
### Models
|
### Models
|
||||||
|
|
||||||
- `BusinessCard/Models/BusinessCard.swift` — SwiftData model with:
|
- `Models/BusinessCard.swift` — SwiftData model with:
|
||||||
- Basic fields: name, role, company, email, phone, website, location
|
- Basic fields: name, role, company, email, phone, website, location
|
||||||
- Rich fields: pronouns, bio, social links (LinkedIn, Twitter, Instagram, etc.)
|
- Rich fields: pronouns, bio, social links (LinkedIn, Twitter, Instagram, etc.)
|
||||||
- Custom links: 2 slots for custom URLs
|
- Custom links: 2 slots for custom URLs
|
||||||
- Photo: `photoData` stored with `@Attribute(.externalStorage)`
|
- Photo: `photoData` stored with `@Attribute(.externalStorage)`
|
||||||
- Computed: `theme`, `layoutStyle`, `vCardPayload`, `hasSocialLinks`
|
- Computed: `theme`, `layoutStyle`, `vCardPayload`, `hasSocialLinks`
|
||||||
|
|
||||||
- `BusinessCard/Models/Contact.swift` — SwiftData model with:
|
- `Models/Contact.swift` — SwiftData model with:
|
||||||
- Basic fields: name, role, company
|
- Basic fields: name, role, company
|
||||||
- Annotations: notes, tags (comma-separated), followUpDate, metAt
|
- Annotations: notes, tags (comma-separated), followUpDate, whereYouMet
|
||||||
- Received cards: isReceivedCard, receivedCardData (vCard)
|
- Received cards: isReceivedCard, email, phone
|
||||||
- Photo: `photoData`
|
- Photo: `photoData`
|
||||||
- Computed: `tagList`, `hasFollowUp`, `isFollowUpOverdue`
|
- Computed: `tagList`, `hasFollowUp`, `isFollowUpOverdue`
|
||||||
- Static: `fromVCard(_:)` parser
|
- Static: `fromVCard(_:)` parser
|
||||||
|
|
||||||
- `BusinessCard/Models/CardTheme.swift` — card theme palette
|
- `Models/CardTheme.swift` — card theme palette
|
||||||
- `BusinessCard/Models/CardLayoutStyle.swift` — stacked/split/photo
|
- `Models/CardLayoutStyle.swift` — stacked/split/photo
|
||||||
|
- `Models/AppTab.swift` — tab bar enum
|
||||||
|
|
||||||
### Protocols (POP)
|
### Protocols (POP)
|
||||||
|
|
||||||
- `BusinessCard/Protocols/BusinessCardProviding.swift`
|
- `Protocols/BusinessCardProviding.swift` — card selection interface
|
||||||
- `BusinessCard/Protocols/ContactTracking.swift`
|
- `Protocols/ContactTracking.swift` — contact management interface
|
||||||
- `BusinessCard/Protocols/ShareLinkProviding.swift`
|
- `Protocols/ShareLinkProviding.swift` — share URL generation interface
|
||||||
|
|
||||||
### State
|
### State
|
||||||
|
|
||||||
- `BusinessCard/State/AppState.swift` — central state container
|
- `State/AppState.swift` — central state container
|
||||||
- `BusinessCard/State/CardStore.swift` — card CRUD, selection, watch sync
|
- `State/CardStore.swift` — card CRUD, selection, watch sync
|
||||||
- `BusinessCard/State/ContactsStore.swift` — contacts, search, received cards
|
- `State/ContactsStore.swift` — contacts, search, received cards
|
||||||
|
|
||||||
### Services
|
### Services
|
||||||
|
|
||||||
- `BusinessCard/Services/ShareLinkService.swift` — share URL helpers
|
- `Services/ShareLinkService.swift` — share URL helpers
|
||||||
- `BusinessCard/Services/WatchSyncService.swift` — App Group sync to watch
|
- `Services/WatchSyncService.swift` — App Group sync to watch
|
||||||
|
|
||||||
### Views
|
### Views
|
||||||
|
|
||||||
- `RootTabView.swift` — tabbed shell
|
Main screens:
|
||||||
- `CardsHomeView.swift` — hero + card carousel
|
- `Views/RootTabView.swift` — tabbed shell
|
||||||
- `CardEditorView.swift` — create/edit cards with PhotosPicker
|
- `Views/CardsHomeView.swift` — hero + card carousel
|
||||||
- `BusinessCardView.swift` — card display with photo and social icons
|
- `Views/ShareCardView.swift` — QR + share actions + track share
|
||||||
- `ShareCardView.swift` — QR + share actions + track share
|
- `Views/CustomizeCardView.swift` — theme/layout controls
|
||||||
- `CustomizeCardView.swift` — theme/layout controls
|
- `Views/ContactsView.swift` — contact list with sections
|
||||||
- `ContactsView.swift` — tracking list with sections
|
- `Views/WidgetsView.swift` — widget preview mockups
|
||||||
- `ContactDetailView.swift` — full contact view with annotations
|
|
||||||
- `QRScannerView.swift` — camera-based QR scanner
|
Feature views:
|
||||||
- `QRCodeView.swift` — wrapper for Bedrock's QRCodeImageView
|
- `Views/BusinessCardView.swift` — card display with layouts
|
||||||
- `WidgetsView.swift` — preview mockups
|
- `Views/CardEditorView.swift` — create/edit cards with PhotosPicker
|
||||||
|
- `Views/ContactDetailView.swift` — full contact view with annotations
|
||||||
|
- `Views/QRScannerView.swift` — camera-based QR scanner
|
||||||
|
- `Views/QRCodeView.swift` — QR code image generator
|
||||||
|
|
||||||
|
Reusable components (in `Views/Components/`):
|
||||||
|
- `AvatarBadgeView.swift` — circular avatar with photo or icon
|
||||||
|
- `IconRowView.swift` — icon + text row for details
|
||||||
|
- `LabelBadgeView.swift` — small badge labels
|
||||||
|
- `ActionRowView.swift` — generic action row with chevron
|
||||||
|
|
||||||
|
Sheets (in `Views/Sheets/`):
|
||||||
|
- `RecordContactSheet.swift` — track share recipient
|
||||||
|
|
||||||
|
Small utilities:
|
||||||
|
- `Views/EmptyStateView.swift` — empty state placeholder
|
||||||
|
- `Views/PrimaryActionButton.swift` — styled action button
|
||||||
|
- `Views/HeroBannerView.swift` — home page banner
|
||||||
|
- `Views/CardCarouselView.swift` — card scroll carousel
|
||||||
|
- `Views/WidgetsCalloutView.swift` — widget promotion callout
|
||||||
|
|
||||||
### Design + Localization
|
### Design + Localization
|
||||||
|
|
||||||
- `BusinessCard/Design/DesignConstants.swift` — extends Bedrock
|
- `Design/DesignConstants.swift` — extends Bedrock
|
||||||
- `BusinessCard/Resources/Localizable.xcstrings`
|
- `Resources/Localizable.xcstrings` — string catalog
|
||||||
- `BusinessCard/Localization/String+Localization.swift`
|
- `Localization/String+Localization.swift` — string helpers
|
||||||
|
|
||||||
### watchOS
|
### watchOS
|
||||||
|
|
||||||
- `BusinessCardWatch/BusinessCardWatchApp.swift`
|
- `BusinessCardWatch/BusinessCardWatchApp.swift`
|
||||||
- `BusinessCardWatch/Views/WatchContentView.swift`
|
- `BusinessCardWatch/Views/WatchContentView.swift`
|
||||||
- `BusinessCardWatch/State/WatchCardStore.swift`
|
- `BusinessCardWatch/State/WatchCardStore.swift`
|
||||||
|
- `BusinessCardWatch/Models/WatchCard.swift`
|
||||||
- `BusinessCardWatch/Resources/Localizable.xcstrings`
|
- `BusinessCardWatch/Resources/Localizable.xcstrings`
|
||||||
|
|
||||||
|
## File Guidelines
|
||||||
|
|
||||||
|
### Size Limits
|
||||||
|
- Main views: aim for under 300 lines
|
||||||
|
- Extract reusable sub-views to `Components/`
|
||||||
|
- Extract sheets/modals to `Sheets/`
|
||||||
|
- Private structs in same file OK if under 50 lines
|
||||||
|
|
||||||
|
### Current File Sizes
|
||||||
|
| File | Lines | Status |
|
||||||
|
|------|-------|--------|
|
||||||
|
| CardEditorView | ~420 | Complex form, acceptable |
|
||||||
|
| QRScannerView | ~310 | Camera + parsing, acceptable |
|
||||||
|
| BusinessCardView | ~245 | Multiple layouts, acceptable |
|
||||||
|
| ShareCardView | ~235 | Good |
|
||||||
|
| ContactDetailView | ~235 | Good |
|
||||||
|
| ContactsView | ~220 | Good |
|
||||||
|
| CustomizeCardView | ~170 | Good |
|
||||||
|
| All others | <110 | Good |
|
||||||
|
|
||||||
## Localization
|
## Localization
|
||||||
|
|
||||||
- All user-facing strings are in `.xcstrings`.
|
- All user-facing strings are in `.xcstrings`.
|
||||||
@ -140,3 +183,6 @@ App-specific extensions are in `Design/DesignConstants.swift`:
|
|||||||
5. Prefer protocols for new capabilities.
|
5. Prefer protocols for new capabilities.
|
||||||
6. Add unit tests for new model logic.
|
6. Add unit tests for new model logic.
|
||||||
7. Update `ROADMAP.md` when adding features.
|
7. Update `ROADMAP.md` when adding features.
|
||||||
|
8. **Keep files under 300 lines** — extract components when needed.
|
||||||
|
9. **No duplicate code** — check for existing components first.
|
||||||
|
10. **One public type per file** — private helpers OK if small.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user