Record ListFree Board
실 운영에서 드러난 SPA/API 런타임 계약 문제들 정리 ( 그누보드7 )
humanpchumanpc ·
05-2753
최근 운영 중인 그누보드7 기반 환경을 점검하면서, 문서/설계 의도와 실제 런타임 계약(runtime contract) 사이가 어긋나는 지점들을 몇 가지 발견하게 되었습니다.
단순히 "버그 수정"이라기보다는, 실제 운영 환경에서만 드러나는 경계 조건에 가까운 사례들이었습니다.
이번에 확인한 것들 중 인상적이었던 것은 아래 2가지였습니다.
* Accept 헤더 유무에 따라 보호 API가 JSON 401 대신 HTTP 500을 반환하던 문제
* 존재하지 않는 public SPA 경로가 404 대신 SPA shell 200으로 응답하던 문제
첫 번째는 꽤 흥미로웠습니다.
SPA/API 중심 구조에서는 login route가 아예 없는 경우가 자연스러운데, 특정 조건에서 Laravel의 unauthenticated redirect 흐름이 여전히 route('login') 을 시도하면서 Route [login] not defined 예외가 발생하고 있었습니다.
즉,
curl -i https://example.com/api/me
는 500이 되고,
curl -i -H 'Accept: application/json' https://example.com/api/me
는 정상적으로 JSON 401이 되는 상태였습니다.
운영 환경에서는 API 클라이언트나 crawler/tooling이 항상 Accept 헤더를 정확히 넣는다는 보장이 없기 때문에, 실제로는 꽤 중요한 차이였습니다.
두 번째는 SPA catch-all 관련 문제였습니다.
존재하지 않는 경로도 모두 SPA shell로 fallback되면서 HTTP 200을 반환하고 있었는데, Googlebot UA까지 동일하게 200을 받는 상태였습니다.
결국 crawler 입장에서는 "없는 페이지도 정상 페이지처럼 보이는" 상태가 됩니다.
이 부분은:
* 등록된 template route인지 먼저 확인
* 미등록 public path는 명시적으로 404 반환
구조로 정리했습니다.
이번 점검 과정에서는 그 외에도:
* bundled template i18n contract 불일치
* runtime driver source-of-truth 혼선
* SEO/static renderer parity 문제
* lazy chunk topology 경계 문제
* public/storage symlink serving 정책
같은 운영 레벨의 계약 불일치들도 함께 확인했습니다.
재미있었던 점은, 대부분이 "기능 자체는 동작"하고 있었지만:
* crawler
* static renderer
* API client
* 운영자
* 배포 환경
같은 서로 다른 소비자 관점에서는 계약이 조금씩 달라지고 있었다는 부분입니다.
결국 실제 운영 안정성은 "기능이 된다"보다:
* 동일한 계약이 유지되는가
* 모든 소비자가 같은 결과를 보는가
* fallback이 의도된 방식으로 동작하는가
쪽에 훨씬 가까운 문제라는 생각이 들었습니다.
최근에는 이런 식으로 "문서/설계/런타임/운영"이 실제로 얼마나 일치하는지를 계속 점검해 보고 있습니다.
Comments and actions are deferred
Load the comment and action area when you need it. Comments: 0
