Lese-Fließtexte (Intro, Messer-Liste, Callout, Fragen-Beschreibungen) von
text-secondary auf text-primary angehoben. Das zu dunkle text-muted (Quellen,
Notizen, Footer) durch das hellere text-secondary ersetzt. Sub-Labels bleiben
text-secondary zur Wahrung der Hierarchie.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Der Konzept-Abschnitt war als einziger initial geöffnet; jetzt starten alle
vier Abschnitte eingeklappt (Projektkonvention: einklappbare Kategorien sind
standardmäßig eingeklappt).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Halbgeviertstriche im sichtbaren Text durch Kommas, Doppelpunkte oder Punkte
ersetzt. Das gebündelte Verbrechen-Messer zeigt jetzt ebenfalls '+1' statt '+1 groß'.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Neue, nicht authentifizierte Route /charakter-erstellung im Dimension47-Design
(Sternenhintergrund, Magenta, Cinzel-Wordmark). Inhalt auf Deutsch:
- Die Messer-Theorie (Knife Theory): übersetzt und adaptiert, mit +1-Badges
pro Messertyp und Faustregel-Callout. Akkreditierung + Link zu r/DnD.
- 20 Fragen für tiefgründige Charaktere: vier aufklappbare Abschnitte
(Konzept, Hintergrund, Details, Spieler). Akkreditierung + Link zu plus1gaming.com.
Mobile-first, Lucide-Icons (keine Emojis), tsc -b sauber, keine Konsolenfehler.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Foundry pf2e dev clone under prisma/data/foundry-pf2e was already excluded from tsconfig.json (d421aad), but nest start --watch and nest build use tsconfig.build.json, which overrides exclude and globs the whole project. With the clone present this pulled ~39k .ts files into compilation (10,716 errors) and prevented the backend dev server from starting. Mirror the exclude in the build config.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add SUMMARY.md documenting the seed pipeline (320 ClassProgression rows + 1
ClassFeatureOption row), the four auto-fix deviations resolved during execution
(env setup, v8 path, Prisma 7 typed-input, third-party tsc exclusion), and the
contract Plan 03b consumes when appending overlay data.
- The cloned Foundry pf2e repository ships its own TypeScript source files which
reference modules our project does not have ('@common/...', 'svelte', 'vite', 'peggy').
- That clone lives at server/prisma/data/foundry-pf2e/ (gitignored, dev-time only;
the seed reads the JSON files at runtime, never the TS source).
- Add 'prisma/data/foundry-pf2e' to tsconfig exclude list so 'tsc --noEmit' on our
codebase is unaffected by third-party content.
- Iterate over D16_CLASS_NAMES; read Foundry pf2e class JSONs; merge with hand-curated overlays
- Generic pipeline (Plan 03b appends data to overlay modules; no script changes needed)
- Idempotent findUnique → update OR create per row using compound unique keys
- Loud failure with SEED-README pointer when Foundry clone is missing
- Use Prisma.JsonNull for nullable Json fields per Prisma 7 typed-input contract
- No 'any' types; type-clean against tsconfig.json
- Define ClassFeatureOptionEntry interface as the contract Plan 03b appends to
- Include School of Battle Magic as the worked Wizard School entry (optionsRef: 'wizard-school')
- Add anchor comments naming all remaining class optionsRef strings so Plan 03b knows where to append
- No 'any' types; type-clean against tsconfig.json
- Define SpellTradition type and SpellSlotOverlayEntry interface as the contract Plan 03b appends to
- Wizard fully populated L1..L19 with ARCANE slot progression and L1 cantrip count (5)
- Stub keys for the other 15 D-16 classes set to empty arrays for Plan 03b to populate
- No 'any' types; type-clean against tsconfig.json
- Pin Foundry pf2e tag to pf2e-8.0.3 (current stable, includes Player Core + APG content for all 16 D-16 classes)
- Document clone command, run command, and failure modes
- Reference Plan 03 (Wizard worked example) vs Plan 03b (bulk curation) split
- applyAttributeBoost: PF2e boost-cap-at-18 rule (Pitfall #8 mitigation)
- Returns score + 2 when current < 18
- Returns score + 1 when current >= 18
- isValidBoostSet: validates exactly 4 distinct abilities for boost levels
- Pure-function module (no NestJS, no Prisma, no I/O imports)
- TypeScript strict, named exports only
- 9/9 tests pass — proves Jest infrastructure works on src/modules/**/*.spec.ts
- 5 cases for applyAttributeBoost (boost-cap-at-18 rule, Pitfall #8)
- 4 cases for isValidBoostSet (PF2e: 4 distinct abilities required)
- Test fails (RED gate) because module is not yet implemented
- Generate migration 20260427122603_add_level_up_sessions_and_class_progression
- Auto-creates LevelUpSession, LevelUpHistory, ClassProgression, ClassFeatureOption tables
- Adds Character.freeArchetype and Character.prereqViolations columns
- Hand-append partial unique index 'LevelUpSession_characterId_open_unique'
with WHERE "committedAt" IS NULL clause (Prisma 7 cannot emit partial indexes)
- Migration applied to dev database via prisma migrate dev
- Prisma Client regenerated and exposes new models + Character columns
- Add LevelUpSession model (DRAFT state, soft-archive on commit via committedAt)
- Add LevelUpHistory model (append-only audit log of committed level-ups)
- Add ClassProgression model (per-class, per-level grants and prof changes)
- Add ClassFeatureOption model (sub-choices like doctrines/schools/instincts)
- Extend Character with freeArchetype Boolean (D-08) and prereqViolations Json (D-06)
- Add reverse relations levelUpSessions and levelUpHistories on Character
- Schema formatted via prisma format and validated via prisma validate
Five pure-function modules (types + 4 logic) implemented strict-TDD.
46 passing Jest tests across 4 spec files. Pitfall #8 (boost-cap-at-18)
and Pitfall #9 (no hpCurrent in output) both enforced by spec.
3 documented deviations:
- Rule 3: created apply-attribute-boost.ts dependency (Plan 01-01 work
not yet merged into worktree base; content matches 01-01 spec exactly)
- Rule 1: corrected L5 expected step list (PF2e CRB has class/skill
feats only at even levels; plan said feat-class+feat-skill at L5)
- Rule 1: TS-strict type-guard helpers for EvalResult narrowing
Requirements completed: LVL-02, LVL-06, LVL-09, LVL-10, LVL-01, LVL-13, LVL-14
Rule 1 deviation: TS strict mode (noImplicitAny + strict) couldn't narrow
the EvalResult union via 'r.ok' direct access because the {unknown:true,raw}
variant has no 'ok' property. Added explicit type-guard helpers (isUnknown,
isOk, isFail) for both production and spec narrowing. Runtime behavior
unchanged; tsc --noEmit now exits clean for the leveling lib.
Files:
- prereq-evaluator.ts: 3 type-guard functions, used in OR/AND walkers
- prereq-evaluator.spec.ts: isFail() in lieu of result.ok=== checks
The plan's expected list for computeApplicableSteps(5, 'Fighter', ...) was
PF2e-incorrect. Per CRB, class feats and skill feats are slotted at EVEN
levels only (2, 4, 6, ..., 20). L5 is odd → no class/skill feat.
Plan said: [class-features, boost, skill-increase, feat-class, feat-skill, feat-ancestry, review]
PF2e-correct: [class-features, boost, skill-increase, feat-ancestry, review]
The plan's other tests are internally consistent (L4 has feat-class, L3
does NOT have feat-class) — only the L5 case was misstated. Project's
'regelkonform' goal (CLAUDE.md, PROJECT.md) requires PF2e correctness
above plan literalism.
Task 2 RED phase: 9 failing tests covering PF2e skill-increase cap rule
(VALIDATION.md rows 1-W1-06 to 1-W1-11). Implementation follows in next
commit (GREEN). Verified failure: module './skill-increase-cap' not found.
Rule 3 deviation: Plan 01-01 (wave 0) work not yet merged into this
worktree base (096edbf). Plan 01-02 imports applyAttributeBoost and
AbilityAbbreviation from this module — required for types.ts and
recompute-derived-stats.ts to compile. Content matches 01-01 plan exactly,
so orchestrator merge will be clean.
- export type AbilityScore = number
- export type AbilityAbbreviation = 'STR'|'DEX'|'CON'|'INT'|'WIS'|'CHA'
- export function applyAttributeBoost(score) — PF2e boost-cap-at-18 (Pitfall #8)
- export function isValidBoostSet(targets) — exactly 4 distinct