6.6 KiB
Studio Curriculum Refactor — Notes
Branch: feat/studio-curriculum
Phase 1 (prior, by remover)
c977e0b chore: remove gamification curriculum/lesson feature— removed the unrelated gamification Curriculum/Lesson feature, freeing theCurriculumname andsrc/types/curriculum.tspath. tsc/build green.
Phase 2 (this work) — data-driven studio Curriculum (회차) entity
Three green-gated steps, commit after each (tsc --noEmit = 0):
-
2-1
a4aa1db feat(studio): add Curriculum entity, role icon registry, 3학년 1회차 seedsrc/types/curriculum.ts—Curriculum+CurriculumRole/Meta/AI/Rewards/Copy(+Localized<T>). Stages are NOT modeled here (fixed at 6 — locked decision).src/components/writing/studio/roleIconRegistry.ts— string icon key →IconType(mapPin/heart/question/default).src/data/studioCurricula/grade3-session1.ts— seed; role label/guide/placeholder/examples copied verbatim frommessages/*.json;ai.keywordCount = 5;metafrom the lesson plan (ko; en/ja = ko +// TODO i18n).- Pure addition; studio did not consume it yet.
-
2-2
3536c8d feat(studio): make writing frame data-driven via Curriculum roles- Removed the
StudioSentenceKeyunion +STUDIO_SENTENCE_ORDER. - Generalized every
Record<StudioSentenceKey, …>→Record<string, …>(StudioSegment/SuggestResponse.bySentence,StudioResult.sentencesV1/V2,StudioCompleteRequest.sentencesV1/V2, segment/suggest requestkey, flow statesentencesV2,tokensBySentence, stage props). StudioBlank.sentenceKey→roleKey: string(no back-compat — locked decision).templates.ts(studioBlankId/getStudioBlanks/composeStudioSentences) now takesCurriculumRole[](slotId-driven).studioRoleMeta.tsdeleted.studioService.ts:SEGMENT_SCHEMA/SUGGEST_SCHEMAbuilt at runtime from role keys (Gemini structured output);emptyTokenMap/emptySuggestionMapand all loops derive from the role keys carried by the request;keywordCountinjected (wasSTUDIO_KEYWORD_COUNT,pickFiveKeywords→pickKeywords).segmentation.ts/suggestion.ts: output-key instruction generated from role keys.- Routes resolve the Curriculum from
curriculumIdand add manual runtime key-validation (repo's existingvalidationErrorResponsestyle, not zod):analyze— feedsai.keywordCount.segment/suggest— reject sentences whosekeyis not a curriculum role key.complete— require all role keys present insentencesV1/V2;<p>body assembly +safeSentencesiterate role keys in frame order;roleKeysaved.
page.tsx+ stages render fromstate.curriculum.frame.rolesviaroleIconRegistry; studio loads the Curriculum withgetCurriculum(?curriculumId=)→ falls back to thegrade3-session1seed.- 3학년 1회차 renders identically to before. tsc 0,
npm run buildexit 0. - New code-seed registry:
src/data/studioCurricula/index.ts(getCurriculum,getCurriculumRoleKeys,DEFAULT_CURRICULUM_ID).
- Removed the
-
2-3
feat: data-driven studio Curriculum entity (3학년 1회차 seed)- ICU-templated copy in
messages/{ko,en,ja}.json, values fed from data:complete.title{session}←meta.sessionOrdinalkeywords.title{count}←ai.keywordCountsecondWriting.subtitle{count}←frame.roles.length
- Removed migrated keys from all three locales:
studio.roles.*,studio.firstWriting.{guides,placeholders,examples}. Platform-chrome keys kept (stepper, reward, actions, imageUpload, etc.). CRLF + tab + trailing newline preserved; key sets identical across the 3 locales (2080 each). - tsc 0, build exit 0.
- ICU-templated copy in
What is data-driven now
- Writing-frame roles (key/slotId/icon/label/guide/placeholder/examples) — variable
count & names, sourced from
Curriculum.frame.roles. - AI keyword count (
ai.keywordCount), AI structured-output schemas & prompt output keys (built from role keys at runtime). - Session/count copy (
complete.title/keywords.title/secondWriting.subtitle) via ICU + data. - Lesson-plan
meta(sessionLabel/topic/objective/achievementStandard/flow/materials/ emotionCards) — present as data on the entity.
What is intentionally FIXED (not data-driven)
- The 6-stage flow
STUDIO_STAGE_ORDER/goNext/StageStepperandstepper.*i18n labels (locked decision: stages fixed at 6). - Reward UI engine + default motion/sprite preset pools (
rewardsleft undefined → shared platform pool).
STOP points (product decisions — NOT built, per locked decisions)
- Management layer — no Firestore
curriculumscollection, CRUD API, teacher authoring console, or security rules. Curricula live only as code seeds today. A real authoring flow needs a schema + rules + UI decision. - Curriculum entry/routing — studio reads
?curriculumId=and falls back tograde3-session1. How students actually receive acurriculumId(team assignment link / home card / Topic linkage) is undecided.Resolved 2026-08-10 — a student arrives from the class session. The notice board and the classroom both link with the in-progress session's
teamId+topicId, and_flow/liveCurriculum.tsoverlays the live week/topic onto the code seed. Note thatmeta.sessionOrdinal(2-3 above) is now seeded fromTeamSession.order— the confirmed class number — rather than being the seed's own constant. There is no "assignment link"; assignments were deleted (seeDATA_MODELS.md→ TeamSession). - Existing published works — NO back-compat/migration was built (locked
decision #2). Old studio writings stored with
situation/emotion/reasonkeys andblanks[].sentenceKeymay not render correctly under the newroleKeyshape. If preserving old works matters, a migration/back-fill is required. - Multilingual authorship for
meta— en/ja formetaare ko +// TODO i18n(meta is data-only, not surfaced in UI yet). Translation authorship is out of scope. copyoverrides —CurriculumCopytype exists but the seed leaves it undefined; ICU templates live in i18n. Per-curriculum copy override wiring is not built (not needed for the seed).- Topic relationship —
Curriculum.topicId?left as an optional aggregation FK; Topic itself unchanged.
Verify
npx tsc --noEmit→ 0 errors.npm run build→ exit 0 (run afterRemove-Item -Recurse -Force .nextonce to clear a stale route-validator cache).- Pre-existing unrelated lint warnings may remain; none introduced.