Engineering conventions
These are the standing rules for working in the ContentsVision repo. They live in full in the repo's CLAUDE.md; this page summarizes them so the whole team shares the same expectations. They apply to everyone, including AI assistants working in the codebase.
Run the tests after every change
The hard rule, repeated because it matters: run ./run_tests.sh after any change, and keep it green before considering the work done. A change with no test is incomplete. Show real failing output; never claim green when it is red. Full detail in testing.
Writing style: no em dashes
Never use em dashes anywhere: UI copy, code comments, commit messages, chat. Use a period, comma, colon, or parentheses instead. (This handbook follows the same rule.)
Frontend UI conventions
Use the existing design system in frontend/src/app/globals.css rather than hand-rolling Tailwind for common controls. Skim globals.css first, and add a new component class there rather than inlining styles.
| Element | Use | Not |
|---|---|---|
| Inputs | .as-input (or .as-input-sm) | raw <input className="border ..."> |
| Selects | the shared <StyledSelect> component | a native <select> (breaks the visual language) |
| Buttons | .btn-primary / .btn-secondary / .btn-danger (+ .btn-sm, .press) | ad-hoc button styles |
| Surfaces | .card, .stat-card | bespoke panels |
| Labels | .filter-label, .col-header, .eyebrow | one-off label styles |
.as-select exists only as a legacy fallback and should be migrated to StyledSelect.
Motion
Every user action should have a subtle animation; stillness reads as broken. Anything that mounts, unmounts, expands, collapses, or moves must animate in and out.
- Use Framer Motion for conditionally rendered elements: wrap in
<AnimatePresence>and give explicitinitial,animate, andexit. Do not use a bare{cond && <div/>}for visible elements (the exit will not animate). - The CSS keyframe utilities (
.animate-slide-down,.animate-fade-in, etc.) only animate the enter side; use them for things that mount once and stay. - Keep durations short (120-220ms). Use Material standard easing
[0.4, 0, 0.2, 1]for panel/height transitions andeaseOutfor fades and pops. - Add
.pressto clickable elements for tactile feedback. - Re-key a list's container on sort/filter/pagination changes so rows re-mount and re-trigger their enter animation.
Add new keyframes under the "Motion primitives" section of globals.css, not as ad-hoc inline @keyframes.
Help Center articles
The in-app Help Center (distinct from this handbook) has its own house style:
- Short, verb-first headings; one task per heading; terse steps and bullets.
- Every article starts from the home Dashboard and tells the reader how to navigate to where the article begins.
- Concise to the point that removing one more word would break the sentence.
- Use many screenshots, one under each step a reader might get stuck on.
- Explain every feature in the flow; if it is not explained, it does not exist to the user.
- When the reader might have more questions, point them to
[email protected].
Handoff prompts
Never save a handoff prompt or "paste this into the next session" text to a file. Put it directly in the chat reply, inside a single fenced code block, so it can be copied. Do not split it across sections or create files for it.
Why these exist
The conventions keep the product coherent: one visual language, motion that signals state, copy in one voice, and a test suite that stays trustworthy. They also let any contributor (or any AI session) pick up work without re-litigating style. When in doubt, match the surrounding code's idiom, comment density, and naming.