Figures
A question could carry exactly one stem image and one explanation image, each a
bare path with no title, no legend, and no way for the prose to refer to it.
`question_media` makes a figure a row: it points at an image already in the bank,
carries a role, a label the text can name ("Figure 1"), a caption and an order,
and there can be as many as the question needs. The same radiograph can serve two
questions without being stored twice.
The 346 existing paths were backfilled into figure records and retitled —
`page_339_img_0.png` says where a file came from and nothing about what it shows,
so the filename moved into the caption where it is still searchable, and the
title became something a person can read.
On the editor question: no new platform needed. Milkdown is already installed —
ProseMirror-based, MIT, GFM tables, code blocks, LaTeX — and already used for
articles, courses and the quick question modal. Only the question *page* still
has plain textareas, and that swap is written down rather than rushed, because
the stem carries manual-highlight offsets and a WYSIWYG rewrite would move them.
Fewer hints during a quiz
The category trail and the difficulty pill were shown beside every stem. Being
told a question is filed under Neonatology, or that it is "hard", narrows the
answer before the stem has been read. Both now wait until the answer is in,
where the trail becomes a way to more of the same topic.
The dashboard is about questions
Quizzes and attempts describe how the material happens to be packaged. What a
learner is working through is questions: how many of the bank they have seen,
how many they have answered correctly, and their average. The old per-quiz
performance card — which needed two attempts before it showed anything — is
gone, superseded by the session analysis. The greeting sits above "continue your
study" rather than below it, where it read as a heading for the wrong section.
208 backend, 249 frontend green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
42 lines
1.8 KiB
Python
42 lines
1.8 KiB
Python
"""Figures on a question: many of them, labelled, and each a real image record.
|
|
|
|
Revision ID: f0a1b2c3d4e5
|
|
Revises: e9f0a1b2c3d4
|
|
"""
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
from sqlalchemy import inspect
|
|
|
|
revision = "f0a1b2c3d4e5"
|
|
down_revision = "e9f0a1b2c3d4"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade():
|
|
# A question could carry exactly one stem image and one explanation image,
|
|
# held as a bare path with no title, no legend and no way to refer to it
|
|
# from the text. This makes a figure a row: it points at an image in the
|
|
# bank, carries the label the prose calls it by, and there can be several.
|
|
if "question_media" not in inspect(op.get_bind()).get_table_names():
|
|
op.create_table(
|
|
"question_media",
|
|
sa.Column("id", sa.Integer, primary_key=True),
|
|
sa.Column("question_id", sa.Integer,
|
|
sa.ForeignKey("questions.id", ondelete="CASCADE"), nullable=False, index=True),
|
|
sa.Column("media_id", sa.Integer,
|
|
sa.ForeignKey("media_assets.id", ondelete="CASCADE"), nullable=False, index=True),
|
|
# Where it belongs. A figure that illustrates the answer must not
|
|
# appear beside the stem, which is the mistake this whole area had.
|
|
sa.Column("role", sa.String(20), nullable=False, server_default="stem"),
|
|
# What the prose calls it — "Figure 1" — so the text can say
|
|
# "shown in Figure 1" and mean something.
|
|
sa.Column("label", sa.String(80), nullable=True),
|
|
sa.Column("caption", sa.Text, nullable=True),
|
|
sa.Column("position", sa.Integer, server_default="0"),
|
|
sa.UniqueConstraint("question_id", "media_id", "role", name="uq_question_media"),
|
|
)
|
|
|
|
|
|
def downgrade():
|
|
op.drop_table("question_media")
|