jcc-express-mvc 1.9.7 → 1.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/final-documentation/Architecture Concept/Request-Lifecycle.md +4 -4
  2. package/final-documentation/Architecture Concept/Service-Container.md +4 -4
  3. package/final-documentation/Architecture Concept/Service-Provider.md +11 -7
  4. package/final-documentation/Database/Database-Introduction.md +7 -1
  5. package/final-documentation/Database/Migrations.md +1 -6
  6. package/final-documentation/Database/Prisma.md +11 -8
  7. package/final-documentation/Database/Query-Builder.md +1 -1
  8. package/final-documentation/Database/Seeding.md +1 -1
  9. package/final-documentation/Database/Sequelize.md +216 -41
  10. package/final-documentation/Database/Transactions.md +1 -1
  11. package/final-documentation/Database/TypeORM.md +114 -22
  12. package/final-documentation/Digging Deeper/Broadcasting.md +6 -9
  13. package/final-documentation/Digging Deeper/Cache.md +2 -2
  14. package/final-documentation/Digging Deeper/Carbon.md +3 -3
  15. package/final-documentation/Digging Deeper/Deferred-Functions.md +1 -14
  16. package/final-documentation/Digging Deeper/Events.md +1 -1
  17. package/final-documentation/Digging Deeper/File-Storage.md +4 -4
  18. package/final-documentation/Digging Deeper/HTTP-Client.md +1 -6
  19. package/final-documentation/Digging Deeper/Helpers.md +5 -6
  20. package/final-documentation/Digging Deeper/Logging.md +3 -4
  21. package/final-documentation/Digging Deeper/Mail.md +4 -4
  22. package/final-documentation/Digging Deeper/Monitor.md +6 -26
  23. package/final-documentation/Digging Deeper/Queues.md +9 -9
  24. package/final-documentation/Digging Deeper/Rate-Limiting.md +1 -1
  25. package/final-documentation/Digging Deeper/Strings.md +2 -4
  26. package/final-documentation/Getting-Started/Configuration.md +12 -9
  27. package/final-documentation/Getting-Started/Deployment.md +3 -3
  28. package/final-documentation/Getting-Started/Directory-structure.md +9 -9
  29. package/final-documentation/Getting-Started/Frontend.md +7 -7
  30. package/final-documentation/Getting-Started/Installation.md +10 -8
  31. package/final-documentation/JCC-Eloquent/Defining-Model.md +84 -11
  32. package/final-documentation/JCC-Eloquent/JCC-Eloquent-Introduction.md +1 -1
  33. package/final-documentation/JCC-Eloquent/Observer.md +276 -6
  34. package/final-documentation/JCC-Eloquent/Query-Builder.md +1 -1
  35. package/final-documentation/Packages/Cloudinary.md +1 -1
  36. package/final-documentation/Packages/JWT.md +2 -2
  37. package/final-documentation/Security/Authentication.md +4 -4
  38. package/final-documentation/Security/Authorization.md +3 -3
  39. package/final-documentation/Security/Email-Verification.md +2 -2
  40. package/final-documentation/Security/Encryption.md +1 -1
  41. package/final-documentation/Security/Hashing.md +1 -1
  42. package/final-documentation/Testing/Introduction.md +2 -2
  43. package/final-documentation/Testing/Testing-Overview.md +8 -8
  44. package/final-documentation/Testing/Unit-Testing.md +3 -36
  45. package/final-documentation/The Basics/API-Resources.md +7 -11
  46. package/final-documentation/The Basics/Artisan-Node.md +7 -1
  47. package/final-documentation/The Basics/Asset-bundling.md +1 -1
  48. package/final-documentation/The Basics/CSRF-protection.md +1 -1
  49. package/final-documentation/The Basics/Controllers.md +7 -7
  50. package/final-documentation/The Basics/Error-handling.md +28 -32
  51. package/final-documentation/The Basics/JCC-Blade.md +2 -2
  52. package/final-documentation/The Basics/Middleware.md +2 -2
  53. package/final-documentation/The Basics/Request.md +6 -5
  54. package/final-documentation/The Basics/Response.md +2 -2
  55. package/final-documentation/The Basics/Routing.md +7 -6
  56. package/final-documentation/The Basics/Session.md +8 -8
  57. package/final-documentation/The Basics/Validation.md +12 -14
  58. package/final-documentation/The Basics/Views.md +9 -14
  59. package/global.d.ts +1 -1
  60. package/lib/Jcc-eloquent/lib/Event/Event.d.ts +1 -0
  61. package/lib/Jcc-eloquent/lib/Event/Event.d.ts.map +1 -1
  62. package/lib/Jcc-eloquent/lib/Event/Event.js +21 -10
  63. package/lib/Jcc-eloquent/lib/Event/ModelEvent.d.ts +3 -3
  64. package/lib/Jcc-eloquent/lib/Event/ModelEvent.d.ts.map +1 -1
  65. package/lib/Jcc-eloquent/lib/Event/ModelEvent.js +23 -22
  66. package/lib/Jcc-eloquent/lib/Model.d.ts +1 -1
  67. package/lib/Jcc-eloquent/lib/Model.d.ts.map +1 -1
  68. package/lib/Jcc-eloquent/lib/Model.js +6 -3
  69. package/package.json +1 -1
