feat: classroom export and import (ZIP) (#408)#418
Merged
Conversation
cosarah
reviewed
Apr 13, 2026
Collaborator
cosarah
left a comment
There was a problem hiding this comment.
Issues
Important
lib/export/use-export-classroom.ts:148—require('../../../package.json')resolves above project root fromlib/export/. Use../../package.json, or better,process.env.npm_package_version/ a Next.js build-time constant.lib/export/classroom-zip-utils.ts:10-16—buildIdMapis exported and tested but never called in production code. Either integrate it into the import flow or remove it.lib/export/classroom-zip-types.ts:35—voiceConfigonManifestAgentis declared but never populated during export or restored during import. Remove it or add a comment explaining it's reserved for forward-compat.lib/import/use-import-classroom.ts:48—JSZip.loadAsync(file)loads the entire file into memory with no size check. For classrooms with many TTS/video files this could be hundreds of MB. Consider adding a size limit warning/rejection.lib/import/use-import-classroom.ts:222— Catch-all showsimport.error.invalidZipfor non-manifest errors (e.g., IndexedDB quota exceeded). This is misleading — use a separate error key for write failures.lib/import/use-import-classroom.ts:137-146— Media record isputto DB, then if poster exists,record.posteris set andputagain. Move the poster check before the firstputto avoid the redundant write.
Minor
lib/export/classroom-zip-types.ts:8—CLASSROOM_ZIP_EXTENSIONis declared but never imported or used. The export hook hardcodes.maic.zip.- Test coverage is limited to pure utility functions. No tests for
collectAudioFiles/collectMediaFiles, import ID remapping, or export→import round-trip.
Summary
Clean architecture with good separation of concerns. Dynamic JSZip import, ID regeneration, and bidirectional audio ref mapping are well done. The issues above are mostly about robustness (size limits, error messages) and dead code cleanup — nothing blocking, but worth addressing before merge.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Read appVersion from process.env.npm_package_version instead of hardcoding - Remove unused buildIdMap export and its tests - Add forward-compat comment on ManifestAgent.voiceConfig - Add file size warning for large ZIP imports - Distinguish storage quota errors from parse errors in import - Move poster check before first DB put to avoid redundant write - Use CLASSROOM_ZIP_EXTENSION constant in export hook - Add storageFull i18n key for all 4 locales
a3e76b0 to
8c11d8e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.maic.zipcontaining course structure JSON + TTS audio + generated mediaChanges
lib/export/classroom-zip-types.ts— manifest type definitionslib/export/classroom-zip-utils.ts— media collection, ID remapping, reference rewritinglib/export/use-export-classroom.ts— export hook (collect store + IndexedDB → build manifest → JSZip → file-saver)lib/import/use-import-classroom.ts— import hook (parse ZIP → validate → remap IDs → write IndexedDB)tests/export/classroom-zip.test.ts— 7 unit/integration testscomponents/header.tsx— added "Export Classroom ZIP" to export dropdownapp/page.tsx— added import button (hover-expand) next to "Recent Classrooms"Code Review Summary
Independent code review was conducted covering spec compliance and code quality:
Strengths:
Issues found & fixed:
appVersionwas hardcoded → now reads frompackage.jsonKnown limitations (out of scope):
voiceConfignot exported (DB schema doesn't persist it — upstream limitation)Test Plan
npx tsc --noEmit— 0 errorspnpm check(Prettier) — all files formattedpnpm lint(ESLint) — 0 errors (12 pre-existing warnings)npx vitest run— 101 tests passed (8 test files)Closes #408
🤖 Generated with Claude Code