@gaonjs/cli 0.13.1 → 0.13.2
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.
|
@@ -434,6 +434,28 @@ gaon db seed # domain/seed.ts 실행
|
|
|
434
434
|
**파일명 순으로 실제 실행**(replay)하고, ② 그 뒤 스키마 diff 로 나머지를
|
|
435
435
|
적용한다.
|
|
436
436
|
|
|
437
|
+
- **replay 가 diff 보다 먼저다 — 손작성 마이그는 "아직 diff 가 안 만든 테이블"을
|
|
438
|
+
참조할 수 없다** (결정 65). 스키마에만 선언돼 있고 아직 DB 에 없는 테이블을
|
|
439
|
+
FK 로 거는 마이그레이션은 **빈 DB 에서만** `relation "posts" does not exist` 로
|
|
440
|
+
실패한다(테이블이 이미 있는 개발 DB 에서는 통과 — 그래서 CI·새 클론에서만
|
|
441
|
+
터진다). 조인 테이블처럼 남의 테이블을 참조해야 하면 **참조 대상도 같은/앞선
|
|
442
|
+
마이그 파일에서 함께 만든다**:
|
|
443
|
+
|
|
444
|
+
```ts
|
|
445
|
+
// 20260728_add_tags.ts — posts 를 FK 로 걸려면 posts 가 먼저 존재해야 한다.
|
|
446
|
+
export async function up(db: Kysely<any>): Promise<void> {
|
|
447
|
+
await db.schema.createTable('tags')/* … */.execute()
|
|
448
|
+
await db.schema.createTable('posts_tags')
|
|
449
|
+
.addColumn('postId', 'bigint', (c) => c.notNull().references('posts.id').onDelete('cascade'))
|
|
450
|
+
// ↑ posts 가 스키마에만 있고 DB 에 없으면 빈 DB 에서 실패한다.
|
|
451
|
+
.execute()
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
전부 스키마 우선으로 두면(손작성 마이그 없이) diff 가 의존 순서를 알아서
|
|
456
|
+
잡으므로 이 함정 자체가 없다 — **손작성 마이그는 diff 로 표현 못 하는 것에만**
|
|
457
|
+
쓴다(rename·백필·수동 DDL).
|
|
458
|
+
|
|
437
459
|
- **손작성 마이그는 `db/migrations/<파일명>.ts`** 에 두고 `up(db)`·`down(db)`
|
|
438
460
|
(Kysely) 를 export 한다. **파일명이 곧 버전 키** — `0001_add_posts.ts`
|
|
439
461
|
시퀀스든 `20260724_add_posts.ts` 타임스탬프든 사전순 정렬이 안정적이면 된다
|
|
@@ -172,6 +172,35 @@ const ok = await verifyPassword(plain, user.passwordDigest) // Promise<boolean>
|
|
|
172
172
|
}
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
+
- **세션을 확정·해제하는 것은 `this.auth`** (결정 65). `requireAuth()` 는 이미
|
|
176
|
+
로그인된 요청을 **지키는** 쪽이고, 로그인 자체를 **성립시키는** 호출은 따로다:
|
|
177
|
+
|
|
178
|
+
| 호출 | 하는 일 |
|
|
179
|
+
|---|---|
|
|
180
|
+
| `this.auth.user` | 현재 사용자 (`GaonCurrentUser \| null`) |
|
|
181
|
+
| `this.auth.login(user)` | 세션에 사용자 id 를 심어 로그인 상태로 만든다 |
|
|
182
|
+
| `this.auth.logout()` | 세션에서 사용자를 지운다 |
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
// 로그인 — 폼 액션의 유일한 render+redirect 혼용 예외(결정 57 보완)
|
|
186
|
+
async create() {
|
|
187
|
+
const { email, password } = this.params({ _row: {} as { email: string; password: string } })
|
|
188
|
+
const user = await User.where('email', '=', email).first()
|
|
189
|
+
if (!user || !(await verifyPassword(password, user.passwordDigest))) {
|
|
190
|
+
return this.render('Auth/Login', { error: '이메일 또는 비밀번호가 올바르지 않습니다.', csrf: this.csrfToken() })
|
|
191
|
+
}
|
|
192
|
+
this.auth.login(user) // 세션 확정
|
|
193
|
+
return this.redirect('/dashboard')
|
|
194
|
+
}
|
|
195
|
+
// 로그아웃 — DELETE /session (페이지에서 router.delete 로 호출 · 결정 64)
|
|
196
|
+
async destroy() {
|
|
197
|
+
this.auth.logout()
|
|
198
|
+
return this.redirect('/session/new')
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
API 앱(JWT)은 세션 대신 `this.jwt.issue(user)` / `this.jwt.refresh(token)` 를 쓴다.
|
|
203
|
+
|
|
175
204
|
- **`this.auth.user`/`requireAuth()` 사용자 타입은 앱이 증강한다** (결정 58).
|
|
176
205
|
`GaonCurrentUser` 는 빈 인터페이스라 증강 없이는 `user.id` 접근이 타입에러다.
|
|
177
206
|
`gaon g auth` 가 `apps/<app>/auth.ts` 에 심는다:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gaonjs/cli",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.2",
|
|
4
4
|
"description": "Gaon CLI 구현: 제너레이터·스캐폴딩·로드맵 출력 (M1 스텁)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
"typescript": "^5.9.0",
|
|
29
29
|
"vite": "^7.0.0",
|
|
30
30
|
"@gaonjs/async": "0.3.1",
|
|
31
|
-
"@gaonjs/config": "0.3.0",
|
|
32
31
|
"@gaonjs/core": "0.1.4",
|
|
32
|
+
"@gaonjs/mail": "0.1.1",
|
|
33
33
|
"@gaonjs/data": "0.8.4",
|
|
34
34
|
"@gaonjs/web": "0.5.3",
|
|
35
|
-
"@gaonjs/
|
|
35
|
+
"@gaonjs/config": "0.3.0"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build": "node ../../node_modules/typescript/bin/tsc -p tsconfig.json && node -e \"require('fs').cpSync('src/templates','dist/templates',{recursive:true})\""
|