feat(import): UI polish, contract requests, report

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Lucas Winther
2026-10-30 03:22:22 +01:00
co-authored by Claude Opus 5.5
parent 90a477691b
commit c4df51f7ca
3 changed files with 13 additions and 1 deletions
+11
View File
@@ -0,0 +1,11 @@
# Contract requests from WP-B (Importer)
1. **`loadConfig` should add `<dataDir>/courses` to `courseDirs`.** The importer writes courses there. Worked around in `apps/server/src/main.ts` (the main guard pushes it) and in `packages/feature-import/dev/serve.ts`. `/api/import/info` reports `coursesDirServed` and the UI warns when it is false.
2. **`startServer` accepts feature factories** (`Feature | ((ctx) => Feature)`). A `Feature` needs `ServerContext`, but `ServerContext.jobs` is built from the features' job handlers. `importFeature(ctx)` only reads `ctx` while a job or request runs, so `main.ts` now builds `ctx` first, resolves the factories, then assigns `ctx.jobs`. The edit is about ten lines in `apps/server/src/main.ts`; Phase 2 should keep or replace it.
3. **Web entry for features.** `apps/web` must not pull a package's server code into the browser bundle. `@stc/feature-import` exposes a browser-safe entry as `./web` (package.json `exports`), but the root tsconfig `paths` (`@stc/*` to `packages/*/src`) cannot resolve `@stc/feature-import/web`, so `apps/web/src/features.ts` imports it by relative path. Suggest a tsconfig `paths` entry per feature, or a `src/web.ts` convention.
4. **Derived cache layout (no contract defines one).** Written by the importer, to be read by the learner and AI packages:
- `<dataDir>/cache/decks/<courseId>/<deckId>/p-001.jpg ...` (1280px wide JPEGs) and `text.json` (`[{ page, text }]`);
- `<dataDir>/cache/covers/<courseId>/frame-N.jpg` and `deck-<deckId>.jpg` (cover candidates);
- `<dataDir>/cache/transcripts/<courseId>/<lessonId>.json` (`{ lessonId, text, segments: [{ start, end, text }] }`).
Suggest a `cacheDir`/`deckPageUrl` helper in core, and a media route for `cache/decks` so the deck viewer can load pages.
5. **Video lessons have no description field.** Packt clips come with a one-line description. It is dropped, because `transcript` is the only Markdown a video lesson can carry and the transcription job writes it.
@@ -65,7 +65,7 @@ function JobRow({ job }: { job: Job }) {
{warnings.length ? (
<details><summary>{warnings.length} warning{warnings.length > 1 ? "s" : ""}</summary><ul className="warn">{warnings.map((w, i) => <li key={i}>{w}</li>)}</ul></details>
) : null}
{job.status === "done" && job.kind !== "import.transcribe" && result?.courseId ? <CoverPicker courseId={result.courseId} /> : null}
{job.status === "done" && (job.kind === "import.packt-video" || job.kind === "import.video-folder") && result?.courseId ? <CoverPicker courseId={result.courseId} /> : null}
</li>
);
}
+1
View File
@@ -26,6 +26,7 @@
.imp-status[data-s="running"] { color: var(--accent); }
.imp-job-bar { display: flex; align-items: center; gap: 12px; }
.imp-job-msg { font-size: 12.5px; color: var(--faint); }
.imp-job-bar .imp-job-msg { flex: none; width: 200px; text-align: right; }
.imp-job details { font-size: 12.5px; color: var(--muted); }
.imp-job summary { cursor: pointer; }
.imp-job ul.warn { margin: 6px 0 0; padding-left: 18px; }