Skip to content

feat: 플랫폼 서브도메인 DNS 레코드를 서버가 관리한다 - #114

Merged
yessjun merged 7 commits into
mainfrom
feat/platform-dns-records
Sep 7, 2026
Merged

feat: 플랫폼 서브도메인 DNS 레코드를 서버가 관리한다#114
yessjun merged 7 commits into
mainfrom
feat/platform-dns-records

Conversation

@yessjun

@yessjun yessjun commented Sep 7, 2026

Copy link
Copy Markdown
Member

📝 작업내용

  • 플랫폼 서브도메인마다 A 레코드를 서버가 만들고 지우는 경로 신설, 손으로 둔 와일드카드 한 장이 대상을 하나밖에 못 가리키던 제약 해소
  • DNS 제공자 추상화와 Google Cloud DNS 클라이언트, 의존성 추가 없이 REST 와 서비스 계정 JWT 로 구현
  • 미설정은 fail-closed, 새 플랫폼 공개만 거부하고 기존 라우트와 커스텀 도메인은 무영향
  • V113 으로 도메인 행에 DNS 상태와 마지막 오류, 반영 시각 추가, 스키마만이고 시드 없음
  • 라우트 적용과 관리자 재동기화, 예약 스위퍼에 레코드 수명주기 연결
  • 고아 레코드 정리는 기본 꺼짐, 켜기 전에 무엇이 지워질지 로그로 먼저 보도록
  • API 명세 0.68.0, 도메인 표현 셋에 dnsStatus 와 두 필드, 연산 수 불변
  • 클라이언트 주소와 인증서 주석을 현재 구성으로 정정

⭐️ 검증

  • 테스트 1341개 통과, 실패 0, checkstyle 과 의존성 감사 포함
  • API 명세 드리프트 6건 통과, 수기 마스터를 지정해 이름 축까지 실행
  • 고아 판정을 19개 레코드 존으로 고정, 아펙스와 와일드카드, 예약 라벨, 타 IP, 비 A 타입, 유예 중인 이름 제외를 각각 확인
  • 미설정 제공자가 커스텀 도메인과 기존 라우트를 건드리지 않는 것을 시험으로 고정
  • 적대 검토 지적 다섯 반영, 기록은 pickle-review

💬 리뷰 포인트

  • 고아 정리 기본값을 꺼짐으로 둘지, 존에 손으로 둔 레코드가 없다고 보고 켤지

@yessjun
yessjun force-pushed the feat/platform-dns-records branch from a834095 to 0014318 Compare September 7, 2026 05:09
ClientIps still explained a CDN header chain, and the certificate
classes still called the shared wildcard a CDN origin certificate. Both
retired with the CDN: the trusted hops are the reverse proxy, which
restores the peer from PROXY protocol and sets X-Real-IP, and the app
tier that forwards it; the wildcard is a Let's Encrypt one. The enum
label stays until it is renamed on its own.
One interface the platform-subdomain lifecycle drives (ensure an A
record, remove it, list the zone) and three implementations: Google
Cloud DNS through its REST API, a noop for dev and test, and the
fail-closed default that reports itself unconfigured so the api boots
either way. The Google client signs the service-account assertion with
jjwt and exchanges it for a bearer itself; no vendor SDK is added.
A platform subdomain now gets its own A record, written outside the
transaction that changes the domain, so the row has to say where that
write stands: a status, the last error and the time the record was
last confirmed present. The three fields reach the user and admin
domain views (contract v0.67.0); custom domains stay NONE by constraint.
The record is a step of the same three-phase apply under the same
generation guard: ensured before the vhost is rendered, removed after
it is gone, never a 422. A failed step leaves the route for the
reconciler, the reservation sweeper takes a leftover record down before
it frees the name, and the admin resync adds missing records and prunes
single-label orphans under a platform root only when that is enabled.
Refusing a new platform publish when no provider is set is correct and happens
earlier. Running the DNS step on every PRESENT push was not: a port edit or a
reconcile of an existing name failed before the agent was called, so the vhost
went untouched too, on a deployment whose names already resolve. The step now
runs only when a provider is configured, the posture the reconciler already
had.

Two more from the same review. The resync ensured records from a manifest read
before the provider calls, so a name released in between had its record put
back with nothing left to take it down; it now re-reads before writing. And
the prune read its claim set once, which let a name freed during the scan and
immediately reclaimed lose the new owner's record; it now re-checks under the
same lock it deletes under. The reserved-label set is folded to match the
folded names it is compared against, and the no-op provider is refused on
production, where it would mark every name applied while none resolves.
This branch is waiting on an operator to place a credential, not on review, so
it has no claim on the lower number and another round took 0.68.0 to ship
today. The rule is that whoever deploys first gets the lower number.
Another round needs a migration and deploys today, while this branch waits on
an operator. Flyway is stricter than the contract constant: out-of-order
application is off, so a lower number arriving after a higher one refuses to
start. Whoever deploys first takes the lower number.

Safe to rename because it has never been applied: the live history tops out at
V112 and that host carries one database. An applied migration could not be
moved at all, which is why this was measured rather than reasoned about.
@yessjun
yessjun force-pushed the feat/platform-dns-records branch from 0014318 to 407d25d Compare September 7, 2026 06:41
@yessjun
yessjun merged commit 1449899 into main Sep 7, 2026
1 check passed
@yessjun
yessjun deleted the feat/platform-dns-records branch September 7, 2026 06:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant