← 목록
기타 2026-05-28 10KB 읽기 11분

크라우니브라우저 2.1 — 앱 모드 / 웹 모드 분기 표준

날짜: 2026-05-28 대상: 크라우니 도메인 서버 개발자 (web/asset/edu/play/bank/dex/architect 등) 브라우저 버전: CrownyBrowser/2.1 SSOT: 이 문서 + /Users/ef/CrownyOS/crownyc/libs/앱모드감지.한선


1. 개요

크라우니브라우저는 일반 웹 브라우저와 달리 4상균형3진 벡터형 응답을 받을 수 있다. 서버는 HTTP 헤더 4개로 클라이언트를 식별하고 분기한다.

  • 앱 모드 (app): 크라우니브라우저 — HTML + <crowny-vector> 메타데이터 블록 응답
  • 웹 모드 (web): 일반 브라우저 (Chrome/Safari/Firefox) — 표준 HTML만 응답
  • 미상 (unknown): UA 누락 등 — 반드시 웹 모드로 fallback (보안)

2. 표준 헤더 4개

2.1 요청 헤더 (클라이언트 → 서버)

헤더예시 값의미
User-AgentCrownyBrowser/2.0 (CrownyOS; 한선씨)UA. 위조 가능 — 단독 판정 금지
X-Crowny-Browser2.1크라우니브라우저 버전. 있으면 앱 확정
X-Crowny-LayerT / O / A / U4상균형3진 레이어 (데이터/명령/체이닝/미정)
Accepttext/html,application/xhtml+xml,application/crowny+vector;q=0.9,*/*;q=0.5application/crowny+vector 포함 → 벡터 응답 가능

2.2 응답 헤더 (서버 → 클라이언트)

헤더의미
VaryUser-Agent, Accept, X-Crowny-Browser캐시 분리 키
X-Crowny-Modeapp / web서버가 판정한 모드 (디버그/관측용)
X-Crowny-Mode-Sourceheader-check / cookie / force판정 근거
Content-Typetext/html; charset=utf-8 (웹) <br> text/html; charset=utf-8 (앱, 벡터는 body 내 블록)응답 타입

3. 분기 알고리즘

1. X-Crowny-Browser 헤더가 있으면        → 앱 모드 (1)
2. (위조 차단) X-Crowny-Browser 없는데
   User-Agent 에만 "CrownyBrowser" 있으면 → 웹 모드 (0)
3. User-Agent 가 있고 위 둘 다 해당없으면 → 웹 모드 (0)
4. User-Agent 자체가 없으면              → 미상 (-1) → 웹 모드 fallback

왜 두 헤더가 일치해야 신뢰? UA는 누구나 위조 가능하다. X-Crowny-Browser 는 크라우니브라우저 빌드에 하드코딩되어 있고 일반 브라우저는 보내지 않는다. 두 헤더가 일관되게 들어와야 진짜 크라우니브라우저로 판정한다.


4. 한선씨 서버 코드 예시

javascript가져오기 "라우터.한선"
가져오기 "네트워크.한선"
가져오기 "앱모드감지.한선"   // 본 표준 모듈

함수 처리(요청) {
    변수 요청헤더 = 요청맵_헤더(요청)
    변수 모드 = 앱모드_요청검사(요청헤더)
    변수 레이어 = 앱모드_레이어추출(요청헤더)
    변수 벡터원함 = 앱모드_벡터응답원하는가(요청헤더)

    변수 응답헤더 = 맵생성()
    앱모드_응답헤더설정(응답헤더, 모드)

    변수 본문 = ""
    만약 (모드 == 1) {
        // 앱 모드 — 벡터 메타데이터 동봉
        본문 = "<html><body><h1>크라우니자산</h1>"
        만약 (벡터원함 == 1) {
            본문 = 본문 + "<crowny-vector layer=\"" + 레이어 + "\">"
            본문 = 본문 + "{\"shape\":\"hero\",\"trits\":27,\"layer\":\"" + 레이어 + "\"}"
            본문 = 본문 + "</crowny-vector>"
        }
        본문 = 본문 + "</body></html>"
    } 아니면 {
        // 웹 모드 — 표준 HTML만
        본문 = "<html><body><h1>자산관리</h1><p>일반 페이지</p></body></html>"
    }

    반환 HTTP응답(200, "text/html; charset=utf-8", 본문, 응답헤더)
}


5. Node.js 서버 코드 예시 (참고 — 한선씨 미적용 서버)

javascriptfunction detectMode(headers) {
  const cb = headers['x-crowny-browser'];
  const ua = headers['user-agent'] || '';
  if (cb) return 'app';                          // 앱 확정
  if (ua.includes('CrownyBrowser')) return 'web'; // UA 위조 의심 — 웹 fallback
  if (!ua) return 'unknown';                     // 미상 — 웹 fallback
  return 'web';
}

function getLayer(headers) {
  const l = headers['x-crowny-layer'];
  return (l === 'T' || l === 'O' || l === 'A' || l === 'U') ? l : 'U';
}

function wantsVector(headers) {
  const accept = headers['accept'] || '';
  return accept.includes('application/crowny+vector');
}

app.use((req, res, next) => {
  const mode = detectMode(req.headers);
  const layer = getLayer(req.headers);
  const wantVec = wantsVector(req.headers);

  res.setHeader('Vary', 'User-Agent, Accept, X-Crowny-Browser');
  res.setHeader('X-Crowny-Mode', mode === 'unknown' ? 'web' : mode);
  res.setHeader('X-Crowny-Mode-Source', 'header-check');

  req.crownyMode = mode;
  req.crownyLayer = layer;
  req.crownyWantsVector = wantVec;
  next();
});

app.get('/', (req, res) => {
  if (req.crownyMode === 'app' && req.crownyWantsVector) {
    const meta = JSON.stringify({ shape: 'hero', trits: 27, layer: req.crownyLayer });
    res.send(`<html><body><h1>크라우니</h1>
      <crowny-vector layer="${req.crownyLayer}">${meta}</crowny-vector>
      </body></html>`);
  } else {
    res.send(`<html><body><h1>표준 페이지</h1></body></html>`);
  }
});

참고: 새 도메인 서버는 반드시 한선씨로 작성한다. Node.js 예시는 기존 레거시 서버 마이그레이션 가이드용이며, 동반 .한선 파일을 필수로 만든다.

6. 응답 형식

6.1 웹 모드 응답 (일반)

html<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <title>자산관리</title>
  <link rel="stylesheet" href="/css/main.css">
</head>
<body>
  <h1>크라우니 자산관리</h1>
  <p>일반 콘텐츠</p>
</body>
</html>

6.2 앱 모드 응답 (벡터 메타데이터 포함)

html<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta name="crowny-design" content="premium-v1">
  <title>자산관리</title>
</head>
<body>
  <h1>크라우니 자산관리</h1>
  <p>일반 콘텐츠</p>

  <!-- 크라우니브라우저 전용 메타데이터 블록 (다른 브라우저는 무시) -->
  <crowny-vector layer="T">
  {
    "shape": "hero-card",
    "trits": 27,
    "layer": "T",
    "cube": [1,0,-1,0,1,-1,...],
    "actions": [
      {"name":"열기", "opcode":347, "args":[0,0,800,600]},
      {"name":"채우기", "opcode":349, "args":[1,0,-1]}
    ]
  }
  </crowny-vector>
</body>
</html>

  • <crowny-vector> 태그는 표준 HTML 파서가 무시한다 (커스텀 요소).
  • 크라우니브라우저는 이 블록을 추출해 GPU렌더러로 직접 전달한다.
  • 모바일/iframe 안전: display:none 기본.

7. 캐시 가이드

7.1 Vary 헤더 필수

Vary: User-Agent, Accept, X-Crowny-Browser

  • 같은 URL에 앱/웹 응답이 분리 캐시되어야 한다.
  • CDN/리버스 프록시(crowny-gateway)는 이 키로 캐시 분리.
  • Accept-Language 도 다국어 분기에 필요하면 추가.

7.2 Cache-Control

Cache-Control: public, max-age=300, must-revalidate

  • 앱 모드 응답은 벡터 옵코드가 자주 바뀔 수 있으므로 짧게 (5분 권장).
  • 정적 자산(이미지, 폰트, CSS)은 분기 없이 공통 — 길게 (1년).

7.3 ETag

벡터 메타데이터의 SHA256 해시를 ETag로 사용 권장:

ETag: "T-a8f3c9d2..."   // 레이어 prefix + 해시


8. 보안 가이드

8.1 헤더 위조 시 fallback

  • X-Crowny-Browser 헤더는 누구나 보낼 수 있다 — 단독으로 신뢰 금지.
  • UA만 CrownyBrowser 라고 주장하면 웹 모드로 처리 (위조 의심).
  • 진짜 크라우니브라우저는 두 헤더를 일관되게 보낸다.

8.2 벡터 메타데이터에 민감 정보 금지

  • <crowny-vector> 블록은 일반 브라우저에서도 view-source로 보인다.
  • 인증 토큰, PII, 내부 ID 등을 박지 마라.
  • 시각/구조 정보만 (도형, 좌표, opcode, 색상).

8.3 X-Crowny-Layer 검증

  • 클라이언트가 보내는 X-Crowny-Layer 값은 신뢰하지 않는다 (단순 힌트).
  • 서버 비즈니스 로직(권한, 가격, 인증)은 layer로 분기하지 마라.
  • layer는 렌더링 분기에만 사용.

8.4 Content-Security-Policy

앱 모드 응답에도 CSP 적용:

Content-Security-Policy: default-src 'self' crowny-internal:; style-src 'self' 'unsafe-inline'; img-src 'self' data:;


9. 점진 적용 가이드

  1. 1단계: 응답 헤더만 추가 (Vary, X-Crowny-Mode). 본문은 동일.
  2. 2단계: 모드 판정 함수 도입 (앱모드_요청검사). 로깅으로 비율 측정.
  3. 3단계: 앱 모드 응답에 <crowny-vector> 블록 점진 추가.
  4. 4단계: 캐시 분리 (Vary 활용) + CDN 설정.
  5. 5단계: 벡터 옵코드 정식 채택 — premium-v1 디자인 시스템과 통합.

10. 관련 파일

  • 헤더 전송 (클라이언트): /Users/ef/CrownyBrowser/src/v2/HTTP스택.한선 §2 (기본헤더설정)
  • 모드 감지 (서버): /Users/ef/CrownyOS/crownyc/libs/앱모드감지.한선
  • 브라우저 메인 빌드: /Users/ef/CrownyBrowser/src/v2/크라우니브라우저v2.한선
  • 게이트웨이 캐시: /Users/ef/crowny-gateway/cache.yaml (Vary 키 등록)

11. 잔여 이슈

  • <crowny-vector> 파싱 옵코드는 GPU렌더러에 아직 미통합 (v2.2 예정)
  • crowny-gateway 의 Vary 멀티 키 캐시 검증 필요
  • 모바일 크라우니브라우저(iOS/Android)는 미구현 — UA 식별만 가능
  • application/crowny+vector MIME 등록 (IANA 자체 영역) 검토 중