Skip to content

Commit 99013ac

Browse files
B4nanclaude
andcommitted
feat: align code with the getting started guide
- Update all entity imports to use @mikro-orm/core - Remove Article/Comment classes, use InferEntity types (IArticle, IComment, ITag) - Replace BaseEntity class with BaseSchema (abstract schema only) - Convert ArticleListing from view entity to virtual entity with expression callback - Use synchronous new MikroORM() instead of async MikroORM.init() - Add beforeUpdate hook and remove ref() from User.password - Add description onCreate callback to Article - Add SeedManager extension, remove SqlHighlighter - Add CI workflow for tests and type checking - Add CLAUDE.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2655de4 commit 99013ac

24 files changed

Lines changed: 309 additions & 863 deletions

.github/workflows/ci.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [master, v7]
6+
pull_request:
7+
8+
jobs:
9+
build:
10+
runs-on: ubuntu-latest
11+
strategy:
12+
matrix:
13+
node-version: [20, 22, 24]
14+
steps:
15+
- uses: actions/checkout@v4
16+
- uses: actions/setup-node@v4
17+
with:
18+
node-version: ${{ matrix.node-version }}
19+
cache: npm
20+
- run: npm ci
21+
- run: npx tsc --noEmit
22+
- run: npm test

CLAUDE.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
MikroORM Getting Started guide — a blog API built with Fastify, MikroORM v7 (SQLite driver), and TypeScript. ESM-only (`"type": "module"` in package.json).
8+
9+
## Commands
10+
11+
- **Build:** `npm run build` (runs `tsc`)
12+
- **Bundle:** `npm run bundle` (Vite SSR build → `dist/`)
13+
- **Dev server:** `npm run start` (runs `tsx src/server.ts` on port 3001)
14+
- **Run all tests:** `npm test` (runs `vitest`)
15+
- **Run a single test:** `npx vitest run test/user.test.ts`
16+
- **MikroORM CLI:** `npx mikro-orm` (config at `src/mikro-orm.config.ts`)
17+
- **Create migration:** `npx mikro-orm migration:create`
18+
19+
## Architecture
20+
21+
### Entity Definition Pattern (v7 `defineEntity` API)
22+
23+
Entities use MikroORM v7's `defineEntity()` + `p.*` property builder pattern, **not** decorators:
24+
25+
```ts
26+
export const ArticleSchema = defineEntity({
27+
name: 'Article',
28+
extends: BaseSchema,
29+
properties: {
30+
title: p.string().index(),
31+
author: () => p.manyToOne(UserSchema).ref(), // arrow function for circular refs
32+
},
33+
});
34+
export type IArticle = InferEntity<typeof ArticleSchema>;
35+
```
36+
37+
Key conventions:
38+
- Schema objects are exported (e.g., `ArticleSchema`) and registered in `mikro-orm.config.ts`
39+
- Types are inferred with `InferEntity<typeof Schema>` (e.g., `IArticle`, `ITag`, `IComment`)
40+
- Only `User` has a custom class (via `setClass`) for `verifyPassword()` method
41+
- `BaseSchema` (in `src/modules/common/base.entity.ts`) provides `id`, `createdAt`, `updatedAt`
42+
- Relations use arrow-function property definitions to handle circular imports
43+
- Entity imports use `@mikro-orm/core`; driver-specific imports (`@mikro-orm/sqlite`) are used only in `db.ts` and custom repositories
44+
45+
### Module Structure
46+
47+
Code is organized in `src/modules/{module}/`:
48+
- **user/**`User` entity (with custom class), `UserRepository`, routes (sign-up, sign-in, profile)
49+
- **article/**`Article`, `Comment`, `Tag` schemas + `ArticleListing` virtual entity, `ArticleRepository`, routes
50+
- **common/**`BaseSchema`, `AuthError`, helper functions, `SoftDeleteSubscriber`
51+
52+
### ORM Service Layer (`src/db.ts`)
53+
54+
`initORM()` synchronously initializes MikroORM (via `new MikroORM()`) and returns a cached `Services` object with typed repository accessors (`db.user`, `db.article`, `db.comment`, `db.tag`). Both app code and tests call this — tests pass overrides (`:memory:` DB, debug off).
55+
56+
### App Bootstrap (`src/app.ts`)
57+
58+
`bootstrap()` creates the Fastify app with:
59+
1. JWT plugin for auth
60+
2. `RequestContext` hook (per-request MikroORM identity map)
61+
3. Auth hook (decodes JWT, loads `request.user`)
62+
4. Error handler mapping `NotFoundError` → 404, `AuthError` → 401
63+
5. Route registration with `/user` and `/article` prefixes
64+
65+
### Testing
66+
67+
Tests use in-memory SQLite (`:memory:`) with schema created fresh + `TestSeeder` for fixtures. Each test file uses a different port for parallel execution. Tests use Fastify's `app.inject()` for HTTP assertions without a real server.
68+
69+
### Notable Patterns
70+
71+
- **Soft delete:** `SoftDeleteSubscriber` intercepts DELETE change sets and converts them to UPDATE with `deletedAt` timestamp. `Comment` entity has a `softDelete` filter enabled by default.
72+
- **Virtual entity:** `ArticleListing` uses an expression callback (returns QueryBuilder) instead of a database table.
73+
- **Lazy properties:** `User.password` and `Article.text` are lazy-loaded (not fetched unless explicitly populated).
74+
- **Ref wrapper:** Foreign keys use `.ref()` for type-safe references without loading the full entity.
75+
- **Zod validation:** Route handlers use Zod schemas for request body validation.

0 commit comments

Comments
 (0)