From 6a24bfae5a2b356f178d2da88f93a31ff600a172 Mon Sep 17 00:00:00 2001 From: Documentation Bot Date: Mon, 31 Aug 2026 06:16:58 +0000 Subject: [PATCH] docs: Sync documentation from private repository --- PROJECT_STRUCTURE.md | 23 +++++++++++++++------ ROADMAP.md | 3 ++- TECH_STACK.md | 48 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 61 insertions(+), 13 deletions(-) diff --git a/PROJECT_STRUCTURE.md b/PROJECT_STRUCTURE.md index 4483ec3..39968e8 100644 --- a/PROJECT_STRUCTURE.md +++ b/PROJECT_STRUCTURE.md @@ -55,6 +55,12 @@ - **다국어 지원**: `imageUpload.qr`, `uploadPage` 네임스페이스 (ko/en/ja) - **배포 필요**: `firebase deploy --only database`(리스너 규칙 필수), `--only functions`(정리 스케줄) +**최근 업데이트** (2026-08-24): +- **독립 문장 연결 활동**: S6 완료 화면과 글 상세 CTA가 같은 `/student/write/sentence-linking/[writingId]` 기능을 사용. `POST/PUT /api/writing/[id]/sentence-linking`이 저장된 `studioResult.sentencesV2`를 직접 읽어 생성·저장 +- **Studio 의존성 분리**: 타입·프롬프트·서비스·검증·UI를 공용 `sentenceLinking` 모듈로 이동하고 Studio는 `WritingManager`를 통한 진입·보상 연결만 담당 +- **순서와 안전성**: 새 글은 `curriculumId`·`sentenceOrder`를 함께 저장하고 기존 글은 회차 역할 키로 순서를 복원. AI 응답 실패 시 결정적 연결어 활동으로 전환 +- **결과 저장**: `studioResult.sentenceLinking`에 원문·연결문·빈칸 답·완료 시각 저장. 완료 뒤에는 연결한 글이 `writing.content`가 되고 이어붙이기 전 문장은 `studioResult`에 남음 + **이전 업데이트** (2026-06-02): - **스튜디오 6단계 선형 글쓰기 플로우** (`/write/studio`) - "그림으로 시작 → 글 완성"을 한 페이지에서 진행하는 신규 라우트 - **단일 페이지 상태머신**: `page.tsx` 오케스트레이터(useReducer)가 단일 진실 공급원(StudioFlowState)을 보유, 7개 스테이지 컴포넌트를 순차 렌더 @@ -814,6 +820,8 @@ | **StudioImageCard** | `studio/StudioImageCard.tsx` | 🆕 **고정 비율 이미지 카드** (선택적 children, 예: 키워드 칩) | ✅ 완료 | | **RewardBanner** | `studio/RewardBanner.tsx` | 🆕 **보상 축하 배너** (S3/S5 보상 단계 공용) | ✅ 완료 | | **SentenceTokenEditor** | `studio/SentenceTokenEditor.tsx` | 🆕 **S4 낱말 칩 편집기** (낱말 탭→교체 Popover, +자리→삽입 Popover, 갱신 낱말 그라디언트, `sentenceTokens.ts` 조립/폴백 유틸) | ✅ 완료 | +| **SentenceLinkingActivity** | `sentence-linking/SentenceLinkingActivity.tsx` | 🆕 **공용 문장 연결 활동** (번호 빈칸 자유 입력, 예시 힌트, 원문·연결 결과 비교, Studio·독립 페이지 공유) | ✅ 완료 | +| **SentenceLinkingCta** | `SentenceLinkingCta.tsx` | 🆕 **완성 글의 단독 문장 연결 진입 카드** (작성자·상상형·저장 문장 2개 이상일 때 노출) | ✅ 완료 | | **DraftSentenceList** | `studio/DraftSentenceList.tsx` | 🆕 **(aiDraft) 초안 문장 목록 + 다듬기 팝업** (번호+타입 배지+하이라이트 문장 행, 클릭 → AI 제안 후보/직접 고쳐 쓰기 Popover, role.color 배지·하이라이트) | ✅ 완료 | | **studioMotion** | `studio/studioMotion.ts` | 🆕 **스튜디오 공용 애니메이션** (studioFadeIn/Pop/Breathe/EmptyBreathe @keyframes + STUDIO_REDUCED_MOTION prefers-reduced-motion 게이트) | ✅ 완료 | | **studioRoleMeta** | `studio/studioRoleMeta.ts` | 🆕 **역할 메타 정의** (상황/마음/까닭 아이콘·라벨, RolePill 공용) | ✅ 완료 | @@ -948,7 +956,7 @@ | **SecondWritingStage** | `_stages/SecondWritingStage.tsx` | 🆕 **S4 글 다듬기** (낱말 분해 + 교체·삽입 추천, SentenceTokenEditor) | ✅ 완료 | | **DraftRefineStage** | `_stages/DraftRefineStage.tsx` | 🆕 **(aiDraft 모드) AI 문단 초안 + 문장 다듬기** (문장 타입별 한 줄, 문장 클릭 → AI 제안/직접 고쳐 쓰기 팝업, DraftSentenceList) | ✅ 완료 | | **RewardEffectStage** | `_stages/RewardEffectStage.tsx` | 🆕 **S5 보상②** (스프라이트 이펙트 1개 부여, RewardCanvasEditor) | ✅ 완료 | -| **CompletionStage** | `_stages/CompletionStage.tsx` | 🆕 **S6 완료** (1회차 수업 종료, complete API 호출 → 발행) | ✅ 완료 | +| **CompletionStage** | `_stages/CompletionStage.tsx` | 🆕 **S6 완료** (complete API 호출 → 발행, 상상형 문장 연결 후속 활동 진입) | ✅ 완료 | **주요 기능**: - ✅ **단일 페이지 선형 상태머신** (useReducer, 단계 전환 부수효과는 오케스트레이터 goNext에서 처리) @@ -959,8 +967,8 @@ - ✅ **역할별 자유 3문장**: 상황/감정/이유를 한 문장씩 자유 작성 (고정 빈칸 템플릿 제거, 선생님 직접 교육 + 예문·전구 안내로 지도) - ✅ **S2→S3 전환**: 모든 입력 채움 검증 → draft Writing 생성(createWriting) + 이미지 업로드(uploadUserImage), 1차 문장을 2차 작문 초기값으로 시드 - ✅ **S3/S5 보상**: 공용 RewardCanvasEditor (영역 1개 제한), 적용 시 distortionAreas/spriteEffectAreas 저장 후 자동 전진 -- ✅ **AI 엔드포인트 6개**: `/api/studio/analyze`(키워드), `/api/studio/segment`(S4 분해), `/api/studio/suggest`(S4 교체·삽입 추천), `/api/studio/draft`(aiDraft 문단 초안), `/api/studio/rewrite`(aiDraft 문장 고쳐 쓰기 후보), `/api/studio/complete`(발행) -- ✅ **데이터 저장**: writings.keywords + writings.studioResult (sentencesV1/V2, blanks, grantedInteraction/Effect, completedAt), status draft→published, rewardType `participation` +- ✅ **Studio 엔드포인트 6개**: `/api/studio/analyze`(키워드), `/api/studio/segment`(S4 분해), `/api/studio/suggest`(S4 교체·삽입 추천), `/api/studio/draft`(aiDraft 문단 초안), `/api/studio/rewrite`(aiDraft 문장 고쳐 쓰기 후보), `/api/studio/complete`(발행) +- ✅ **데이터 저장**: writings.keywords + writings.studioResult (sentencesV1/V2, curriculumId, sentenceOrder, blanks, grantedInteraction/Effect, sentenceLinking, completedAt), status draft→published, rewardType `participation` - ✅ **다국어 지원** (studio namespace, pageTitles.writeStudio, ko/en/ja) --- @@ -1213,7 +1221,8 @@ firebase functions:log --only cleanupExpiredReservations | **Pattern Analysis** | `patternAnalysisService.ts` | 🆕 **글 작성 패턴 분석 서비스** (10개 글 종합 분석, AI 평가) | ✅ 완료 | | **Spelling Check** | `spellingService.ts` | **맞춤법 검사 서비스** (Gemini 기반, 초등학생 눈높이) | ✅ 완료 | | **Writing Assistance** | `writingAssistanceService.ts` | 🆕 **AI 글쓰기 도우미 서비스** (4단계 힌트 생성, 주제 맥락 활용, 서버 캐싱) | ✅ 완료 | -| **Studio Service** | `studioService.ts` | 🆕 **스튜디오 플로우 AI 서비스** (extractStudioKeywords: 그림→키워드 5개, segmentSentences: 띄어쓰기 교정+낱말 분해, suggestReplacements: 교체·삽입 추천, generateStudioDraft: aiDraft 문단 초안+하이라이트, suggestSentenceRewrites: aiDraft 문장 고쳐 쓰기 후보, _ai 사용량 메타 전달) | ✅ 완료 | +| **Studio Service** | `studioService.ts` | 🆕 **스튜디오 플로우 AI 서비스** (그림 키워드, 문장 분해·추천, aiDraft 초안·고쳐 쓰기, _ai 사용량 메타 전달) | ✅ 완료 | +| **Sentence Linking Service** | `sentenceLinkingService.ts` | 🆕 **저장 글 기반 문장 연결 생성 서비스** (Studio와 독립 페이지 공유, 응답 검증·결정적 폴백) | ✅ 완료 | | **Region Health** | `regionHealthManager.ts` | **Region 과부하 상태 추적** (자동 복구, 1분 TTL) | ✅ 완료 | | ~~**Team Service**~~ | ~~`teamService.ts`~~ | ~~팀 CRUD~~ | ⚠️ Deprecated (TeamManager로 이동) | | ~~**Student Service**~~ | ~~`studentService.ts`~~ | ~~학생 CRUD, PIN 해시/검증~~ | ⚠️ Deprecated (UserManager로 대체) | @@ -1235,7 +1244,8 @@ firebase functions:log --only cleanupExpiredReservations | **Team 타입** | `team.ts` | 팀 데이터 모델 (members Map), 🆕 **AIAssistanceConfig** (AI 도우미 설정) | ✅ 완료 | | **FirestoreUser 타입** | `firestoreUser.ts` | **FirestoreUser** (DB 저장용, 🆕 **plan/organizationId 필드 추가**, 🆕 **loginId/isSystemAccount/createdByTeacher 필드**), **User** (UI용) 분리 | ✅ 완료 | | **Writing 타입** | `writing.ts` | 글 데이터 모델, 🆕 **WritingAnalysis** (AI 분석 결과, contentHash 기반 재사용), **SpellingError** (맞춤법 오류), 🆕 **AIAssistanceRecord** (AI 도움 이력), 🆕 **GeneratedImage** (AI 생성 이미지), 🆕 **keywords?·studioResult?** (스튜디오 플로우 필드) | ✅ 완료 | -| **Studio 타입** | `studio.ts` | 🆕 **스튜디오 6단계 플로우 타입** (StudioStage, StudioSentenceKey, StudioBlank, StudioScaffold, StudioToken, StudioResult, Analyze/Segment/Suggest/Complete Request·Response, STUDIO_STAGE_ORDER/SENTENCE_ORDER) | ✅ 완료 | +| **Studio 타입** | `studio.ts` | 🆕 **스튜디오 플로우 타입** (단계·문장·빈칸·토큰·결과, Analyze/Segment/Suggest/Complete Request·Response) | ✅ 완료 | +| **Sentence Linking 타입** | `sentenceLinking.ts` | 🆕 **공용 문장 연결 타입** (Activity, Blank, Segment, Result, 저장 요청) | ✅ 완료 | | **Scene 타입** | `scene.ts` | 🆕 **장면 데이터 모델** (Scene, SceneExtractionResponse) | ✅ 완료 | | **Draft 타입** | `draft.ts` | 글조각 데이터 모델 (Draft, DraftListItem, **AnalysisHistoryItem**, **syncStatus**: 'local'\|'synced'\|'syncing') | ✅ 완료 | | **WritingPattern 타입** | `writingPattern.ts` | **글 작성 패턴 분석** 데이터 모델 (WritingPatternAnalysis) | ✅ 완료 | @@ -1317,6 +1327,7 @@ firebase functions:log --only cleanupExpiredReservations | **스튜디오 완료** | `/api/studio/complete` | POST | 🆕 **S6 발행** (draft→published, studioResult 저장, HTML sanitize, AI 호출 없음, 주제 사용량 증가) | ✅ 완료 | | **글 생성** | `/api/writing` | POST | 🆕 **글 생성** (wordCount/charCount 자동 계산, 🆕 **analysis 저장**) | ✅ 완료 | | **글 조회** | `/api/writing/[id]` | GET | 🆕 **글 조회** (작성자만 접근) | ✅ 완료 | +| **글 문장 연결** | `/api/writing/[id]/sentence-linking` | POST, PUT | 🆕 **저장 문장으로 활동 생성·결과 저장** (작성자·상상형·발행 상태·2문장 이상 검증) | ✅ 완료 | | **글 분석** | `/api/writing/[id]/analyze` | POST | 🆕 **글 분석 실행** (서버 데이터 기반, 결과 저장) | ✅ 완료 | | **글 수정** | `/api/writing/[id]` | PUT | 🆕 **글 수정** (작성자만 접근, 통계 재계산) | ✅ 완료 | | **글 삭제** | `/api/writing/[id]` | DELETE | 🆕 **글 삭제** (작성자만 접근) | ✅ 완료 | @@ -1600,4 +1611,4 @@ project_w/ --- -© 2024 BlueNovaLab. All rights reserved. \ No newline at end of file +© 2024 BlueNovaLab. All rights reserved. diff --git a/ROADMAP.md b/ROADMAP.md index 67cb73a..539cb4d 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -178,6 +178,7 @@ | **스튜디오 플로우 UI 통합 리디자인** | **공용 프리미티브 + 단계별 일관 레이아웃, S2 빈칸 입력 버그 수정 (src/components/writing/studio/에 표현 전용 공용 프리미티브 정리: StudioCard·StudioStageHeader·RolePill+studioRoleMeta·FillBlankSentence·StudioImageCard·RewardBanner·ExpressionChip·studioMotion, 전 단계가 하나의 카드/헤더/애니메이션 시스템 공유, FillBlankSentence 고정 폭 빈칸 입력 + 빈칸별 힌트로 입력 늘어남 버그 수정, studio namespace i18n 키 추가 roles.{situation,emotion,reason}·firstWriting.blankStub·rewardInteraction.tip·rewardEffect.tip·reward.{controlsTitle,dragHint,applyButton}·secondWriting.contextTitle, ko/en/ja)** | **2026-06-04** | | **S2 첫 글쓰기 자유 작성 전환** | **고정 빈칸 템플릿("나는 ___ 때 ___ 일이 있었습니다" 등) 제거 → 선생님 직접 교육 방식. 역할(상황/감정/이유)별 자유 Textarea 1문장 + 전구 안내(guides) + 예문 2개(examples)를 FirstWritingStage가 직접 렌더, FillBlankSentence 컴포넌트 삭제, templates.ts 토큰 템플릿 제거하고 역할당 1슬롯 모델로 단순화 (STUDIO_BLANK_IDS 3개·getStudioBlanks·composeStudioSentences(values)·studioBlankId), StudioTemplateToken/StudioSentenceTemplate 타입 제거, 다운스트림(sentencesV1/V2·S4 분해) 불변, 예문/안내는 현재 i18n 하드코딩(주제 연동 시 주제 데이터로 변수화 예정), firstWriting i18n 재구성 freePlaceholder·examplesLabel·guides.{situation,emotion,reason}·examples.{role}.{0,1} (ko/en/ja). 부수: TECH_STACK 스튜디오 섹션을 이미 반영된 S4 segment/suggest 파이프라인 기준으로 정정** | **2026-06-04** | | **스튜디오 aiDraft 모드 (AI 초안 + 문장 다듬기)** | **회차(Curriculum)에 수업 방식 mode 필드 도입 (CurriculumMode "selfWriting"\|"aiDraft", 미지정=selfWriting, 모드별 스테이지 순서는 getStudioStageOrder가 코드로 고정), aiDraft 5단계 플로우 (업로드→AI 문단 초안 생성→문장 다듬기→보상①→보상②→완성), frame.roles를 "문장 타입"(중심 문장·이유·장면 설명·예시·마무리)으로 재해석 (CurriculumRole.color 배지·하이라이트 파스텔색 + aiHint 타입별 AI 지시문 추가), AI 엔드포인트 2개 신설 (POST /api/studio/draft 타입당 1문장 초안+핵심 구절 highlight, POST /api/studio/rewrite 타입당 완성 문장 후보 2~3개·백그라운드 프리페치), DraftRefineStage+DraftSentenceList (번호+타입 배지+하이라이트 문장 행, 클릭→팝업: 고치기 안내 guide+AI 제안 선택+직접 고쳐 쓰기 Textarea), 초안 원문은 studioResult.sentencesV1로 저장 (초안→다듬은 글 비교), StageStepper stages prop (모드별 단계 표시), 교사 콘솔 확장 (CurriculumFormModal 수업 방식 선택, CurriculumRoleEditor aiDraft 모드 시 배지 색 스와치 피커+AI 문장 조건 입력·placeholder/examples 숨김, CurriculumList 모드 배지), 교사 개수 설정 (ai.rewriteCount 1~4 문장당 AI 제안 필수 제시 개수 — 부족 시 서버 1회 재시도·병합·재시도 사용량 별도 로깅, ai.requiredEditCount 0~문장 타입 수 필수 수정 문장 수 — 초안 원문 대비 달라진 문장 기준·goNext 가드+nextBlockedReason+complete API 서버 검증·"고친 문장 n/N" 진행 칩·고친 행 체크 표시, validateCurriculumAiCounts 서버 범위 검증), 시드 회차 grade3-session2 (aiDraft, 문장 타입 5종, rewriteCount 3·requiredEditCount 2), 서버 resolveCurriculum (Firestore 우선+코드 시드 폴백 — segment/suggest/complete 라우트도 교사 생성 회차 키 검증 가능하도록 교체), studioService generateStudioDraft/suggestSentenceRewrites + prompts/studio/draft.ts, 다국어 지원 (studio.draftRefine·stepper.draftRefine·error.draftFailed/sentencesRequired, ko/en/ja)** | **2026-06-10** | +| **상상형 문장 연결 후속 활동 + 독립 실행** | **스튜디오 완료 화면의 "문장 연결하기"와 완성 글 상세 CTA 구현. 두 진입점 모두 POST/PUT /api/writing/[id]/sentence-linking을 통해 저장된 studioResult.sentencesV2 key/value를 직접 읽고, 새 글에 저장한 curriculumId·sentenceOrder 또는 기존 회차 역할 키로 문장 순서를 복원하므로 AI 문장 재분리와 클라이언트 원문 전달이 없음. 공용 sentenceLinking 타입·프롬프트·서비스·서버 검증·UI로 Studio 의존성을 분리. 번호형 점선 빈칸·예시 힌트·원문/연결 결과 비교 제공, 학생 자유 입력은 정답 판정 없이 허용. AI 규칙 검증 실패 시 결정적 폴백. 결과는 studioResult.sentenceLinking에 저장하고 연결한 글이 writing.content가 되며(이어붙이기 전 문장은 studioResult.sentencesV2·originalText에 보존) Studio 진입에서는 RewardEffectStage 추가 보상 연결. 작성자·상상형·published·완성 문장 2개 이상 서버 검증, ko/en/ja i18n 및 서버 단위 테스트 추가** | **2026-08-24** | | **QR 휴대폰 사진 업로드 + 이미지 업로드 UI 리디자인** | **공용 ImageDropzone 전면 리디자인(구름 업로드 클러스터+핑크 점선 테두리+흰 알약 버튼[파일 선택/카메라로 촬영/휴대폰으로]+우하단 카메라 스티커, 전 사용처 공통 적용, compact/containerAspectRatio/일반 3모드 보존) + QR 휴대폰 사진 핸드오프(데스크톱 QR↔휴대폰 /{locale}/upload/{id}, 폰 캔버스 축소 전송[최대 1600px JPEG], 공유 저장소 RTDB /handoffs/{id}, 데스크톱 onValue 실시간 리스너로 즉시 감지→기존 ImageCropper 4:3 크롭 연결). 비인증 POST/DELETE /api/handoff(폰 쓰기 Admin 경유·데스크톱 읽기만 클라 리스너). 보안: 128bit handoffId·IP별 레이트리밋(RTDB 트랜잭션 1분 30회)·매직바이트 MIME 검증·작은 이미지 가드(600px 미만 거부)·database.rules.json handoffs(읽기 auth/쓰기 false). 정리: functions cleanupHandoffs(onSchedule 매시, 버려진 /handoffs·/handoff_rate 삭제). 신규 src/lib/handoff/{config,rateLimit}.ts·src/app/api/handoff/{route,store}.ts·QrUploadDialog.tsx·app/[locale]/upload/[id]/page.tsx·functions/src/cleanup/cleanupHandoffs.ts. 다국어 imageUpload.qr·uploadPage(ko/en/ja). 배포: firebase deploy --only database·functions** | **2026-06-10** | | **새 디자인 시안 포팅** | **`raonnuri-next-main` 목업을 Chakra UI v3로 전면 포팅. 디자인 시스템 확장(design.* semantic 토큰 네임스페이스, 그림자 토큰 6종, textStyles 7종, 버튼 variant 5종, input variant, 기본 폰트 SUIT→Pretendard, package.json postinstall typegen). 인증 구조를 LoginDialog 모달→전용 페이지 9개로 전환(/login, /signup 역할선택, /signup/{student,teacher,complete,pending,rejected}, /find-account, /sns/role, authStore.openLoginDialog는 /login 리다이렉트 shim), 공용 AuthCard/PasswordEyeInput 컴포넌트 신설. 크롬 리디자인(Navbar 역할 기반, TeacherShell+teacher/layout.tsx 사이드바 셸, Footer). 학생 홈 리디자인(히어로 카드+알림장+나의 팀 그리드, StudentHeroCard/StudentNoticeCard/StudentTeamMiniCard). 마이페이지 리디자인(시안 3섹션 MyProfileSection 추가, 기존 통계·구독 유지). 팀/글 페이지 리디자인(/team, /team/all, /team/[teamId], /writing, /writing/[writingId] - TeamCard/WritingCard 리디자인, 투톤 제목, 캐러셀). 교사 콘솔 리디자인(/teacher/home 대시보드 신규, /team/[teamId]/manage 6탭 재구성, /team/create 커리큘럼 연동 폼). 교사 신규 페이지 2개(/teacher/learning 학습관리 - 커리큘럼 테이블+월 캘린더, /teacher/notice 공지사항 - 현재 목데이터, 백엔드 미연동). i18n ko/en/ja 신규 네임스페이스(auth, teacherLearning, teacherNotice, teacherShell 등), 키 정합성 2143개 일치** | **2026-07-03** | @@ -490,4 +491,4 @@ enum UserRole { --- -© 2024 BlueNovaLab. All rights reserved. \ No newline at end of file +© 2024 BlueNovaLab. All rights reserved. diff --git a/TECH_STACK.md b/TECH_STACK.md index 10663ec..68d0290 100644 --- a/TECH_STACK.md +++ b/TECH_STACK.md @@ -2690,7 +2690,33 @@ S5 complete 발행 — sentencesV1 = AI 초안 원문, sentencesV2 = 다 - **교사 개수 설정 (aiDraft)**: `ai.rewriteCount`(1~4, 기본 3) — 문장당 AI 제안 **필수 제시 개수**. 프롬프트가 "정확히 N개"를 요구하고, 정제 후 부족하면 서비스가 1회 재시도해 두 응답을 병합(중복 제거)으로 채운다(본호출+재시도 각각 logAIUsage). `ai.requiredEditCount`(0~문장 타입 수, 기본 0) — **필수 수정 문장 수**. "고침" = 문장이 초안 원문(sentencesV1)과 달라진 상태이며, 기준을 채워야 다음 단계로 전진(클라 가드: goNext + nextBlockedReason) 및 발행 가능(complete API 서버 검증). UI는 초안 카드에 "고친 문장 n/N" 진행 칩 + 고친 행에 체크 아이콘 표시. 범위 검증은 POST/PUT /api/curriculum의 `validateCurriculumAiCounts`가 담당. - **초안 재생성 가드**: `draftOriginal`이 캐시 역할(같은 그림 재진입 시 재생성 안 함), SET_IMAGE 시 초안·문장·후보 모두 무효화. -#### AI 엔드포인트 6개 +#### 상상형 문장 연결 후속 활동 (2026-08-24) + +상상형 회차의 완료 화면과 완성 글 상세에서 발행된 글을 짧은 문장 연결 활동으로 확장한다. 이 활동은 기존 본문을 수정하지 않고 별도 학습 결과로 저장한다. + +``` +S6 complete 또는 완성 글 상세 CTA + ↓ writingId와 작성자 권한 확인 +POST /api/writing/[id]/sentence-linking + ↓ studioResult.sentencesV2 + sentenceOrder를 서버에서 직접 로드 +SentenceLinkingActivity + ↓ 학생이 모든 빈칸 자유 입력 - 정답 판정 없음 +원문 / 연결 결과 비교 + ↓ PUT /api/writing/[id]/sentence-linking +studioResult.sentenceLinking 저장 + ↓ Studio에서 시작한 경우에만 RewardEffectStage 재진입 +그림 이펙트 영역 1개 추가 +``` + +- **대상 제한**: 작성자 본인의 `published` 상상형 Studio 글이며 저장된 완성 문장이 2개 이상일 때만 호출 가능 +- **원문 복원**: 새 글은 `curriculumId`·`sentenceOrder`를 저장하고, 기존 글은 주제에 해당하는 회차 역할 키로 순서를 복원. AI 문장 재분리 없음 +- **공용 경계**: `sentenceLinking` 타입·프롬프트·서비스·서버 검증·UI는 Studio 밖에 두고, Studio와 독립 페이지가 `WritingManager`를 통해 공유 +- **빈칸 구성**: 문장 합치기 1~2개, 연결어 2~4개, 꾸밈말 2~3개를 합쳐 총 6~8개 +- **응답 검증**: AI 자체 점검값, 원문 순서, 보호 구절, 빈칸 유형·개수, 예시 존재 여부를 서버에서 다시 확인 +- **장애 폴백**: AI 실패나 규칙 위반 시 원문과 결정적 연결어 빈칸으로 안전한 활동을 즉시 구성 +- **저장 방식**: 결과는 `studioResult.sentenceLinking` 하위 필드만 갱신하며 기존 본문은 유지 + +#### Studio AI 엔드포인트 6개 | API | 경로 | AI | 역할 | |-----|------|----|------| @@ -2709,6 +2735,8 @@ S5 complete 발행 — sentencesV1 = AI 초안 원문, sentencesV2 = 다 - `suggestSentenceRewrites(types, sentences, keywords, locale)` — (aiDraft) 타입당 완성 문장 후보(현재 문장·중복 제외, 3개 클램프), 실패 시 빈 후보 폴백 - 사용량 메타데이터(`_ai`)는 라우트로 그대로 전달 → 라우트가 logAIUsage 기록 +**문장 연결 공용 모듈**: `src/services/sentenceLinkingService.ts`, `src/prompts/sentenceLinking.ts`, `src/lib/server/sentenceLinking.ts`, `src/lib/shared/sentenceLinking.ts`, `src/types/sentenceLinking.ts` + **프롬프트**: `src/prompts/studio/templates.ts`(역할별 자유 슬롯 — STUDIO_BLANK_IDS/getStudioBlanks/composeStudioSentences/studioBlankId), `src/prompts/studio/segmentation.ts`·`suggestion.ts`·`draft.ts`(ko/en/ja) #### 데이터 / 영속화 모델 @@ -2728,15 +2756,18 @@ interface StudioResult { keywords: string[]; sentencesV1: Record; // 1차 작문 (학생 단독) sentencesV2: Record; // 2차 작문 (AI 도움, 최종 본문) + curriculumId?: string; // 신규 저장 글의 회차 식별자 + sentenceOrder?: string[]; // 역할 키 기준 완성 문장 순서 blanks: StudioBlank[]; grantedInteraction: boolean; // S3 보상 적용 여부 grantedEffect: boolean; // S5 보상 적용 여부 + sentenceLinking?: SentenceLinkingResult; // 상상형 후속 활동 결과 completedAt: string; // ISO 8601 } ``` **저장 위치별 정리**: -- **writings 컬렉션**: `keywords`, `studioResult`(sentencesV1/V2·blanks·grantedInteraction/Effect·completedAt) +- **writings 컬렉션**: `keywords`, `studioResult`(sentencesV1/V2·curriculumId·sentenceOrder·blanks·grantedInteraction/Effect·sentenceLinking·completedAt) - **보상**: 인터랙션/이펙트는 `distortionAreas` / `spriteEffectAreas` (S3/S5에서 클라이언트가 저장, complete API는 건드리지 않음) - **상태 전이**: `status` draft → published (최초 발행 시 주제 usageCount 1회 증가) - **보상 분류**: `rewardType: 'participation'` @@ -2758,6 +2789,8 @@ interface StudioResult { - **`StudioImageCard`** — 고정 비율 이미지 카드 (선택적 children, 예: 키워드 칩) - **`RewardBanner`** — S3/S5 보상 축하 배너 공용 - **`SentenceTokenEditor` + `sentenceTokens`** — S4 낱말 칩 편집기 (낱말 탭→교체 Popover, +자리→삽입 Popover, 갱신 낱말 그라디언트 표시) + 토큰 조립/폴백 유틸 +- **`writing/sentence-linking/SentenceLinkingActivity`** — Studio와 독립 페이지가 공유하는 문장 연결 빈칸 입력·원문/결과 비교 UI +- **`writing/SentenceLinkingCta`** — 작성자의 상상형 완성 글에서 독립 활동으로 진입 - **`studioMotion`** — 공용 `@keyframes`(studioFadeIn/Pop/Breathe/EmptyBreathe) + `STUDIO_REDUCED_MOTION`(prefers-reduced-motion 게이트) - **S2 자유 작성**: 고정 빈칸 템플릿(FillBlankSentence) 제거 → FirstWritingStage가 역할별 자유 Textarea + 전구 안내 + 예문을 직접 렌더 - **i18n 추가**: `studio` 네임스페이스에 `roles.{situation,emotion,reason}`, `firstWriting.{freePlaceholder,examplesLabel,guides.*,examples.*}`, `rewardInteraction.tip`, `rewardEffect.tip`, `reward.{controlsTitle,dragHint,applyButton}`, `secondWriting.*`(낱말 편집 키) (ko/en/ja) @@ -2769,10 +2802,13 @@ interface StudioResult { - `src/app/[locale]/student/write/studio/_stages/*.tsx` - 7개 스테이지 컴포넌트 - `src/components/ui/StageStepper.tsx` - 6단계 진행 표시기 - `src/components/writing/studio/RewardCanvasEditor.tsx` - 인터랙션/이펙트 공용 편집기 -- `src/components/writing/studio/{StudioCard,StudioStageHeader,RolePill,StudioImageCard,RewardBanner,SentenceTokenEditor,DraftSentenceList}.tsx` + `{sentenceTokens,studioMotion,studioRoleMeta}.ts` - 공용 프리미티브 (통합 비주얼 언어) +- `src/components/writing/studio/{StudioCard,StudioStageHeader,RolePill,StudioImageCard,RewardBanner,SentenceTokenEditor,DraftSentenceList}.tsx` + `{sentenceTokens,studioMotion,studioRoleMeta}.ts` - Studio 공용 프리미티브 (통합 비주얼 언어) +- `src/components/writing/sentence-linking/SentenceLinkingActivity.tsx` - 진입점과 무관한 문장 연결 UI - `src/services/studioService.ts` - extractStudioKeywords / segmentSentences / suggestReplacements / generateStudioDraft / suggestSentenceRewrites -- `src/app/api/studio/{analyze,segment,suggest,draft,rewrite,complete}/route.ts` - AI 엔드포인트 6개 -- `src/prompts/studio/{templates.ts,segmentation.ts,suggestion.ts,draft.ts}` - 프롬프트 +- `src/services/sentenceLinkingService.ts` - 저장 글 기반 문장 연결 활동 생성 +- `src/app/api/studio/{analyze,segment,suggest,draft,rewrite,complete}/route.ts` - Studio 엔드포인트 6개 +- `src/app/api/writing/[id]/sentence-linking/route.ts` - 독립 생성(POST)·결과 저장(PUT) +- `src/prompts/studio/{templates.ts,segmentation.ts,suggestion.ts,draft.ts}` + `src/prompts/sentenceLinking.ts` - 프롬프트 - `src/types/studio.ts` - 플로우 타입(StudioStage/getStudioStageOrder/StudioDraftSentence 등), `src/types/curriculum.ts` - CurriculumMode/CurriculumRole(color·aiHint), `src/types/writing.ts` - keywords?/studioResult? --- @@ -2829,4 +2865,4 @@ interface StudioResult { --- -© 2024 BlueNovaLab. All rights reserved. \ No newline at end of file +© 2024 BlueNovaLab. All rights reserved.