Build the Routee MVP: record hiking routes, attach photos to route points, and create/share hiking recap images. Prefer simple, shippable UIKit code over abstraction-heavy architecture.
- Swift 6
- UIKit
- iOS 17+
- SnapKit
- NMapsMap
- Alamofire
- Swift Concurrency
- Combine only for continuous event streams or existing bindings
- Use programmatic UIKit only.
- Use SnapKit for all Auto Layout code.
- Do not use deprecated APIs.
- Prefer
finalclasses. - Default access level is
private. - Keep methods small and responsibility-focused.
- Use
// MARK: -sections with one blank line above and below. - Follow existing naming, folder structure, and conventions before introducing new patterns.
- Do not add dependencies unless clearly necessary.
Use a lightweight layered structure:
ViewController/ViewModel -> Repository -> NetworkService -> Endpoint -> Alamofire
Responsibilities:
- ViewController: rendering, user input, navigation, binding.
- View: reusable UI, layout, visual state only.
- ViewModel: screen state and presentation logic when needed.
- Repository: domain-level data access.
- NetworkService: request execution and decoding.
- Endpoint: path, method, headers, parameters.
- DTO: API payload only.
Rules:
- ViewController/ViewModel must not call
AF,Endpoint,NetworkService, orTokenManagerdirectly. - Avoid Clean Architecture layers, protocols, factories, or use cases unless they solve a current problem.
- Do not create a ViewModel for static or trivial screens.
- Use
async/awaitas the default API style. - Decode with
DecodableandserializingDecodable. - Use the shared
BaseResponse<T>format. - Send dates as ISO 8601 UTC strings.
- Send
TimeZone.current.identifieronly when the API requires timezone context. - Centralize authentication and token refresh in an Alamofire interceptor.
- Never log access tokens, refresh tokens, authorization codes, or personal location data.
- Use typed errors.
- Convert transport, HTTP, decoding, server, and authentication failures into project errors.
- UI decides how errors are displayed.
- Do not silently ignore errors with empty
catchblocks.
- UI state mutations must run on
@MainActor. - Prefer structured concurrency:
async let, task groups, and child tasks. - Avoid unstructured
Taskunless bridging from synchronous UIKit callbacks. - Support cancellation for long-running network, image, and location operations.
- Do not use
DispatchQueue.main.asyncwhen actor isolation solves the same problem.
- Separate layout from behavior.
- A custom
UIViewowns subviews, layout, styling, and visual state updates. - A
UIViewControllerowns lifecycle, navigation, user actions, permissions, and orchestration. - Use delegation or closures for reusable view events.
- Capture
selfweakly only where a retained closure can create a cycle. - Reuse existing UI components and design tokens before creating new ones.
- Use WGS84 coordinates: latitude and longitude.
- Store route points as raw coordinates, not rendered images.
- Preserve server-provided
trackPointIndexordering. - A photo capture must save the current route coordinate.
- Filter invalid points using timestamp, horizontal accuracy, distance, and speed.
- Avoid saving duplicate or noisy coordinates.
- Render the live route locally with a map path overlay.
- Fit the camera to all route coordinates when recording ends.
- Do not upload every location point individually unless real-time sharing is required.
- Prefer local buffering and batch upload after completion or at safe checkpoints.
- Never block the main thread with route processing or image rendering.
- Treat map background, route overlay, photos, and text as separate layers.
- Generate recap output from stored coordinates and metadata.
- Do not use a saved route PNG as the source of truth.
- Keep rendering deterministic so the same data can reproduce the same recap.
- Store server access and refresh tokens in Keychain.
- Do not persist Apple identity tokens after server authentication.
- Request the minimum location and photo permissions required.
- Explain permission purpose before system prompts when UX requires it.
- Avoid exposing precise user routes in logs, analytics, screenshots, or fixtures.
Prioritize tests for:
- coordinate filtering
- route ordering
- distance/time calculations
- DTO decoding
- repository error mapping
- recap coordinate-to-point conversion
Do not add low-value tests for simple UIKit layout code.
Before editing:
- Read nearby files and follow existing patterns.
- Identify the smallest valid change.
- Reuse current abstractions.
After editing:
- Check compile errors and actor isolation.
- Check optionals, bounds, retain cycles, and cancellation.
- Remove dead code, debug prints, unused imports, and duplicated logic.
- Summarize changed files, behavior, and remaining risks briefly.
- Answer in Korean.
- Be concise and implementation-focused.
- Show only the code needed for the requested change.
- Do not rewrite unrelated files.
- Do not invent missing project types or APIs; inspect the codebase first.
- When multiple solutions exist, recommend one and state the trade-off briefly.
- Point out architecture, concurrency, memory, security, or MVP-scope problems directly.