@@ -59,7 +59,7 @@ Think of the stack as: framework defaults → your kernel `middlewares` (for exa
59
59
 
60
60
  One of the most important bootstrap steps is loading service providers. Providers register bindings on the container (`register`) and run extra setup once registrations exist (`boot`).
61
61
 
62
- In `ApplicationBuilder.withProviders()`, the framework prepends `DatabaseServiceProvider`, registers your list from `bootstrap/providers.ts` (and may place `AuthServiceProvider` early), then appends `QueueServiceProvider`. That order matters so the database, auth, and queue subsystems are available where other code expects them.
62
+ During application bootstrap, the framework prepends `DatabaseServiceProvider`, registers your list from `bootstrap/providers.ts` (and may place `AuthServiceProvider` early), then appends `QueueServiceProvider`. That order matters so the database, auth, and queue subsystems are available where other code expects them.
63
63
 
64
64
  Your own providers live under `app/Providers/` (for example `AppServiceProvider`) and are listed in `bootstrap/providers.ts`. Use `AppServiceProvider` (or additional providers) for container bindings, config-driven setup, and small bootstrap tasks—same idea as Laravel’s `AppServiceProvider`.
65
65
 
@@ -92,7 +92,7 @@ If the request fails a guard (for example user not authenticated), middleware ca
92
92
 
93
93
  If the request passes all matched middleware, your route or controller runs and produces the response (JSON, Blade, Inertia, redirect, …).
94
94
 
95
- Reference — framework middleware order (before kernel entries), from `jcc-express-mvc/lib/Middleware`:
95
+ Reference — default framework middleware order (before kernel entries):
96
96
 
97
97
  1. `express.json()`
98
98
  2. `express.urlencoded({ extended: false })`
@@ -117,7 +117,7 @@ When your controller or closure finishes—by calling `res.send`, `res.json`, `r
117
117
 
118
118
  The framework listens for `finish` on the response and clears the per-request `request` / `response` / `next` bindings on the container so the next request does not leak state.
119
119
 
120
- If an error is passed to `next(error)` or thrown without being caught, `AppErrorHandler` maps it to an HTTP response (status and body) according to framework rules.
120
+ If an error is passed to `next(error)` or thrown without being caught, the framework error handler maps it to an HTTP response (status and body). See [Error handling](../The%20Basics/Error-handling.md).
121
121
 
122
122
  ---
123
123
 
@@ -132,6 +132,6 @@ Your `bootstrap/providers.ts` list is the counterpart to Laravel’s provider li
132
132
  ## Where to customize (quick reference)
133
133
 
134
134
  - Global HTTP middleware — `app/Http/kernel.ts` → `middlewares` and `middlewareAliases`.
135
- - Default Express stack — `jcc-express-mvc/lib/Middleware` + `app/Config` (CORS, rate limit, engine).
135
+ - Default Express stack — framework global middleware + `app/Config` (CORS, rate limit, engine).
136
136
  - Routes and API prefixes — `route/*.ts` and `bootstrap/app.ts` → `withRouting`.
137
137
  - Container bindings and boot logic — `app/Providers/*` and `bootstrap/providers.ts`.
@@ -84,15 +84,15 @@ If resolution fails, you may need an explicit `bind` for that type or pass param
84
84
 
85
85
  ---
86
86
 
87
- ## Controllers and `callControllerMethod`
87
+ ## Controllers and method injection
88
88
 
89
- For controller actions, the framework can `callControllerMethod`, which reads `inject:method:deps` metadata and resolves FormRequest, models, route parameters, etc. Plain routes that use `(req, res) =>` do not need this—you still benefit from `view()` / `inertia()` because they read `response` from the container after it is bound.
89
+ For controller actions, the framework resolves method parameters from container metadata: FormRequest classes, models, route parameters, and services. Plain routes that use `(req, res) =>` do not need this—you still benefit from `view()` / `inertia()` because they read `response` from the container after it is bound.
90
90
 
91
91
  ---
92
92
 
93
93
  ## Global `app` and helpers
94
94
 
95
- After `globalHelpers(app)` runs (during `ApplicationBuilder.create()`), `globalThis.app` is the Application instance. Helpers like `env()`, `view()`, `inertia()` use the container under the hood (for example `response` from `app.resolve("response")`).
95
+ After the application boots, `globalThis.app` is the Application instance. Helpers like `env()`, `view()`, and `inertia()` use the container under the hood (for example `response` from `app.resolve("response")`).
96
96
 
97
97
  Prefer constructor injection or explicit `app.resolve()` in providers and long-lived services; use globals where the framework already does (routes, Blade/Inertia helpers).
98
98
 
@@ -100,7 +100,7 @@ Prefer constructor injection or explicit `app.resolve()` in providers and long-l
100
100
 
101
101
  ## Comparison to Laravel (mental model)
102
102
 
103
- - Container class — Laravel: `Illuminate\Container\Container`. JCC: `jcc-express-mvc/lib/Container`.
103
+ - Container — Laravel: `Illuminate\Container\Container`. JCC: the framework service container (resolved via `app.resolve()` / `app.make()`).
104
104
  - Application — Laravel’s `Application` extends the container. JCC: `Application` → `ExpressApplication` → `Container`.
105
105
  - Registering services — Laravel: `AppServiceProvider::register`. JCC: same idea in `app/Providers/*` → `register()`.
106
106
  - Resolving — Laravel: `app()`, `resolve()`. JCC: `app.resolve()`, `app.make()`.
@@ -15,7 +15,7 @@ A provider connects the framework to your app:
15
15
  - Register container bindings (`bind`, `singleton`, `instance`) so other code can `resolve` them.
16
16
  - Boot behavior that depends on those bindings (routes are not registered here—`RouteServiceProvider` loads route files during `app.run()`, but your `boot()` can use `Gate`, events, or other services already on the container).
17
17
 
18
- The abstract base class lives in `jcc-express-mvc` (`ServiceProvider`). Extend it from `jcc-express-mvc/Core/Provider` (re-export) or the underlying `lib/Providers/ServiceProvider`.
18
+ The abstract base class is **`ServiceProvider`**. Extend it from `jcc-express-mvc/Core/Provider`.
19
19
 
20
20
  ---
21
21
 
@@ -28,14 +28,17 @@ The abstract base class lives in `jcc-express-mvc` (`ServiceProvider`). Extend i
28
28
 
29
29
  ---
30
30
 
31
- ## Registration order (`ApplicationBuilder`)
31
+ ## Registration order (bootstrap)
32
32
 
33
- In `withProviders()`, the builder does not use your array alone. It builds this chain:
33
+ During `withProviders()`, the application builder does not use your array alone. It builds this chain:
34
34
 
35
- 1. `DatabaseServiceProvider` — Knex / Sequelize / Mongoose setup (skipped when `DB_ORM=prisma`).
36
- 2. `PrismaServiceProvider` — Prisma client singleton and graceful `$disconnect`.
37
- 2. Your providers from `bootstrap/providers.ts` — If `AuthServiceProvider` (framework) is in the list but not first, the builder moves it to the front of your list so auth is set up early.
38
- 3. `QueueServiceProvider` — Always last in the chain.
35
+ 1. `LogServiceProvider`
36
+ 2. `DatabaseServiceProvider` — Knex / Sequelize / Mongoose setup (skipped when `DB_ORM=prisma` or `DB_ORM=typeorm`).
37
+ 3. `PrismaServiceProvider` — Prisma client singleton and graceful `$disconnect` (when configured).
38
+ 4. `TypeORMServiceProvider` — TypeORM `DataSource` singleton and graceful shutdown (when configured).
39
+ 5. `SessionServiceProvider`, `CacheServiceProvider`
40
+ 6. Your providers from `bootstrap/providers.ts` — If `AuthServiceProvider` (framework) is in the list but not first, the builder moves it to the front of your list so auth is set up early.
41
+ 7. `QueueServiceProvider` — Always last in the chain.
39
42
 
40
43
  That order matters when one provider’s `register()` assumes another binding already exists.
41
44
 
@@ -100,6 +103,7 @@ export const providers = [AppServiceProvider];
100
103
 
101
104
  - `DatabaseServiceProvider` — Database / ORM wiring; runs before your list.
102
105
  - `PrismaServiceProvider` — Registers `database.prisma.service` when configured.
106
+ - `TypeORMServiceProvider` — Registers `database.typeorm.dataSource` when configured.
103
107
  - `AuthServiceProvider` (when included) — Intended to run early among your providers.
104
108
  - `QueueServiceProvider` — Queue binding; runs after your list.
105
109
  - `RouteServiceProvider` — Not in your `bootstrap/providers.ts` list by default; it is registered as a singleton on `Application` and `loadRoutes()` is invoked from `app.run()` to load `route/web`, `route/api`, etc.
@@ -8,6 +8,7 @@ Almost every real application needs a database. JCC Express MVC keeps this flexi
8
8
  - **Sequelize** as an alternative SQL ORM
9
9
  - **Mongoose** for MongoDB document workflows
10
10
  - **Prisma** for schema-first SQL with generated client and migrations
11
+ - **TypeORM** for decorator-based entities and `DataSource` repositories
11
12
 
12
13
  In practice, most projects start with the default JCC stack, then switch ORM mode only when needed.
13
14
 
@@ -26,6 +27,8 @@ For document databases, use `DB_ORM=mongoose` with your Mongo connection setting
26
27
 
27
28
  For Prisma, use `DB_ORM=prisma` and configure `DATABASE_URL` plus `database.prisma.service` — see [Prisma](./Prisma.md).
28
29
 
30
+ For TypeORM, use `DB_ORM=typeorm` and configure `database.typeorm.dataSource` — see [TypeORM](./TypeORM.md).
31
+
29
32
  ---
30
33
 
31
34
  ## Configuration
@@ -42,12 +45,13 @@ Minimal shape from `app/Config/database.ts`:
42
45
  export const database = {
43
46
  orm: config.get("DB_ORM", "jcc"),
44
47
  prisma: { service: PrismaService },
48
+ typeorm: { dataSource: TypeORMDataSource },
45
49
  sequelize: { /* ... */ },
