hor-sequelize-model · git:20260905.5a04969 · 2026-09-05 · sha256 55ed4a2c7334f75e
hor-sequelize-model git:20260905.5a04969A
Immutable. This exact content never changes and is served at /api/v1/blob/55ed4a2c7334f75e.
---
name: hor-sequelize-model
description: >
Write and edit renchan/Sequelize model definitions (sequelize/models/*.js).
Use this skill whenever the user asks to create or update a Sequelize model
class — its attributes, createOptions, associations, scopes, hooks, or how to
wire a MixinModel.
---
# Sequelize Model
A skill for writing the `sequelize/models/*.js` model definitions used in a renchan project.
The physical schema is defined by `hor-sequelize-migration`; this
skill writes the corresponding **logical declarations on top of Sequelize** (attributes /
association / scope / hook / Mixin). The conventions are split across the detail files below —
consult them as needed.
## Grand principle: a model is a filled-in template, not free-form code
Every model extends `BaseAppRenchanModel` and has the **same skeleton**. The six extension
points that form that skeleton (`createAttributes` / `createOptions` / `associate` /
`defineScopes` / `defineSubqueries` / `setupHooks`) are **always laid out in the same order,
even when unused**, and any that have no content keep `super.xxx?.()` plus `// noop`
([default-methods.md](./references/default-methods.md)).
- **Do not "delete to omit"**. Removing a method entirely makes it impossible to tell whether
the model "has no such feature (i.e. it was considered)" or someone "forgot to write it".
Keeping an explicit noop declares "considered, and not applicable". This is the same idea as
the QA stance in `hoc-jest` ("do not cut coverage using implementation
knowledge") — to avoid mistaking *a gap* for *not-applicable*, always keep the extension
points visible.
- Because the skeleton is identical across every model, review attention goes straight to the
**model-specific differences** (attributes / associations). When the structure varies from
model to model, it becomes impossible to read what is intentional and what is an omission.
- When in doubt, **lean toward the template**. Do not try to write it "cleverly" with custom
static methods or a changed initialization order. Extend via a Mixin
([mixins.md](./references/mixins.md)) or a framework extension point.
## Write code comments in English
Comments inside model code (`.js`) — such as `// ForeignKey must start with upper case.` — are
written in **English**, to match the other comments in the codebase.
- This applies to comments inside the model code generated into `sequelize/models/` (the `//`
and `/* */` in `.js`). They are artifacts, so English.
- The explanatory prose of this skill (the body text of each Markdown file) is in English as
well.
- The comments inside **this skill's own examples** (```js``` blocks) are also in English.
## Keep a one-to-one correspondence with the migration
A model's attributes must correspond one-to-one with the columns of the matching
`hor-sequelize-migration`. The camelCase attribute keys on the model side map
to the snake_case physical columns (`field:`) on the migration side via `underscored: true`
([default-methods.md](./references/default-methods.md#createoptions-spreads-supercreateoptions-and-adds-only-extras)).
- **Why**: adding only one side produces an inconsistency — an attribute exists but the column
does not (queries fail), or a column exists but the model cannot touch it. Always add or change
columns in the migration and the model together.
- Timestamp columns are the exception; **do not** write them in the model's attributes
([timestamps.md](./references/timestamps.md)).
## Detail files
- [notation.md](./references/notation.md) — class skeleton, imports, attribute declarations
- [default-methods.md](./references/default-methods.md) — the six override methods and `createOptions`
- [timestamps.md](./references/timestamps.md) — do not include `created_at` / `updated_at` in the model
- [associations.md](./references/associations.md) — how to write `associate()` (relations via `this._`)
- [mixins.md](./references/mixins.md) — kinds of MixinModel and how to pass them (all 6)