Skip to content

Commit 91b80eb

Browse files
committed
๐Ÿ“š ๋ฌธ์„œ ์—…๋ฐ์ดํŠธ ๋ฐ ์ •๋ฆฌ ์ž‘์—…
- ํ”„๋กœ์ ํŠธ ๋ฌธ์„œ(CLAUDE.md) ์—…๋ฐ์ดํŠธ ๋ฐ ๊ฐœ์„  - ๊ฐœ๋ฐœ ์ž‘์—… ๋ชฉ๋ก(todo.md) ์ถ”๊ฐ€ - ์ปค์„œ ๊ทœ์น™ ํŒŒ์ผ ์ •๋ฆฌ ๋ฐ ์ œ๊ฑฐ - ์•ฑ ์—”ํƒ€์ดํ‹€๋จผํŠธ ์„ค์ • ๊ฐœ์„ 
1 parent 01eaf8e commit 91b80eb

File tree

4 files changed

+165
-243
lines changed

4 files changed

+165
-243
lines changed

โ€ŽSNUTT/CLAUDE.mdโ€Ž

Lines changed: 148 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -2,145 +2,184 @@
22

33
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
44

5-
## Project Overview
6-
7-
SNUTT is an iOS app for Seoul National University's timetable management system built with Swift using a modular architecture. The project uses Tuist for project management and generation.
8-
9-
- **Language**: Swift 6.0
10-
- **Deployment Target**: iOS 17.0+
11-
- **Architecture Pattern**: Modular architecture with feature modules and interfaces
12-
135
## Development Commands
146

15-
### Environment Setup
7+
This project uses **Tuist** for project generation and **Just** for task automation.
168

9+
### Essential Setup Commands
1710
```bash
18-
# Install prerequisites
11+
# Install prerequisites (if not already installed)
1912
curl https://mise.run | sh
20-
brew install just
13+
brew install just mint pre-commit swift-format
2114

22-
# Install dependencies
15+
# Install dependencies (mise will auto-select versions from .mise.toml)
2316
mise install
2417
tuist install
2518

2619
# Setup development environment
27-
just dev # Generate dev OpenAPI + project
28-
just prod # Generate prod OpenAPI + project
20+
just dev # Generate dev OpenAPI + project
21+
just prod # Generate prod OpenAPI + project
2922
```
3023

31-
### Project Generation
32-
24+
### Common Development Tasks
3325
```bash
34-
# Clean and regenerate
35-
just clean-build # Clean build
36-
just clean-generate # Clean generate
37-
38-
# OpenAPI
39-
just openapi-dev # Generate dev OpenAPI
40-
just openapi-prod # Generate prod OpenAPI
41-
42-
# Tuist commands
26+
# Project Generation & Building
27+
tuist generate # Generate Xcode project
28+
tuist clean # Clean Tuist cache
4329
tuist install # Install dependencies
44-
tuist generate # Generate project
45-
tuist clean # Clean cache
46-
tuist test # Run tests
47-
tuist build # Build the project (use this to verify code changes)
48-
```
49-
50-
## Project Architecture
51-
52-
### Module Structure
53-
54-
The codebase follows a modular architecture pattern with three main module categories:
55-
56-
1. **Feature Modules**: Self-contained features with their own UI, business logic, and data access layers
57-
- Examples: Timetable, Auth, Settings, Vacancy, Notifications
30+
tuist test # Run all tests
31+
tuist build # Build the project
5832

59-
2. **Feature Interface Modules**: Interfaces/contracts that define the public API of feature modules
60-
- Examples: TimetableInterface, AuthInterface, APIClientInterface
33+
# Clean Operations
34+
just clean-build # Full clean build (clears DerivedData, installs deps, builds)
35+
just clean-generate # Clean generate (clears DerivedData, installs deps, generates)
36+
just clean-derived-data # Clear Xcode DerivedData only
6137

62-
3. **Utility and Shared Modules**: Reusable components and utilities
63-
- **Shared**: Common UI components and app metadata
64-
- **Utility**: Foundation extensions, SwiftUI utilities, etc.
38+
# Code Quality
39+
just format # Format Swift code using swift-format
40+
just check # Run all checks (dependencies, imports, formatting)
6541

66-
### Module Dependencies
42+
# OpenAPI Generation
43+
just openapi-dev # Generate dev environment OpenAPI
44+
just openapi-prod # Generate prod environment OpenAPI
6745