46
50
  mongoose: { /* ... */ },
47
51
  };
48
52
  ```
49
53
 
50
- See [Prisma](./Prisma.md) for the full Prisma setup.
54
+ See [Prisma](./Prisma.md) and [TypeORM](./TypeORM.md) for full setup.
51
55
 
52
56
  ---
53
57
 
@@ -74,6 +78,8 @@ The provider layer uses your env/config to decide connection behavior:
74
78
  - `DB_ORM=jcc` -> JCC/Knex SQL flow
75
79
  - `DB_ORM=sequelize` -> Sequelize connection path
76
80
  - `DB_ORM=mongoose` -> Mongoose connection path
81
+ - `DB_ORM=prisma` -> Prisma client path (see [Prisma](./Prisma.md))
82
+ - `DB_ORM=typeorm` -> TypeORM DataSource path (see [TypeORM](./TypeORM.md))
77
83
 
78
84
  Keep `DB_ORM` and `DB_CONNECTION` consistent (for example, do not pair `DB_ORM=mongoose` with SQL-only assumptions in your app code).
79
85
 
@@ -135,12 +135,7 @@ Common schema helpers seen in the current codebase:
135
135
 
136
136
  ---
137
137
 
138
- ## Full migration API (current source)
139
-
140
- This list is taken from the current implementation in:
141
-
142
- - `jcc-express-mvc/lib/Jcc-eloquent/lib/Schema/index.ts`
143
- - `jcc-express-mvc/lib/Jcc-eloquent/lib/Schema/BluePrint/index.ts`
138
+ ## Full migration API
144
139
 
145
140
  ### `Schema` methods
146
141
 
@@ -129,8 +129,8 @@ The framework only injects an adapter when you set `database.prisma.adapter` or
129
129
 
130
130
  ```typescript
