Two tables were named after the concept they came from rather than the module
they belong to, so the schema read as if the template tables were part of the
paper module. Renamed (data preserved, `RENAME TABLE` moves rows in place):
paper_template -> template the 模板 module
section_field -> template_field_library the 字段库 the 模板 module owns
The paper tables and `template_field` already followed the rule. The rename
carries through everything that named a module:
models Template, TemplateField, TemplateFieldLibrary
schemas Template*, TemplateFieldLibrary*
crud app/crud/template.py, app/crud/template_field_library.py
API /template-field-library (was /section-fields); handlers are now
named after library entries, which removes the ambiguity with
TemplateField — a placement, a different thing entirely
client src/api/templateFieldLibrary.ts
`paper_template_filed_sort` is deliberately untouched: it is a column of the
paper module, spelled as the feature was specified.
TiDB v8.5 with tidb_enable_foreign_key on — as this cluster runs — enforces
foreign keys rather than ignoring them, so the docs' "TiDB does not enforce
foreign keys" was wrong. Corrected, with what actually follows from it: the
rename was rehearsed (RENAME TABLE carries a referencing constraint along), the
API keeps checking first so a violation names the row instead of surfacing a
driver error, and the ORM cascades stay so behaviour does not depend on a
cluster setting.
Revision f27a1c6d9e04 verified both ways; 40 smoke checks, type-check and build
all pass.
Records the two decisions the paper feature rests on: a sentence is addressed
by the template placement's `sort` rather than by a row id, and citations are
a table rather than a column. Both explain behaviour that otherwise looks
arbitrary — why an empty paper already has its structure, why a template switch
destroys nothing, and why content with no matching heading is still rendered.
Also documents the new endpoints, the /papers/:id route, the paper view's three
jobs, and the smoke test.
The logo block stopped wherever its text happened to end (~140px) while the
rail below it is 208px, so the left edge was a step rather than a column.
Both now read `asideWidth()` from src/layout.ts, so they cannot drift apart,
and collapsing the rail narrows the logo block with it — the wordmark is
dropped and the mark centres in the 56px strip. The block also carries the
rail's separator up through the header, so the column reads as one piece.
The header's own 20px padding had to go for this to work: the logo block has
to start at x=0 to be flush with the rail, so the nav and the right-hand mark
now own their insets. The mark's inset comes from the same `ASIDE_INSET` as
the rail's section title, so the two line up.
A side effect worth keeping: the rail is 208px and the top nav's first item
and .el-main are each inset a further 20px by their own Element Plus defaults,
so the nav text, the page body and the page header all start on one vertical
line.
The widths live in a module rather than CSS custom properties because el-aside
takes its width through a prop and would otherwise fight an inline style.
The rail was on the right. It now leads the row instead, so the section menu
reads as a conventional left-hand navigation column.
Which side it lands on was never a stylesheet decision: `.app-body` is a flex
row and the aside is simply its first child now, with `.app-main` after it.
The only style change that had to follow is the rail's separator, which moves
from its left edge to its right, plus the collapse tooltip's placement.
The global shell contract in base.css now says this explicitly, so the next
person to move the rail knows the side comes from DOM order rather than from a
rule in that file.
Records the decisions that are not visible from the code alone:
- why section_field has no parent_id, and what reuse that buys;
- that template_field.sort is the single source of display order, and
that repeats and ties are deliberately legal;
- that templates reference library fields rather than copying them, which
is what makes a rename propagate;
- that TiDB parses FOREIGN KEY and ignores it, so the integrity lives in
the application layer.
Also adds the API table, the frontend route table, and the seed script.