Skip to main content
이 페이지는 사람이 읽는 Quickstart가 아니라 에이전트 구현 스펙입니다. 우선 @davenai/mcp 도구 **daven_guidelines**를 호출하세요 (topic=edu_app, 학생 제출 시 topic=submission). 모호하면 추측하지 말고 그 출력을 따르세요. 원문: llms.txt · Proxy: openapi.yaml · 제출: lms-openapi.yaml · activity-submission.schema.json 이미 있는 앱을 교실에 올릴 때는 기존 앱을 Daven에 얹기의 불변 조건을 지키세요. 학습 화면을 Hub나 Vibe로 바꾸지 마세요.

MUST

  1. HTTPS(또는 local) 웹앱을 호스팅한다. Hub 시작은 새 탭으로 연다.
  2. TypeScript 앱은 @davenai/sdk/edu를 우선 사용한다. SDK가 launch의 session, proxy를 읽고 주소에서 제거한다.
  3. Daven 호출은 SDK 또는 {proxy} base만 사용한다.
  4. raw fetch fallback은 매 요청에 Authorization: Bearer {session} 그리고 X-Edu-Session: {session}을 넣는다.
  5. 응답 envelope를 파싱한다: status === "success" | "error".
  6. 프론트에 API 키 / MCP 시크릿을 넣지 않는다.
  7. SDK 기본 신뢰 proxy만 사용한다. custom proxy가 필요하면 앱의 정적 설정으로만 additionalTrustedProxyUrls에 추가하고 launch query 값을 그대로 allowlist하지 않는다.
  8. shouldRelaunchEducationApp(error)가 true이면 저장한 작업은 유지하고 Hub에서 활동을 다시 열도록 안내한다.

MUST NOT

  1. 브라우저에서 daven.ai / app.daven.ai를 직접 호출하지 않는다.
  2. 추가 OAuth 팝업을 Edu 기본 플로우에 필수로 두지 않는다.
  3. 학생 원문을 AI 결과로 자동 덮어쓰지 않는다.

Defaults

Session v2 (deterministic)

새 세션은 서명된 HS256 JWT이며 version: 2, purpose, actorId를 포함하고 sub === actorId입니다. actor.id는 인증된 Hub 프로필이고 studentId는 작업 대상 학생입니다. 앱은 JWT를 직접 신뢰하지 말고 GET /api/session/context를 사용합니다. context의 학생·교사 actorId를 앱 사용자 매핑 키로 사용합니다. 이름이나 학생 코드로 매칭하지 마세요. teacher_manage만 GET /api/session/roster를 사용할 수 있으며, 응답에는 이메일·학생 코드·잔액·payer가 없습니다. 앱 전용 교사 작업 공간을 제공할 때 Master 승인 카탈로그의 supportsTeacherManage를 켜면 Hub가 이 목적의 실행 버튼을 표시합니다. 서버는 전환을 위해 서명된 v1 JWT를 정규화하지만 서명 없는 base64 세션은 거부합니다.

Submission v2 (deterministic)

  • 최종 제출 POST는 student_activity Edu 세션만 사용할 수 있습니다.
  • externalArtifactId는 선택이며 [A-Za-z0-9._:-] 문자 1–128자입니다.
  • 생략하면 __default__가 되어 기존 앱처럼 기본 행 하나를 갱신합니다.
  • Identity는 (activityId, studentId, appSlug, externalArtifactId)입니다. ID별로 여러 artifact와 재제출을 지원합니다.
  • 제출 URL은 공개 영구 HTTPS만 허용합니다. localhost, IP literal, 내부 hostname, credential 포함 URL은 금지합니다.
  • 제출 목록 GET은 Edu 세션 API가 아닙니다. 일반 Hub 교사 bearer와 해당 교실 소유권이 필요하며 익명 조회는 금지합니다.

Endpoints (complete)

구현 시 이 표만 있으면 됩니다. 앞의 proxy 경로는 launch의 {proxy}를 base로 사용합니다. 학생 제출은 SDK가 {proxy}에서 계산한 Edu API base를 사용합니다. body 필드 상세는 OpenAPI와 제출 schema를 따릅니다.

Canonical SDK client

Node BFF에서는 명시적인 session, proxy, expectedAppSlug로 @davenai/sdk/server를 사용합니다. expectedAppSlug가 session context와 다르면 SDK는 요청을 중단합니다. SDK를 사용할 수 없는 런타임만 llms.txt의 raw fetch fallback을 구현합니다.

Acceptance (binary)

에이전트는 아래가 전부 true일 때만 “연동 완료”라고 보고합니다.
  • daven.billing.getAccount() 성공
  • 세션 헤더 제거 시 → 401
  • SDK AI 호출은 사용자 동작마다 operation ID를 생성하고 같은 요청 재시도에만 재사용
  • 최종 제출은 student_activity에서만 실행하고 artifact별 externalArtifactId를 재사용
  • session 만료/401에서 저장 작업을 유지한 재실행 UI 표시
  • DevTools Network에 Edu proxy host만 존재
  • 새 탭(최상위 페이지)에서 핵심 플로우 완료 가능
  • 학생 Start로 텍스트·이미지가 각 1번 나온 뒤에만 카탈로그 Approve. 함정은 hosted-app

Reference paths

  • App: dv_mcp/apps/sihwa_project
  • Proxy: dv-edu/apps/api/src/mcp-proxy/mcp-proxy.controller.ts