131
131
  import { PrismaClient } from "generated/prisma/client";
132
- import { createMariaDbAdapter } from "@framework/lib/Database/Drivers/Prisma/adapters/mariadb";
133
- import type { PrismaClientOptions } from "@framework/lib/Database/Drivers/Prisma/types";
132
+ import { createMariaDbAdapter } from "jcc-express-mvc/lib/Database/Drivers/Prisma/adapters/mariadb";
133
+ import type { PrismaClientOptions } from "jcc-express-mvc/lib/Database/Drivers/Prisma/types";
134
134
 
135
135
  export class PrismaService extends PrismaClient {
136
136
  constructor(options?: PrismaClientOptions) {
@@ -160,7 +160,8 @@ PRISMA_ADAPTER=postgres
160
160
  **3. `database.prisma.adapter` in app config:**
161
161
 
162
162
  ```typescript
163
- import { createPostgresAdapter } from "jcc-express-mvc/lib/Database/Drivers/Prisma/adapters/postgres";
163
+ import { createPostgresAdapter } from "jcc-express-mvc/lib/Database/Drivers/Prisma/adapters/
164
+ postgres";
164
165
 
165
166
  export const database = {
166
167
  prisma: {
@@ -188,17 +189,16 @@ prisma: {
188
189
 
189
190
  ## Framework adapter helpers
190
191
 
192
+ Built-in adapter factories:
193
+
191
194
  | Export | Use |
192
195
  | --------------------------- | --------------------------------------------------- |
193
- | `resolvePrismaAdapter(app)` | Used by `PrismaServiceProvider` |
194
196
  | `createPrismaAdapter(name)` | Build adapter for a named driver (`PRISMA_ADAPTER`) |
195
197
  | `createMariaDbAdapter()` | MySQL / MariaDB |
196
198
  | `createPostgresAdapter()` | PostgreSQL |
197
199
  | `createSqliteAdapter()` | SQLite file |
198
200
  | `createLibSqlAdapter()` | LibSQL / Turso |
199
201
 
200
- Import from `jcc-express-mvc/lib/Database` or `jcc-express-mvc/lib/Database/Drivers/Prisma/connection`.
201
-
202
202
  The framework registers `PrismaService` as a **singleton** and aliases `prisma` and `database.connection`.
203
203
 
204
204
  ---
@@ -262,9 +262,12 @@ Equivalent npm scripts: `prisma:generate`, `prisma:migrate`, `prisma:studio`.
262
262
  | `PrismaServiceProvider` | `jcc-express-mvc/lib/Database/PrismaServiceProvider.ts` |
263
263
  | `Database` resolver | `jcc-express-mvc/lib/Database/Database.ts` (`DB_ORM=prisma`) |
264
264
 
265
- `PrismaDriver` implements the same `DatabaseDriver` interface as `KnexDriver`, `SequelizeDriver`, and `MongooseDriver` (`connect`, `getConnection`, `disconnect`). Adapter selection lives under `Drivers/Prisma/`.
265
+ When `DB_ORM=prisma` (or when `database.prisma.service` is set in `app/Config/database.ts`):
266
266
 
267
- When `DB_ORM=prisma`, `DatabaseServiceProvider` skips Knex/Sequelize/Mongoose setup so only Prisma owns the connection.
267
+ - Your `PrismaService` class is registered as a **singleton**.
268
+ - The client is available via constructor injection, `app.resolve("prisma")`, or the global `prisma()` helper.
269
+ - Knex / Sequelize / Mongoose setup is skipped so Prisma owns the database connection.
270
+ - The client disconnects gracefully on shutdown.
268
271
 
269
272
  ---
270
273
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Introduction
4
4
 
5
- JCC Express MVC provides a fluent query builder through `DB.table(...)` and `DB.query()` (`jcc-express-mvc/lib/Jcc-eloquent/lib/Builder.ts`).
5
+ JCC Express MVC provides a fluent query builder through `DB.table(...)` and `DB.query()`.
6
6
 
7
7
  Use it for composable SQL queries without writing full raw SQL for every operation.
8
8
 
@@ -23,7 +23,7 @@ This creates a new seeder class in `database/seeders`.
23
23
  Typical seeder pattern:
24
24
 
25
25
  ```typescript
26
- import { DB } from "jcc-express-mvc/lib/Jcc-eloquent";
26
+ import { DB } from "jcc-express-mvc/Eloquent";
27
27
 
28
28
  export class UserSeeder {
29
29
  async run() {
@@ -2,19 +2,19 @@
2
2
 
3
3
  ## Introduction
4
4
 
5
- JCC Express MVC supports Sequelize as an alternative ORM path through `DatabaseServiceProvider` and `SequelizeDriver`.
5
+ JCC Express MVC supports [Sequelize](https://sequelize.org/) as an alternative SQL ORM when `DB_ORM=sequelize`. Models live in `app/Models/` and use Sequelize's class + `Model.init(...)` pattern — not JCC Eloquent's `Model` from `jcc-express-mvc/Eloquent`.
6
6
 
7
- When enabled, the framework resolves a Sequelize connection and aliases it as:
7
+ When enabled, the framework registers the connection as:
8
8
 
9
9
  - `database.connection`
10
10
  - `sequelize`
11
11
 
12
+ Resolve it with `app.resolve("sequelize")` or the global `app` helper during bootstrap.
13
+
12
14
  ---
13
15
 
14
16
  ## Enable Sequelize
15
17
 
16
- Set env/config to use Sequelize:
17
-
18
18
  ```env
19
19
  DB_ORM=sequelize
20
20
  DB_CONNECTION=mysql
@@ -25,7 +25,7 @@ DB_USERNAME=root
25
25
  DB_PASSWORD=secret
26
26
  ```
27
27
 
28
- `app/Config/database.ts` already contains the expected `sequelize` block:
28
+ `app/Config/database.ts` includes the expected `sequelize` block:
29
29
 
30
30
  ```typescript
31
31
  sequelize: {
@@ -38,49 +38,111 @@ sequelize: {
38
38
  }
39
39
  ```
40
40
 
41
+ `sync.alter` updates tables to match your models in development. Keep `sync.force` and `dropTables` disabled in production unless you intentionally reset schema.
42
+
41
43
  ---
42
44
 
43
45
  ## Required packages
44
46
 
45
- Install Sequelize and a SQL driver package:
46
-
47
47
  ```bash
48
48
  npm install sequelize mysql2
49
49
  ```
50
50
 
51
- For PostgreSQL or SQLite, install the matching dialect package(s).
51
+ For PostgreSQL or SQLite, install the matching dialect driver (`pg`, `better-sqlite3`, etc.).
52
52
 
53
53
  ---
54
54
 
55
- ## Generate models (recommended)
55
+ ## Generate models
56
56
 
57
- Do not manually create model files for this flow. Use ArtisanNode:
57
+ With `DB_ORM=sequelize`, ArtisanNode scaffolds Sequelize models:
58
58
 
59
59
  ```bash
60
60
  bun artisanNode make:model User
61
+ bun artisanNode make:model Post
61
62
  ```
62
63
 
63
- `SequelizeDriver` auto-loads models from `app/Models`, so generated model files are discovered at connect time.
64
+ Files are created in `app/Models/`. On connect, the framework loads every `.ts` / `.js` file in that folder, registers models, and runs `static associate` on each class that defines it.
64
65
 
65
66
  ---
66
67
 
67
- ## Sequelize model example
68
+ ## Model file structure
69
+
70
+ Each Sequelize model file should:
71
+
72
+ 1. Import `Model`, `DataTypes`, and `Sequelize` from the **`sequelize`** package.
73
+ 2. Resolve the shared connection with `app.resolve<Sequelize>("sequelize")`.
74
+ 3. Extend Sequelize's `Model` class and `declare` typed attributes.
75
+ 4. Define `static associate(models)` for relationships (optional).
76
+ 5. Call `ModelName.init(attributes, options)` at the bottom of the file.
77
+ 6. **Export a class whose name matches the filename** (e.g. `Test.ts` exports `class Test`) so autoloading can register it.
68
78
 
69
- In Sequelize mode, model files in `app/Models` should follow Sequelize's `Model.init(...)` pattern:
79
+ Example (`app/Models/Test.ts`):
70
80
 
71
81
  ```typescript
72
- import { DataTypes, Model } from "sequelize";
82
+ import { Model, DataTypes, Sequelize } from "sequelize";
73
83
 
74
- // Make sure this resolves to your registered Sequelize instance.
75
- const sequelize = app.resolve("sequelize");
84
+ const sequelize = app.resolve<Sequelize>("sequelize");
85
+
86
+ export class Test extends Model {
87
+ declare id: number;
88
+
89
+ /**
90
+ * Define relationships between models
91
+ * @param models - Record of all loaded model classes
92
+ */
93
+ static associate(models: any) {
94
+ //
95
+ }
96
+ }
97
+
98
+ Test.init(
99
+ {
100
+ id: {
101
+ type: DataTypes.INTEGER,
102
+ primaryKey: true,
103
+ autoIncrement: true,
104
+ },
105
+ },
106
+ {
107
+ sequelize,
108
+ tableName: "tests",
109
+ timestamps: true,
110
+ modelName: "Test",
111
+ }
112
+ );
113
+ ```
114
+
115
+ ### `Model.init` options
116
+
117
+ | Option | Purpose |
118
+ | ------------ | ---------------------------------------------------------- |
119
+ | `sequelize` | Shared connection from `app.resolve("sequelize")` |
120
+ | `tableName` | Database table name |
121
+ | `modelName` | Sequelize model name (used for route model binding suffix) |
122
+ | `timestamps` | When `true`, Sequelize manages `createdAt` / `updatedAt` |
123
+
124
+ Add columns in the first argument to `init` using `DataTypes` (`STRING`, `TEXT`, `BOOLEAN`, `DATE`, `JSON`, etc.).
125
+
126
+ ---
127
+
128
+ ## Full example: User model
129
+
130
+ ```typescript
131
+ import { Model, DataTypes, Sequelize } from "sequelize";
132
+
133
+ const sequelize = app.resolve<Sequelize>("sequelize");
76
134
 
77
135
  export class User extends Model {
78
- declare id?: number;
79
- declare name?: string;
80
- declare email?: string;
81
- declare password?: string;
82
- declare createdAt?: Date;
83
- declare updatedAt?: Date;
136
+ declare id: number;
137
+ declare name: string;
138
+ declare email: string;
139
+ declare password: string;
140
+ declare createdAt: Date;
141
+ declare updatedAt: Date;
142
+
143
+ static associate(models: any) {
144
+ User.hasMany(models.Post, { foreignKey: "userId", as: "posts" });
145
+ }
84
146
  }
85
147
 
86
148
  User.init(
@@ -94,54 +156,167 @@ User.init(
94
156
  type: DataTypes.STRING,
95
157
  allowNull: false,
96
158
  },
159
+ email: {
160
+ type: DataTypes.STRING,
161
+ allowNull: false,
162
+ unique: true,
163
+ },
164
+ password: {
165
+ type: DataTypes.STRING,
166
+ allowNull: false,
167
+ },
97
168
  },
98
169
  {
99
170
  sequelize,
100
171
  tableName: "users",
101
172
  timestamps: true,
102
173
  modelName: "User",
174
+ }
175
+ );
176
+ ```
177
+
178
+ ---
179
+
180
+ ## Relationships (`associate`)
181
+
182
+ After all models in `app/Models/` are loaded, the framework calls `static associate(models)` on each model. The `models` argument is a map of loaded classes keyed by filename (`User`, `Post`, etc.).
183
+
184
+ ```typescript
185
+ // app/Models/Post.ts
186
+ import { Model, DataTypes, Sequelize } from "sequelize";
187
+
188
+ const sequelize = app.resolve<Sequelize>("sequelize");
189
+
190
+ export class Post extends Model {
191
+ declare id: number;
192
+ declare title: string;
193
+ declare body: string;
194
+ declare userId: number;
195
+
196
+ static associate(models: any) {
197
+ Post.belongsTo(models.User, { foreignKey: "userId", as: "author" });
198
+ }
199
+ }
200
+
201
+ Post.init(
202
+ {
203
+ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
204
+ title: { type: DataTypes.STRING, allowNull: false },
205
+ body: { type: DataTypes.TEXT },
206
+ userId: { type: DataTypes.INTEGER, allowNull: false },
103
207
  },
208
+ {
209
+ sequelize,
210
+ tableName: "posts",
211
+ timestamps: true,
212
+ modelName: "Post",
213
+ }
104
214
  );
105
215
  ```
106
216
 
217
+ Models are loaded in **filename sort order**. Define foreign keys on child models and wire `associate` after both sides exist — parent models that appear earlier in the alphabet are available when `associate` runs on child models.
218
+
219
+ ---
220
+
221
+ ## Using models in controllers
222
+
223
+ Import the model class from `app/Models/`:
224
+
225
+ ```typescript
226
+ import { User } from "@/Models/User";
227
+
228
+ // List
229
+ const users = await User.findAll();
230
+
231
+ // Find by primary key
232
+ const user = await User.findByPk(1);
233
+
234
+ // Create
235
+ const created = await User.create({
236
+ name: "Jane",
237
+ email: "jane@example.com",
238
+ password: "secret",
239
+ });
240
+
241
+ // Update
242
+ await user.update({ name: "Jane Doe" });
243
+
244
+ // Delete
245
+ await user.destroy();
246
+
247
+ // Eager load
248
+ const withPosts = await User.findByPk(1, { include: ["posts"] });
249
+ ```
250
+
251
+ Use standard Sequelize query APIs on the model class and instances.
252
+
107
253
  ---
108
254
 
109
- ## What the driver does on connect
255
+ ## Route model binding
110
256
 
111
- From `SequelizeDriver`:
257
+ When `DB_ORM=sequelize`, implicit binding resolves models with `findByPk` from the route parameter (e.g. `{user}` → `User.findByPk(id)`). See [Routing](../The%20Basics/Routing.md#route-model-binding).
112
258
 
113
- - creates Sequelize instance with your config
114
- - calls `authenticate()`
115
- - auto-loads model files from `app/Models`
116
- - runs `sequelize.sync(config.sync)`
117
- - optionally drops tables when `dropTables` is enabled
259
+ ```typescript
260
+ Route.get("/users/{user}", [UsersController, "show"]);
261
+ ```
262
+
263
+ ```typescript
264
+ import { Inject, Method } from "jcc-express-mvc/Core/Dependency";
265
+ import { User } from "@/Models/User";
266
+
267
+ @Inject()
268
+ export class UsersController {
269
+ @Method({ params: ["user"] })
270
+ async show(user: User) {
271
+ return user;
272
+ }
273
+ }
274
+ ```
275
+
276
+ Column binding (`{email$user}`) uses Sequelize `findOne({ where: { email } })`.
118
277
 
119
278
  ---
120
279
 
121
280
  ## Access the Sequelize connection
122
281
 
123
- To get the Sequelize instance:
282
+ For raw queries or transactions outside model classes:
124
283
 
125
284
  ```typescript
126
285
  const sequelize = app.resolve("sequelize");
127
- ```
128
286
 
129
- The connection is registered as a singleton by `DatabaseServiceProvider`.
287
+ await sequelize.transaction(async (t) => {
288
+ // ...
289
+ });
290
+ ```
130
291
 
131
292
  ---
132
293
 
133
- ## Notes
294
+ ## What happens on connect
134
295
 
135
- - Sequelize setup is selected by `DB_ORM=sequelize`.
136
- - Model loading scans `app/Models` for `.ts` / `.js` files.
137
- - Keep `sync.force` / `dropTables` disabled in production unless intentionally resetting schema.
296
+ When `DB_ORM=sequelize`, the framework:
297
+
298
+ 1. Creates the Sequelize instance from `app/Config/database.ts`.
299
+ 2. Authenticates against the database.
300
+ 3. Requires every model file in `app/Models/` and collects exported classes.
301
+ 4. Calls `associate(models)` on each model that defines it.
302
+ 5. Runs `sequelize.sync(...)` using your `sync` config.
138
303
 
139
304
  ---
140
305
 
141
306
  ## Summary
142
307
 
143
- - Set `DB_ORM=sequelize`.
144
- - Configure `app/Config/database.ts` -> `sequelize`.
145
- - Install required npm packages.
146
- - Generate models with `bun artisanNode make:model User`.
147
- - Resolve connection via `app.resolve("sequelize")`.
308
+ - Set `DB_ORM=sequelize` and configure `database.sequelize` in app config.
309
+ - Models live in `app/Models/` — use `sequelize`'s `Model` + `Model.init`, not JCC Eloquent.
310
+ - Resolve the connection with `app.resolve<Sequelize>("sequelize")` in each model file.
311
+ - Define relationships in `static associate(models)`.
312
+ - Generate scaffolds with `bun artisanNode make:model <Name>`.
313
+ - Query with Sequelize APIs (`findAll`, `findByPk`, `create`, etc.).
314
+
315
+ ---
316
+
317
+ ## Related
318
+
319
+ - [Database Introduction](./Database-Introduction.md)
320
+ - [Configuration](../Getting-Started/Configuration.md)
321
+ - [Routing](../The%20Basics/Routing.md)
322
+ - [Artisan Node](../The%20Basics/Artisan-Node.md)
@@ -14,7 +14,7 @@ JCC Express MVC supports transactions through:
14
14
  ## Basic transaction usage
15
15
 
16
16
  ```typescript
17
- import { DB } from "jcc-express-mvc/lib/Jcc-eloquent";
17
+ import { DB } from "jcc-express-mvc/Eloquent";
18
18
 
19
19
  await DB.transaction(async () => {
20
20
  await DB.table("wallets").where("id", 1).decrement("balance", 100);