68-
Features can only depend on interfaces of other features, not their implementations. This enforces loose coupling between modules. The dependency rules are:
69-
70-
- **Feature โ†’ FeatureInterface**: A feature can only depend on interfaces of other features
71-
- **Feature โ†’ Utility/Shared**: Features can depend on utilities and shared components
72-
- **FeatureInterface โ†’ Utility**: Interfaces can depend on utilities
73-
- **Utility โ†’ Utility**: Utilities can depend on other utilities
74-
75-
### Key Modules
76-
77-
- **Timetable**: Core timetable functionality
78-
- **APIClient**: OpenAPI-generated API client for backend communication
79-
- **Auth**: Authentication and user management
80-
- **Themes**: Theme management for the app
81-
- **Settings**: App settings and preferences
82-
- **Vacancy**: Feature related to course vacancies
46+
# Testing
47+
tuist test # Run all module tests
48+
# Test individual modules using Xcode schemes (e.g., "ModuleTests" scheme)
49+
```
8350

84-
### External Dependencies
51+
### Build Configurations
52+
- **Dev**: Development configuration with debug symbols
53+
- **Prod**: Production/release configuration
54+
- The project uses scheme-based configuration switching
8555

86-
The project uses several third-party dependencies:
87-
- Dependencies (Point-Free's dependency injection)
88-
- OpenAPI Runtime and URLSession
89-
- SwiftUI Introspect
90-
- Firebase Core and Messaging
91-
- KakaoMapsSDK
56+
## Architecture Overview
9257

93-
## Dependency Injection Pattern
58+
SNUTT follows a **strict modular architecture** with Clean Architecture principles:
9459

95-
### Interface Module Pattern
60+
### Module Categories
61+
1. **Feature Modules** (`Modules/Feature/`): Self-contained features with implementations
62+
2. **Feature Interface Modules** (`Modules/Feature/*Interface/`): Public contracts for features
63+
3. **Shared Modules** (`Modules/Shared/`): Reusable UI components and app-wide utilities
64+
4. **Utility Modules** (`Modules/Utility/`): Low-level utilities and helpers
9665

97-
Interface modules should follow this pattern to maintain clean separation between interface definitions and implementations:
66+
### Critical Dependency Rules
67+
- **Feature โ†’ FeatureInterface**: Features can ONLY depend on interfaces of other features
68+
- **FeatureInterface โ†’ Feature**: **STRICTLY FORBIDDEN** - Interfaces cannot depend on implementations
69+
- **Feature/FeatureInterface โ†’ Utility/Shared**: Can depend on utilities and shared modules
70+
- No circular dependencies between modules at the same level
9871

99-
1. **Interface Module (e.g., VacancyInterface)**:
100-
```swift
101-
@Spyable
102-
public protocol SomeRepository: Sendable {
103-
func someMethod() async throws -> ReturnType
104-
}
105-
106-
public enum SomeRepositoryKey: TestDependencyKey {
107-
public static let testValue: any SomeRepository = {
108-
let spy = SomeRepositorySpy()
109-
spy.someMethodReturnValue = defaultValue
110-
return spy
111-
}()
112-
}
113-
114-
extension DependencyValues {
115-
public var someRepository: any SomeRepository {
116-
get { self[SomeRepositoryKey.self] }
117-
set { self[SomeRepositoryKey.self] = newValue }
118-
}
119-
}
120-
```
72+
### Clean Architecture Layers (within each feature)
73+
```
74+
UI Layer (SwiftUI Views)
75+
โ†“
76+
Presentation Layer (ViewModels with @Observable)
77+
โ†“
78+
Business Logic Layer (Use Cases, Domain Models, Repository Protocols)
79+
โ†“
80+
Infrastructure Layer (Repository Implementations)
81+
```
12182

122-
2. **Live Implementation (in LiveDependencies.swift)**:
123-
```swift
124-
extension SomeRepositoryKey: @retroactive DependencyKey {
125-
public static let liveValue: any SomeRepository = SomeAPIRepository()
126-
}
127-
```
83+
**Layer Rules:**
84+
- UI can ONLY depend on ViewModels (Presentation layer)
85+
- UI CANNOT directly access repositories or use cases
86+
- ViewModels use dependency injection to access business logic
87+
- Business logic depends on repository interfaces, not implementations
88+
89+
### Dependency Injection Pattern
90+
91+
The project uses **swift-dependencies** with the following pattern:
92+
93+
**Interface Definition** (in FeatureInterface modules):
94+
```swift
95+
@Spyable
96+
public protocol SomeRepository: Sendable {
97+
func someMethod() async throws -> ReturnType
98+
}
99+
100+
public enum SomeRepositoryKey: TestDependencyKey {
101+
public static let testValue: any SomeRepository = SomeRepositorySpy()
102+
}
103+
104+
extension DependencyValues {
105+
public var someRepository: any SomeRepository {
106+
get { self[SomeRepositoryKey.self] }
107+
set { self[SomeRepositoryKey.self] = newValue }
108+
}
109+
}
110+
```
128111

129-
### Key Principles
112+
**Live Implementation** (in Feature module's `LiveDependencies.swift`):
113+
```swift
114+
extension SomeRepositoryKey: DependencyKey {
115+
public static let liveValue: any SomeRepository = SomeAPIRepository()
116+
}
117+
```
130118

131-
- **Interface modules** only define protocols and test dependencies using `TestDependencyKey`
132-
- **Live implementations** are injected via `@retroactive DependencyKey` in `LiveDependencies.swift`
133-
- This pattern ensures interface modules don't depend on concrete implementations
134-
- Follows the same pattern as other modules (TimetableRepository, AuthRepository, etc.)
119+
**Usage in ViewModels:**
120+
```swift
121+
@Observable
122+
@MainActor
123+
public class FeatureViewModel {
124+
@Dependency(\.someRepository) private var someRepository
125+
// Implementation
126+
}
127+
```
135128

136-
## Build Configurations
129+
### Key Features
130+
- **Timetable**: Core timetable functionality and UI components
131+
- **Auth**: Authentication with Kakao, Facebook, Google integrations
132+
- **Vacancy**: Classroom vacancy checking
133+
- **Themes**: UI theming system
134+
- **Notifications**: Push notification handling
135+
- **Settings**: App configuration and user preferences
136+
- **Reviews**: App store review integration
137+
- **Popup**: App-wide popup system
138+
139+
## Technology Stack
140+
141+
- **Language**: Swift 6.1+ with modern Swift Concurrency (`async/await`)
142+
- **UI Framework**: SwiftUI with Observation framework (`@Observable`, `@Bindable`)
143+
- **Minimum iOS Version**: 17.0+
144+
- **Xcode Version**: 16.0+
145+
- **Project Management**: Tuist for modular project generation
146+
- **Code Formatting**: swift-format with 120 character line length, 4-space indentation
147+
- **API Integration**: OpenAPI-generated client with separate dev/prod configurations
148+
- **Dependency Injection**: swift-dependencies package
149+
- **Maps**: Kakao Maps SDK
150+
- **Testing**: Built-in unit testing with Spyable for mock generation
151+
152+
## Code Style & Conventions
153+
154+
- **Formatting**: Automatic formatting via swift-format (configured in `.swift-format`)
155+
- **Pre-commit Hooks**: swift-format runs automatically on commit
156+
- **Sendable**: All repository protocols and implementations must be `Sendable`
157+
- **MainActor**: ViewModels should be annotated with `@MainActor`
158+
- **Async/Await**: Use Swift Concurrency for all asynchronous operations
159+
- **Observation**: Use `@Observable` macro for ViewModels instead of ObservableObject
160+
161+
## File Structure Template
162+
163+
Each feature should follow this structure:
164+
```
165+
Modules/Feature/FeatureName/
166+
โ”œโ”€ Sources/
167+
โ”‚ โ”œโ”€ UI/ # SwiftUI Views
168+
โ”‚ โ”œโ”€ Presentation/ # ViewModels
169+
โ”‚ โ”œโ”€ BusinessLogic/ # Use Cases, Domain Models
170+
โ”‚ โ”œโ”€ Infra/ # Repository Implementations
171+
โ”‚ โ””โ”€ Composition/ # Dependency Registration (LiveDependencies.swift)
172+
โ””โ”€ Tests/
173+
โ””โ”€ UnitTests/ # Tests for all layers
174+
```
137175

138-
The project has two main configurations:
139-
- **Dev**: Development environment
140-
- **Prod**: Production environment
176+
## OpenAPI Integration
141177

142-
Each configuration uses its own xcconfig file located in the XCConfigs directory.
178+
- API specs are automatically downloaded and generated
179+
- Separate configurations for dev and prod environments
180+
- Generated clients are located in `Modules/Feature/APIClientInterface/`
181+
- Use `just openapi-dev` or `just openapi-prod` to regenerate API clients
143182

144183
## Widget Extension
145184

146-
The project includes a widget extension for iOS home screen widgets that displays timetable information.
185+
The project includes a widget extension (`SNUTTWidget`) with its own target and dependencies, primarily using timetable functionality.

โ€ŽSNUTT/Supporting Files/SNUTT.entitlementsโ€Ž

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
<dict>
55
<key>aps-environment</key>
66
<string>development</string>
7+
<key>com.apple.developer.applesignin</key>
8+
<array>
9+
<string>Default</string>
10+
</array>
711
<key>com.apple.security.application-groups</key>
812
<array>
913
<string>group.com.wafflestudio.snutt</string>

0 commit comments

Comments
ย (0)