Skip to content

feat(db): Phase 2c-i — style_templates + style_rules + default style_rules seed#87

Merged
thewrz merged 4 commits into
mainfrom
feat/issue-30
May 19, 2026
Merged

feat(db): Phase 2c-i — style_templates + style_rules + default style_rules seed#87
thewrz merged 4 commits into
mainfrom
feat/issue-30

Conversation

@thewrz
Copy link
Copy Markdown
Contributor

@thewrz thewrz commented May 19, 2026

Summary

  • Adds style_templates + style_rules schema (migration 010) and a UFGS-derived default seed (migration 011) so a future PR (feat(generator): Phase 2c-iii — wire templateId through generator #32) can override per-NodeType font/size/indent/spacing/bold/caps in DOCX output without code changes.
  • Adds src/db/queries/templates.ts with getTemplate, getTemplateByName, listTemplates, createTemplate, upsertStyleRule and re-exports them from the db barrel.
  • Renames the internal generator numbering reference from Csi → Spec (buildCsiNumberingConfigbuildSpecNumberingConfig, CSI_NUM_REFSPEC_NUM_REF, 'csi-numbering''spec-numbering'). Output is functionally identical; verified zero remaining grep hits.
  • Adds docs/references/UFGS/**/*.docx to .gitignore — the fixture (27080001.docx) stays local; its extracted values are encoded in migration 011's comment table + INSERT statements so a reviewer can verify the mapping without re-running extraction.
  • Updates ARCHITECTURE.md schema overview with the two new tables.

Design doc (authoritative — supersedes the original issue body which said .sql migrations): docs/superpowers/specs/2026-05-18-issue-30-design.md.

Schema decisions vs original issue body

Field Original Final Reason
font_size_pt NUMERIC font_size_half_pt INTEGER OOXML native unit, no float drift
space_*_pt NUMERIC *_twips INTEGER OOXML native unit
caps absent BOOLEAN NOT NULL DEFAULT false UFGS PART/Article use w:caps
(template_id, node_type) none UNIQUE one rule per type per template
style_templates.name none UNIQUE stable lookup by 'UFGS-Default'
bold nullable NOT NULL DEFAULT false tri-state has no use

Out of scope (per design doc)

Test plan

  • pnpm migrate succeeds; pnpm migrate:down reverses 011 then 010 cleanly; re-apply succeeds
  • pnpm test — 462 unit tests pass (numbering.test.ts updated to use renamed buildSpecNumberingConfig)
  • pnpm test:integration — 117 pass, 65 pre-existing skips. New templates.integration.test.ts covers: UFGS-Default has exactly 7 rules; each NodeType present once; part row matches extracted values (Courier New, sz=20, bold=true, caps=true, 'PART %1 -'); getTemplate returns null for unknown id; createTemplate round-trips; upsertStyleRule is idempotent (insert then update); FK CASCADE deletes child rules; UNIQUE name constraint rejects duplicates
  • pnpm lint clean (eslint + tsc + prettier)
  • grep -rn 'csi-numbering\|buildCsiNumberingConfig\|CSI_NUM_REF' src/ returns zero hits
  • .docx fixture is gitignored (not in the commit)

Closes #30

Summary by CodeRabbit

  • New Features

    • Added a firm style template system with seeded UFGS default rules and updated DOCX section numbering.
  • Documentation

    • Architecture doc updated to describe the new style template schema and constraints.
  • Tests

    • Added integration tests for template/rule behavior and updated numbering unit tests.
  • Chores

    • Updated ignore rules to exclude generated fixture .docx files.

Review Change Stack

Adds the schema and default seed for per-firm DOCX style templates so a
future PR (#32) can override font, size, indent, spacing, bold, and caps
per NodeType without touching generator code.

Migrations (node-pg-migrate, reversible):
- 010_style_templates: style_templates (UNIQUE name) + style_rules
  (UNIQUE template_id+node_type, FK CASCADE). OOXML-native units
  (half-points for font_size, twips for indent/spacing).
- 011_seed_default_style_rules: one row in style_templates
  ('UFGS-Default') and 7 rows in style_rules (part, article, pr1..pr5)
  extracted from docs/references/UFGS/DIVISION_27/27080001.docx. Source
  values + extraction methodology recorded as a comment table in the
  migration file.

Queries (src/db/queries/templates.ts):
- getTemplate(id), getTemplateByName(name), listTemplates(),
  createTemplate(name, owner?), upsertStyleRule(templateId, rule)
- All re-exported from src/db/index.ts (barrel).

Csi → Spec rename (in-scope cleanup):
- buildCsiNumberingConfig → buildSpecNumberingConfig
- CSI_NUM_REF → SPEC_NUM_REF
- 'csi-numbering' literal → 'spec-numbering'
- Generator output is functionally identical; reference string renamed
  for internal consistency. Verified: zero grep hits for old names.

Other:
- .gitignore: docs/references/UFGS/**/*.docx (fixture stays local;
  values that matter are encoded in 011's comment + INSERT statements).
- ARCHITECTURE.md: added style_templates + style_rules to schema overview.

Closes #30

Test plan:
- pnpm migrate / pnpm migrate:down round-trip both migrations cleanly
- pnpm test (462 unit tests pass)
- pnpm test:integration (117 pass, 65 pre-existing skips) — includes
  new templates.integration.test.ts covering seed, CRUD, upsert
  idempotence, FK cascade, UNIQUE name constraint
- pnpm lint clean
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 681d8bb9-d3f0-42a7-8524-4b353536d9ed

📥 Commits

Reviewing files that changed from the base of the PR and between 9b617e3 and 0170398.

📒 Files selected for processing (2)
  • ARCHITECTURE.md
  • src/db/index.ts

📝 Walkthrough

Walkthrough

Adds Phase 2c-i DB schema and seed for style templates/rules, a typed query API with re-exports and integration tests, updates ARCHITECTURE and .gitignore, and renames the DOCX numbering config to use spec-numbering.

Changes

Style Template Database & Query API

Layer / File(s) Summary
Database schema & docs
ARCHITECTURE.md, src/db/migrations/010_style_templates.ts, .gitignore
Adds style_templates and style_rules tables with UUID ids, FK cascade, composite unique constraint, index, and check constraints; documents schema in ARCHITECTURE; ignores extracted UFGS .docx fixtures.
Default Template Seed Migration
src/db/migrations/011_seed_default_style_rules.ts
Seeds UFGS-Default template and inserts 7 node-type style_rules rows from a typed seed matrix using helpers (cn, sqlLit, insertSql); down deletes seeded rows and template.
Query types & implementations
src/db/queries/templates.ts, src/db/index.ts
Adds StyleNodeType/STYLE_NODE_TYPES, StyleRule, TemplateMeta, Template types and implements loadRules, getTemplate, getTemplateByName, listTemplates, createTemplate, upsertStyleRule; re-exports added via src/db/index.ts.
Integration tests & cleanup
src/db/queries/templates.integration.test.ts
Integration tests validate seeded template structure, CRUD operations, upsert idempotency, FK cascade behavior, uniqueness constraint, and perform per-test cleanup via DB pool.

Generator Numbering Refactor

Layer / File(s) Summary
Numbering configuration rename
src/generator/numbering.ts, src/generator/index.ts, src/generator/numbering.test.ts
Renamed buildCsiNumberingConfig()buildSpecNumberingConfig(), changed numbering reference to 'spec-numbering', updated generator wiring and tests to assert the new reference and numbering levels.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

  • wrzonance/SpecR#26: Overlaps with DOCX numbering logic and the rename from CSI → Spec numbering.
  • wrzonance/SpecR#87: Contains the same style_templates/style_rules migrations, queries, seeds, and tests (code-level overlap).

Poem

🐰 I hopped through schemas, seeds, and docs today,
I planted rules where templates play,
I taught numbering to speak in spec,
Tests tidy paths where data trek,
New styles sprout — I nibble, hooray!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes out-of-scope changes: renaming buildCsiNumberingConfig to buildSpecNumberingConfig and updating numbering references ('csi-numbering' to 'spec-numbering'), which are unrelated to the style_templates schema and seed requirements from issue #30. Move the numbering refactoring changes (src/generator/numbering.ts, src/generator/numbering.test.ts, src/generator/index.ts) to a separate PR, keeping this PR focused on style_templates/style_rules schema and seed.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: implementing Phase 2c-i of the style templates feature with three core components (style_templates, style_rules, and default seed).
Linked Issues check ✅ Passed All primary coding deliverables from issue #30 are implemented: migrations for style_templates and style_rules [#30], seed migration with default template and seven rules [#30], query functions (getTemplate, getTemplateByName, listTemplates, createTemplate, upsertStyleRule) [#30], re-exports from src/db/index.ts [#30], and acceptance criteria met (migrations reversible, seed present, queries functional, integration tests added).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-30

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/db/queries/templates.integration.test.ts (1)

12-25: ⚡ Quick win

Avoid mutable shared state for created template tracking.

This uses in-place mutation (push, length = 0, splice) on module-level state. Prefer immutable reassignment (let + spread/filter) to keep tests deterministic and guideline-compliant.

As per coding guidelines: "Use immutable patterns: create new objects, never mutate. Use spread operators, not property assignment."

Also applies to: 159-160

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/db/queries/templates.integration.test.ts` around lines 12 - 25, Replace
the mutable module-level array usage for tracking created templates
(CREATED_TEMPLATE_NAMES, trackName, afterEach cleanup) with an immutable
pattern: change CREATED_TEMPLATE_NAMES to a let-bound collection and update
trackName to return a new collection reference instead of pushing (e.g.,
reassign CREATED_TEMPLATE_NAMES = [...CREATED_TEMPLATE_NAMES, name] inside
trackName or return the new array and assign the result), and in afterEach
perform cleanup by reassigning CREATED_TEMPLATE_NAMES to a filtered/new empty
array (e.g., CREATED_TEMPLATE_NAMES = CREATED_TEMPLATE_NAMES.filter(...) or =
[]) rather than using in-place mutation like push or length = 0; ensure tests
use the reassigned variable consistently so no in-place mutations remain.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/db/migrations/010_style_templates.ts`:
- Around line 19-21: Update the migration 010_style_templates.ts to enforce
DB-level constraints: add a CHECK on the node_type column (node_type)
restricting values to the allowed set
('part','article','pr1','pr2','pr3','pr4','pr5') and add CHECK constraints that
the OOXML numeric fields (the numeric style columns defined in this
migration—e.g., font_size / run_font_size, indent, spacing_before, spacing_after
or whichever numeric columns are declared in lines 23-30 and 33-35) are >= 0;
modify the CREATE TABLE / addColumns logic in this migration so the column
definitions include these CHECK constraints (and update the corresponding down
migration to drop these constraints if present).

In `@src/db/queries/templates.ts`:
- Around line 3-5: Tighten the type for node types by introducing a finite union
type (e.g. StyleNodeType) and replacing all occurrences of plain string with
that union: change the StyleRule.nodeType property from string to StyleNodeType,
update any other declarations that use nodeType (including the referenced usages
around the other occurrences and the upsertStyleRule function signature) to
accept StyleNodeType, and export/reuse the new StyleNodeType type so callers
must supply only the allowed node kinds.

---

Nitpick comments:
In `@src/db/queries/templates.integration.test.ts`:
- Around line 12-25: Replace the mutable module-level array usage for tracking
created templates (CREATED_TEMPLATE_NAMES, trackName, afterEach cleanup) with an
immutable pattern: change CREATED_TEMPLATE_NAMES to a let-bound collection and
update trackName to return a new collection reference instead of pushing (e.g.,
reassign CREATED_TEMPLATE_NAMES = [...CREATED_TEMPLATE_NAMES, name] inside
trackName or return the new array and assign the result), and in afterEach
perform cleanup by reassigning CREATED_TEMPLATE_NAMES to a filtered/new empty
array (e.g., CREATED_TEMPLATE_NAMES = CREATED_TEMPLATE_NAMES.filter(...) or =
[]) rather than using in-place mutation like push or length = 0; ensure tests
use the reassigned variable consistently so no in-place mutations remain.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 23a84883-3a10-415e-94d0-d9230f78015f

📥 Commits

Reviewing files that changed from the base of the PR and between 150fbbd and c94f5c4.

📒 Files selected for processing (10)
  • .gitignore
  • ARCHITECTURE.md
  • src/db/index.ts
  • src/db/migrations/010_style_templates.ts
  • src/db/migrations/011_seed_default_style_rules.ts
  • src/db/queries/templates.integration.test.ts
  • src/db/queries/templates.ts
  • src/generator/index.ts
  • src/generator/numbering.test.ts
  • src/generator/numbering.ts

Comment thread src/db/migrations/010_style_templates.ts
Comment thread src/db/queries/templates.ts
…e_rules

Tightens both the TypeScript and SQL boundaries for style_rules.node_type
so invalid kinds can't enter the table from either the query layer or a
direct INSERT.

- Introduce StyleNodeType union ('part' | 'article' | 'pr1'..'pr5') in
  src/db/queries/templates.ts; export it (and STYLE_NODE_TYPES) from
  src/db/index.ts. StyleRule.nodeType and StyleRuleRow.node_type now use
  this union — upsertStyleRule callers get compile-time rejection of
  invalid kinds.
- Migration 011 mirrors the union as a local SeedNodeType so the seed
  data is statically verified against the same domain.
- Migration 010 adds two CHECK constraints on style_rules:
    * node_type ∈ ('part','article','pr1'..'pr5')
    * font_size_half_pt / indent_twips / space_before_twips /
      space_after_twips are NULL or >= 0 (OOXML units are unsigned)
  The down migration drops the table, so the constraints come along.
- Integration test ruleFor() helper now takes StyleNodeType instead of
  string so test fixtures stay aligned with the production type.

Addresses CodeRabbit review on #87.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/db/migrations/010_style_templates.ts`:
- Line 6: The migration defines the style_templates table with name: { type:
'text', notNull: true, unique: true } but does not prevent empty strings; update
the table creation in 010_style_templates.ts (the CREATE TABLE / up migration
where style_templates is defined) to add a check constraint preventing empty
names — e.g. add a constraint that name <> '' or char_length(name) > 0 (or
equivalent check expression supported by your SQL/ORM) so the name column
remains not-null, unique, and non-empty.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5fd8582c-8b1d-4aa4-bb3b-cf9b681666f5

📥 Commits

Reviewing files that changed from the base of the PR and between c94f5c4 and 4f569b2.

📒 Files selected for processing (5)
  • src/db/index.ts
  • src/db/migrations/010_style_templates.ts
  • src/db/migrations/011_seed_default_style_rules.ts
  • src/db/queries/templates.integration.test.ts
  • src/db/queries/templates.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/db/index.ts
  • src/db/migrations/011_seed_default_style_rules.ts
  • src/db/queries/templates.integration.test.ts
  • src/db/queries/templates.ts

Comment thread src/db/migrations/010_style_templates.ts
thewrz added 2 commits May 18, 2026 22:04
Adds a CHECK constraint `style_templates_name_non_empty_check` on
`style_templates.name` enforcing `length(trim(name)) > 0`. Without it,
the column accepted '' and '   ', either of which would silently break
`getTemplateByName()` lookups and leave orphaned style_rules behind.

Verified locally: INSERTs with '' and '   ' now fail with the named
constraint; a 'valid' name still inserts. Down migration drops the
table, so the constraint comes along.

Addresses CodeRabbit minor on #87 (latest re-review).
@thewrz thewrz merged commit d2ebea8 into main May 19, 2026
4 of 5 checks passed
@thewrz thewrz deleted the feat/issue-30 branch May 19, 2026 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(db): Phase 2c-i — style_templates + style_rules migrations + default CSI seed

1 participant