| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
feat(email): let organizations set the sender display name Transactional mail went out as a hardcoded "LearnHouse <...>". An organization on a white-labelled deployment could not show its own name, and a self-hoster could not rebrand at all. Only the display NAME is configurable. The From address stays mailing.system_email_address, the domain holding the verified SPF/DKIM records — an org-chosen address would fail DKIM alignment on every message and damage a sending reputation shared across tenants. - LEARNHOUSE_SYSTEM_EMAIL_SENDER_NAME sets the deployment default and falls back to the previous name, so an unset install is unchanged. - Per-org override at customization.general.email_sender_name; the org config is a JSON blob, so no migration. - The name is admin-typed text landing in an RFC 5322 header, so sanitize_sender_name() removes control characters and line separators outright rather than replacing them, and formataddr() handles quoting and RFC 2047 so non-Latin names survive instead of being stripped. Sanitizing runs on write and again on read, so a row edited directly in the database cannot reach a header unfiltered. - Org-created and org-deleted mail stay platform-branded, for reasons noted at both call sites. | 15 天前 | |
feat: refactor the entire learnhouse project | 2 年前 | |
fix(editor,assignments): follow-up fixes for H5P resize, due dates - Re-chain due_date migration onto dev's real head; the old down_revision forked the graph, so `alembic upgrade head` aborted with MultipleHeads instead of applying it. - Fix unsaved-changes guard: it stripped `height` from H5P nodes unconditionally, so a custom-mode resize (which touches no other attribute) vanished with no save prompt. - Add a 3px drag threshold, stop arrow keys from committing past the clamp, and drop pointercancel instead of committing it; add aria-valuemin/max/text to the resize handle. - Trim stored deadlines with a time component to YYYY-MM-DD so the date input isn't blank and doesn't get silently overwritten on save. - Pin the H5P SIZE_MODES test to an ordered list; the old assertion missed a dropped 'auto'. - Mark due_date optional/nullable in the offline OpenAPI snapshot. | 7 天前 | |
feat(api): add the demo content bundle Everything a prospect sees, checked in as data: 6 courses across 3 sections, 18 chapters, 54 activities, 6 graded assignments, 40 learner personas, 3 cohorts, a community with 5 discussions, 3 canvas boards, 2 playgrounds, 3 podcasts with 10 episodes and a storefront with 5 offers. The loader validates the whole thing on read, so a malformed bundle fails at startup with a specific message rather than half-building an organization. Two properties the sync depends on: Activity content compiles from a compact block DSL, and every id it emits is uuid5 of the text it belongs to. Compiling the same bundle twice is byte-identical, which is what lets a refresh compare rather than rewrite. Personas are drawn from a seeded generator, so a given content epoch always produces the same distribution. Images and audio come from committed generator scripts rather than stock files: provenance is clean, there is no licensing question, and no photograph of a real person or AI-generated face is involved. Board canvases are Yjs CRDT documents, built by a script in apps/collab where yjs already lives. | 21 天前 | |
Merge pull request #1069 from learnhouse/fix/prod-regression-sweep fix(api): anonymized users no longer 500 org member lists | 7 天前 | |
perf(api): bake bytecode, split docker layers for faster cold start Cold start profiling showed about 17s of every container start was pure bytecode compilation, because uv sync never cached .pyc files and the whole source tree invalidated the dependency layer on every commit. Adds a missing apps/api/.dockerignore and execs uvicorn directly instead of going through uv run. | 1 个月前 | |
feat: improvements to analytics layer | 6 个月前 | |
perf(api): bake bytecode, split docker layers for faster cold start Cold start profiling showed about 17s of every container start was pure bytecode compilation, because uv sync never cached .pyc files and the whole source tree invalidated the dependency layer on every commit. Adds a missing apps/api/.dockerignore and execs uvicorn directly instead of going through uv run. | 1 个月前 | |
feat: refactor the entire learnhouse project | 2 年前 | |
feat: init alembic + add init revision | 2 年前 | |
release: bump version to 1.3.5 | 12 天前 | |
feat(api): reconcile the demo organization in place instead of rebuilding it One idempotent sync, run every 10 minutes. It overwrites registered rows back to their bundle values, deletes anything unregistered as visitor drift, and upserts derived progress. A settled demo costs exactly one write — an UPDATE to its own bookkeeping row — instead of churning roughly seven thousand rows per cycle. Rebuilding would have burned primary keys, piled up dead tuples, and orphaned storage on every half-failed teardown. Four things make that hold, each a trap if missed: Fields are compared before assignment. Assigning an equal value still marks the attribute dirty in SQLAlchemy and emits an UPDATE, so _apply exists to keep a no-op run silent. Timestamps derive from a content epoch that rolls once a day, never now(). Upload filenames are derived rather than drawn. A random name is unknowable to a later refresh, so the guard could only ask "is this column empty?" — and a column a visitor overwrote is not empty. Deriving it makes the correct value computable, so branding, thumbnails, avatars and audio revert like any other bundle-managed field. The bundle version is part of the key, which is how new artwork reaches an existing demo. Progress is reconciled, not accumulated. The daily epoch redraws every persona; without a matching removal, enrolments only ever grew until all forty learners appeared to be taking the whole catalogue. Drift deletion covers what a visitor can leave behind, including the rows the generic uuid sweep cannot see because they hang off a parent rather than carrying an org_id: discussion comments, votes and reactions, certifications, their own learning progress and submissions, activity versions, library-root entries and custom roles. Deleting a role first moves the memberships holding it, since role_id has no ON DELETE and would otherwise abort the transaction. Teardown lives in its own module so it can be tested against a session rather than only a live deployment, and removes the three things the org cascade cannot reach: the seeded students, authorship rows that reference content by a bare uuid, and uploaded files. The tests alongside it state the promise directly: a table of "a visitor edits this, the refresh puts it back" and its mirror for deletion, one entry per bundle-managed entity, plus a pass over each drift sweep and the scheduler's guards. The idempotence test asserts on emitted SQL rather than on the sync's own counters, because the counters are what would be wrong if it regressed. | 21 天前 | |
perf(api): bake bytecode, split docker layers for faster cold start Cold start profiling showed about 17s of every container start was pure bytecode compilation, because uv sync never cached .pyc files and the whole source tree invalidated the dependency layer on every commit. Adds a missing apps/api/.dockerignore and execs uvicorn directly instead of going through uv run. | 1 个月前 | |
fix(deps): update dependency resend to v2.41.0 | 6 天前 | |
feat: add the demo entry points, routes and tests /demo/status and /demo/enter, and the surfaces that use them: an entry card on onboarding and the org picker, a DEMO badge so a shared sandbox is never mistaken for one of your own organizations, and a banner that says what the demo is and counts down to the next reset. The banner is fixed to the top of the dash column rather than sitting in flow — several dash pages are h-screen with their own inner scrolling, so a strip in flow made the column taller than the viewport, and the bottom edge is where the save bars and the mobile menu live. Copy goes through i18n like the rest of the app, and robots.txt asks the API whether an org is the demo before allowing it to be indexed. Tests cover the bundle, the sync, the exclusions, teardown and the routes. Several assert the negative case too, because a guard that is never exercised is a guard that quietly stops working: entering the demo must not consume a free-org slot, and the members filter must not touch a real organization. The 403 assertions are pinned to the guard's own message — RBAC answers 403 here as well, and one of these tests was passing for that reason rather than the intended one. Two unrelated test fixes, both the same shape: an opt-in live suite that failed instead of skipping on a developer machine. The Ollama tests checked that the port answered but not that the model was pulled, and the superadmin token tests imported the Enterprise package without forcing the deployment mode that makes those code paths reachable. DEMO_STACK.md documents running it locally; the scripts generate their own secrets rather than carrying any. | 21 天前 | |
fix(deps): update dependency resend to v2.41.0 | 6 天前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 15 天前 | ||
| 2 年前 | ||
| 7 天前 | ||
| 21 天前 | ||
| 7 天前 | ||
| 1 个月前 | ||
| 6 个月前 | ||
| 1 个月前 | ||
| 2 年前 | ||
| 2 年前 | ||
| 12 天前 | ||
| 21 天前 | ||
| 1 个月前 | ||
| 6 天前 | ||
| 21 天前 | ||
| 6 天前 |