| name | new-model |
| description | Scaffold a new Mongoose model and its CRUD service for the WealthWise API. Triggers when asked to "create a model", "add a Mongoose schema", or add the data layer for a new entity without a full endpoint. Does NOT scaffold routes, controllers, or frontend code. Use $api-endpoint for the full stack.
|
Scaffold a new Mongoose model with its full CRUD service.
The entity name is provided in the task prompt.
Files to create
Model — apps/api/src/models/<entity>.model.ts
import { Schema, model, Document, Types } from 'mongoose';
export interface I<Entity> extends Document {
userId: Types.ObjectId;
createdAt: Date;
updatedAt: Date;
}
const <entity>Schema = new Schema<I<Entity>>(
{
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true,
index: true,
},
},
{
timestamps: true,
toJSON: { virtuals: true },
toObject: { virtuals: true },
}
);
<entity>Schema.index({ userId: 1, createdAt: -1 });
export const <Entity>Model = model<I<Entity>>('<Entity>', <entity>Schema);
Service — apps/api/src/services/<entity>.service.ts
Five methods, fully typed:
-
get<Entity>s(userId: string): Promise<I<Entity>[]>
- Filter:
{ userId: new Types.ObjectId(userId) }
-
get<Entity>ById(id: string, userId: string): Promise<I<Entity>>
- Throw
ApiError.notFound('<Entity> not found') if not found — never return null
-
create<Entity>(userId: string, data: Create<Entity>Input): Promise<I<Entity>>
- Attach
userId to the document before saving
-
update<Entity>(id: string, userId: string, data: Update<Entity>Input): Promise<I<Entity>>
- Filter by both
_id and userId — throw ApiError.notFound if missing
- Use
{ new: true } in findOneAndUpdate
-
delete<Entity>(id: string, userId: string): Promise<void>
- Filter by both
_id and userId — throw ApiError.notFound if missing
Rules
- Import
ApiError from utils/api-error.ts — never throw new Error(...)
- Every query includes
userId as a filter — no cross-user access
- Use
new Types.ObjectId(userId) when building ObjectId filters
- Never expose raw Mongoose errors — catch and rethrow as
ApiError.internal(...)
- Named exports only. No
any.
Verification
npx turbo lint --filter=@wealthwise/api
List all created file paths and the five service method signatures.