Agent skill
create-model
Create Objection.js model files with proper structure in the Commons monorepo. Use when the user wants to create a new model, add a database entity, or needs a model class for a table.
Install this agent skill to your Project
npx add-skill https://github.com/jakewaldrip/.dotfiles/tree/main/misc/commons/.opencode/skills/create-model
SKILL.md
Create Database Model
Create Objection.js model files following Commons patterns.
Prerequisites
- Table must exist (or have a migration created)
- Table must have
id,createdAt, andupdatedAtcolumns (required by BaseModel)
Base Class Selection
| Use Case | Base Class |
|---|---|
| Standard model | BaseModel |
| Patient-related with enrollment scoping | PatientEnrollmentRelatedModel |
| Has Draft.js content | MarkdownModel |
| Needs Zod validation | ZodValidatedModel mixin with Mixin() |
Standard Model Template
import type { JSONSchema, Transaction } from 'objection';
import BaseModel from '@commons/backend/models/base-model';
export default class ModelName extends BaseModel {
// Fields with ! (non-null assertion)
fieldName!: string;
optionalField!: string | null;
deletedAt!: string | null;
deletedById!: string | null;
// These audit columns are only included if applicable. They are not compulsory
createdById!: string | null;
updatedById!: string | null;
static tableName = 'table_name';
// We do NOT include a jsonSchema, it is a deprecated pattern
static async getById(id: string, txn?: Transaction) {
return ModelName.query(txn).findById(id).whereNull('deletedAt');
}
static async getAll(txn?: Transaction): Promise<ModelName[]> {
return ModelName.query(txn).whereNull('deletedAt');
}
static async create(input: CreateInput, userId: string, txn?: Transaction): Promise<ModelName> {
return ModelName.query(txn).insertAndFetch({
...input,
createdById: userId,
updatedById: userId,
});
}
static async update(id: string, input: UpdateInput, userId: string, txn?: Transaction): Promise<ModelName> {
return ModelName.query(txn).patchAndFetchById(id, {
...input,
updatedById: userId,
});
}
static async softDelete(id: string, userId: string, txn?: Transaction): Promise<ModelName> {
return ModelName.query(txn).patchAndFetchById(id, {
deletedAt: new Date().toISOString(),
deletedById: userId,
});
}
}
Zod Validated Model Template
import { Mixin } from 'ts-mixer';
import { z } from 'zod';
import BaseModel from '@commons/backend/models/base-model';
import ZodValidatedModel, { DateInStringsClothing } from '@commons/backend/models/mixins/zod-validated-model';
const ModelNameColumns = z.object({
id: z.string(),
fieldName: z.string(),
optionalField: z.string().nullable(),
deletedAt: z.string().nullable(),
deletedById: z.string().nullable(),
createdAt: DateInStringsClothing,
updatedAt: DateInStringsClothing,
});
export default class ModelName extends Mixin(ZodValidatedModel(ModelNameColumns), BaseModel) {
// No additional fields are listed on Zod validated models
// because they do not interact well with the validator
static tableName = 'table_name';
// Static query methods...
}
Rules
- Use
!for field declarations (non-null assertion) - Always include soft-delete filter in query methods if table has
deletedAt - Include transaction parameter in all static methods:
txn?: Transaction - Include audit tracking in create/update if table has audit columns
- Do NOT add relationMappings — query related data explicitly using data loaders, joins or separate queries
- Use
DateInStringsClothingfor createdAt/updatedAt in Zod schemas
File Location
commons-packages/backend/models/{kebab-case-name}.ts
Example: LabelDefinition → label-definition.ts
Related models (2+ files): Organize into subdirectory with barrel export and README.
Import Path
import ModelName from '@commons/backend/models/model-name';
Reference
- BaseModel:
commons-packages/backend/models/base-model.ts - ZodValidatedModel:
commons-packages/backend/models/mixins/zod-validated-model.ts - EnrollmentModel:
commons-packages/backend/models/patient-enrollment/patient-enrollment-related.ts - See WORKFLOW.md for step-by-step guidance
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
react-component-writing
React component patterns and style guide for the Commons monorepo. Use when creating React components, working with GraphQL in components, or implementing internationalization with MessageFormat.
graphite-cli
Use Graphite CLI (gt) for stacked PRs and branch management. Use when creating branches, committing changes, submitting PRs, syncing with trunk, or managing stacked pull requests.
test-running
Run Jest tests in the Commons monorepo. Use when testing code changes, validating implementations, debugging test failures, or when the user mentions running tests.
document-type-adding
Add new document types to the DocuSign integration in the Commons monorepo. Use when the user wants to add a patient document, consent form, or agreement to the DocuSign workflow.
dataloader-dual-mode-migration
Migrate dataloaders to dual-mode pattern supporting both patientId and enrollmentId for Member Model 2.0. Use when converting a patient-based dataloader to support the MemberModelV2Switch.
feature-flag-create-or-remove
Create or remove feature flags in the Commons application. Use when the user wants to add a new feature flag, delete a feature flag, or asks about feature flag naming conventions.
Didn't find tool you were looking for?