Swift 마이크로서비스 설계자
다른 방식으로 구축된 백엔드에서는 해당 구조와 규칙을 유지하고, 사용자가 변경을 요청하지 않는 한 이 스킬의 형태는 백엔드에 부족한 부분에만 적용하세요.
X는 대상 이름(LoansCore)과 유형 이름(BorrowBookUseCase, LoanService)에서 서비스를 나타내며, <Org>와 <org>는 조직을 나타냅니다. 예제는 작은 대출 도서관인 Bookshelf입니다:
| 패키지 | 보유 내용 |
|---|---|
bookshelf-identity | 계정, 비밀번호, 세션; 모든 액세스 토큰 발급; Valkey의 재설정 코드; 내부적으로 다른 서비스를 위한 멤버 |
bookshelf-catalog | 도서: 누구나 읽고, 관리자는 편집; Loans는 내부적으로 도서를 조회 |
bookshelf-loans | 회원의 대출, 테넌트 테이블; 워크플로가 대출을 연체로 표시하고 알림 전송 |
bookshelf-gateway | 공개 HTTP API, 서비스의 gRPC 계약으로 전달 |
bookshelf-core | BookshelfAuthentication, BookshelfPersistence, BookshelfTransport, BookshelfTesting |
bookshelf-protos | IdentityProtos, CatalogProtos, LoansProtos |
형태
클라이언트 ── HTTPS ──► 에지 (TLS 종료) ── HTTP ──► 게이트웨이 (Hummingbird, OpenAPI)
게이트웨이 ── gRPC, mTLS, 호출자의 JWT ──► 각 서비스의 XService
서비스, 워커 ── gRPC, mTLS ──► 다른 서비스의 XInternalService
서비스, 워커 ── mTLS ──► Temporal 서비스 ──► 자체 Postgres 데이터베이스, Valkey
모든 서비스와 게이트웨이는 <org>-core, <org>-protos 및 swift-microservices 라이브러리(스택)에 의존합니다.
서비스 패키지
<org>-x
├── XCore 도메인 모델, 오류, 저장소 프로토콜 및 명령, 포트, 사용 사례
├── XPostgres 데이터베이스 역할별 범위, 저장소, 명령문, 마이그레이션
├── XGRPC XService 및 XInternalService, Protobuf 변환, Core 포트용 gRPC 클라이언트
├── XTemporal 워크플로, 활동 컨테이너, Core 워크플로 포트용 Temporal 클라이언트
├── XValkey 단기 값 저장소
├── X<Provider> Core 포트 뒤의 타사 API (LoansResend)
└── X 실행 파일: 명령, 구성 기본값, 마이그레이션, 구성 루트
서비스에는 필요한 대상만 있으며, 각 대상은 해당 행에 나열된 것만 가져옵니다. 엄격한 규칙:
- XCore는 드라이버, 전송, 계약, 워크플로 엔진, 구성 또는 수명 주기 모듈을 가져오지 않습니다 (Core가 연결할 수 있는 것).
- 어댑터 대상은 절대 서로 가져오지 않습니다. 실행 파일은 Core의 프로토콜을 통해 하나를 다른 대상에 전달합니다.
- 생성된 계약 유형은 XGRPC, 게이트웨이의 HTTP 대상 및 실행 파일을 벗어나지 않습니다.
- 실행 파일만 구성을 읽고, 클라이언트를 빌드하며,
ServiceGroup을 실행합니다. - 어떤 서비스도 다른 서비스의 데이터베이스를 읽지 않습니다. 데이터는 계약을 통해서만 서비스 간에 이동합니다.
누가 무엇을 소유하는가
| 관심사 | 소유자 |
|---|---|
| 비즈니스 규칙, 권한 부여 결정, 오류의 의미 | XCore의 사용 사례; 어댑터는 변환 및 위임만 수행 |
| 서비스가 다른 서비스의 데이터에 대해 아는 것 | 해당 포트를 반환하는 XCore Ports/의 모델 |
| Protobuf ↔ 도메인, HTTP ↔ protobuf | XGRPC의 Protobuf/ 변환; 게이트웨이의 Schemas/ |
| 프로세스 간 메시지; 공개 API | <org>-protos; 게이트웨이의 openapi.yaml |
| 호출자가 누구인지 | 게이트웨이가 토큰을 확인하고 전달; 각 서비스가 다시 확인 |
| 내부 RPC를 호출할 수 있는 프로세스 | 리스너의 mTLS: 환경의 권한이 서명한 모든 프로세스 |
| 테넌트 격리 | 행 수준 보안; <Org>Persistence가 호출자를 각 트랜잭션에 바인딩하고, 각 대상의 사용 사례는 해당 데이터베이스 역할로 실행 |
| 내구성, 지연 또는 다중 서비스 작업 | XTemporal의 Temporal 워크플로 |
| 모든 서비스가 동일하게 필요로 하는 것 | <org>-core: ID, 테넌트 바인딩, 전송 리더 |
코드 스타일
코드는 구현하는 요구 사항처럼 읽혀야 하며, Apple의 WWDC 샘플 코드가 기준입니다(스타일). 사용 사례와 어댑터는 다음과 같이 오류를 매핑합니다:
do {
... // 요구 사항에 명시된 순서대로 작업
} catch let error as BorrowBookUseCaseError {
throw error
} catch CatalogClientError.unavailable {
logger.warning("대출 실패: 카탈로그를 사용할 수 없음")
throw .catalogUnavailable
} catch {
logger.error("대출 실패: 알 수 없는 오류", metadata: ["error": "\(String(reflecting: error))"])
throw .unknown
}
- 하나의
do는return을 통해 작업을 보유하고, 각catch는 자체 경로를 종료합니다.catch가 채울 변수가do앞에 선언되지 않습니다. - 빌드한 다음 호출: 호출이 받는 값은 명명된
let이며, 인수에 변환,try또는await가 절대 없습니다 (빌드한 다음 호출). - 사용 사례, 워크플로 또는 활동에 헬퍼 메서드가 없으며,
Result조작, 조종 플래그,try?,catch안의 중첩do, 또는 강제 언래핑이 없습니다. ExistentialAny,MemberImportVisibility,InternalImportsByDefault및NonisolatedNonsendingByDefault가 포함된 Swift 6 모드 (Swift 설정); 서비스 대상 간package접근.- 경계를 넘는 모든 것은
Sendable입니다.Task {}또는Task.detached가 없으며, 동시성이 허용하는 경우에만 확인되지 않은 동시성을 사용합니다.
주의 사항
ServiceGroup에서 누락된 구성 요소는 절대 실행되지 않습니다. 실행되지 않은GRPCClient또는PostgresClient는 절대 연결되지 않으므로 해당 호출은 기한까지 대기합니다.- 데이터베이스 소유자로 연결된 프로세스는 행 수준 보안을 우회하므로, 모든 프로세스는 해당 역할로 연결되고 소유자로는
serve --migrate-database만 실행합니다. - Temporal은
Codable을 런타임에만 확인합니다. 모든 워크플로 및 활동 페이로드와 그것이 보유한 각 유형은Codable, Sendable이어야 합니다 (워크플로). - 워크플로 코드는 재생됩니다. 워크플로에서
Date.now,UUID(), 무작위성,Task.sleep또는 I/O를 사용하면 워크플로가 손상됩니다 (결정론). - 소유 코드에서 일반 또는 범위 지정
import Foundation은 Linux에서 전체 Foundation을 연결합니다. 조건부FoundationEssentials가져오기를 사용하세요.
체크리스트
작업의 체크리스트를 응답에 복사하고 완료된 항목을 체크하세요. 각 .md 파일은 references/에 있습니다.
백엔드 계획
- [ ] 기능과 각각이 소유하는 데이터, 기능별 서비스 (system.md#splitting-a-system-into-services)
- [ ] 각 서비스 이름 지정, 그래프의 모든 모듈에 대해 대상 이름 확인
- [ ] 서비스별: 대상별 XService RPC, XInternalService RPC 및 호출 순환 없는 호출자, 테이블(테넌트 여부), 워크플로, 단기 상태
- [ ] 서비스별: 대상, 명령, 데이터베이스 역할
- [ ] <org>-core의 제품, <org>-protos의 계약, 계층별 게이트웨이 경로
- [ ] 빌드 순서: <org>-core 및 <org>-protos, 토큰 발급자, 호출자 이전의 각 서비스, 게이트웨이
- [ ] system.md의 계획 작성; 코드 작성 전에 엄격한 규칙에 대해 확인
서비스 추가
- [ ] <org>-protos: XProtos with XService, 프로세스가 호출하는 경우 XInternalService 포함
- [ ] packages.md#packageswift-template에서 패키지 <org>-x, 계획이 명명한 대상만 포함
- [ ] XCore: 모델, 오류, 저장소, 포트, RPC당 사용 사례 (use-cases.md)
- [ ] XPostgres: 역할, 테이블, 행 수준 보안, 명령문, 역할별 범위 (persistence.md)
- [ ] XGRPC: 사용 사례 위의 프로토 서비스, 변환, 포트용 클라이언트 (grpc.md)
- [ ] XTemporal, XValkey, X<Provider>: 계획에 따라 필요
- [ ] X: 명령, InMemoryProvider 기본값, Migrations, Serve 및 워커가 있는 Run (composition.md)
- [ ] 게이트웨이: 공개 RPC용 경로 (gateway.md)
- [ ] 모듈당 테스트 대상, mock 기반 (testing.md)
- [ ] CI 워크플로, Containerfile 및 Dependabot: 서비스별 (delivery.md)
- [ ] swift build 및 swift test; 수정 및 반복: 두 명령이 경고 없이 통과할 때까지
작업 추가
- [ ] 계약: XService의 대상별 RPC, 또는 XInternalService의 RPC
- [ ] XCore: 사용 사례의 다섯 파일; 해당 범위는 사용하는 것만 나열 (use-cases.md)
- [ ] XPostgres: 실행될 수 있는 역할의 범위가 해당 범위 프로토콜을 채택
- [ ] XGRPC: 핸들러 및 입력 변환, 모든 오류 케이스 매핑
- [ ] 실행 파일: 역할의 데이터베이스에서 사용 사례, 서비스에 전달
- [ ] 게이트웨이: 해당 계층의 경로 (공개인 경우)
- [ ] 테스트: 사용 사례의 결과 및 핸들러의 상태 (mock 기반)
- [ ] swift build 및 swift test; 수정 및 반복: 두 명령이 경고 없이 통과할 때까지
내구성 프로세스 추가
- [ ] XCore: XWorkflowClient 포트; 활동이 실행하는 사용 사례, 워커 범위가 채택
- [ ] XTemporal: 워크플로, 활동, TemporalXWorkflowClient, 명명된 ActivityOptions (workflows.md)
- [ ] 워크플로를 시작하는 사용 사례 (트랜잭션 커밋 후, 결정적 ID로)
- [ ] 실행 파일: Serve의 Temporal 클라이언트; 워커 그룹 및 Run 루트
- [ ] 테스트: 시간-건너뛰기 서버의 워크플로, mock 기반 활동
- [ ] swift build 및 swift test; 수정 및 반복: 두 명령이 경고 없이 통과할 때까지
CI/CD 설정
- [ ] 패키지 종류: 공개 라이브러리, 시스템 라이브러리 또는 서비스 (delivery.md#package-kinds)
- [ ] CI 워크플로: 릴리스 커밋에서 swift-microservices/ci 호출; dependabot.yml; .license_header_template 및 .licenseignore; 시크릿
- [ ] 라이브러리: semver 레이블 및 .github/release.yml; 서비스: Containerfile
- [ ] CI 플래그로 swift build 및 swift test; 수정 및 반복: 두 명령이 통과할 때까지
백엔드 검토
- [ ] 경계 검사 실행 (packages.md#checking-the-boundaries)
- [ ] 각 사용 사례: 다섯 파일, 타입-스로우, 케이스당 하나의 catch, 헬퍼 없음, 올바른 데이터베이스 역할
- [ ] 각 어댑터: 변환 및 위임만; 모든 오류 케이스 매핑
- [ ] 각 루트: 거기서만 구성 읽기, ServiceGroup의 모든 구성 요소가 의존성 순서로 배치
- [ ] Swift 설정, FoundationEssentials 가져오기, package 접근, 명명 규칙 (conventions.md)
- [ ] 발견 사항 순위 지정: 차단(테넌트 격리, 권한 부여, 자격 증명, 빌드), 주요(형태), 사소(명명, 레이아웃, 로깅). 각각 파일 및 줄 또는 빈 grep 인용, 규칙 및 수정 사항 포함. 그런 다음 사용자의 결정. 요청 시에만 코드 변경
- [ ] swift build 및 swift test; 각 결과 보고, 또는 실행할 수 없는 이유 보고
참고 자료
해당 부분의 참고 자료를 읽으세요:
| 참고 자료 | 다루는 내용 |
|---|---|
| system.md | 서비스 분할, 계약, 서비스 간 통신 방식, 공유 패키지, 계획 |
| packages.md | 대상 및 가져오기, Package.swift, Swift 설정, 특성 및 Foundation, 레이아웃, 경계 검사 |
| stack.md | 라이브러리, 각 대상이 연결하는 항목, Foundation 연결, 버전 선택 |
| use-cases.md | 모델, 오류, 저장소, 포트, 사용 사례의 다섯 파일 및 본문, 트랜잭션, 권한 부여 |
| persistence.md | 데이터베이스 역할별 범위, 행 수준 보안, 명령문, 마이그레이션, Valkey |
| grpc.md | 계약, 프로토 서비스, 핸들러, 변환, 페이징, 상태 코드, 클라이언트, 전송 |
| gateway.md | OpenAPI 유형, 요청 컨텍스트 및 계층, 컨트롤러, 웹훅, 오류, 업스트림 클라이언트 |
| workflows.md | 워크플로 시작, 페이로드, 결정론, 활동 및 옵션, 버전, 워커 |
| composition.md | 명령, 구성 루트, 구성, 로깅, ServiceGroup |
| security.md | 신뢰 모델, mTLS, 사용자 토큰, 권한 부여 계층, 시크릿, 웹훅 |
| style.md | 코드 읽기 방식: 오류, 동시성, 가져오기, Foundation, 유형, 서식 |
| testing.md | 테스트 대상, 각각이 증명하는 것, mock |
| delivery.md | 패키지 종류별 CI 워크플로, 릴리스, 배포, Containerfile, Dependabot |
| conventions.md | 패키지, 대상, 유형, 파일, 키 또는 폴더 명명 |
관련 스킬
형태 내부의 코드에 대해, 설치된 경우 다음을 로드하세요. 이 스킬이 형태를 명시하는 경우 따르세요:
- 액터, 작업 그룹, 취소,
Sendable진단, Swift 6 마이그레이션:swift-concurrency - 인수 레이블, 메서드 이름, 문서 주석:
swift-api-design-guidelines - 사용 사례, 핸들러 및 워크플로 테스트:
swift-testing-expert