feat: 完成 B 群組 — 資料層與核心領域模型

- 導入 Prisma 7.9.1 + SQLite(better-sqlite3 driver adapter),prisma.config.ts 管理連線設定
- 完整資料模型:User/Work/Character/CharacterAlias/EpisodicMemory/SemanticMemory/
  ProceduralRule/EmotionState/Relationship/SentimentLedgerEntry
- packages/db:Prisma Client 存取層(ESM,因 Prisma 7 產出的 generated client 僅支援 ESM)
- apps/api 隨之改為 ESM 以相容 packages/db
- packages/shared:新增角色/記憶/情緒/關係共用型別,api 與 web 皆從此匯入
- prisma/seed.ts:建立測試使用者與元氣型測試角色,含完整關係帳本與記憶種子資料
- apps/api:新增 GET /characters
- scripts/smoke/B.mjs:驗證資料表齊全、API 讀出種子角色、關係與記憶可寫入讀出
- 保留 Prisma 官方隨 CLI 附的 agent skill 文件(.agents/skills 等),供後續群組查閱

npm run restart && npm run smoke -- B 皆通過(B-V),A 群組冒煙測試無回歸。
This commit is contained in:
Jeffery
2026-08-13 09:43:15 +08:00
parent ae9c44dde7
commit f44200f543
124 changed files with 13566 additions and 48 deletions
+4
View File
@@ -3,15 +3,19 @@
"version": "0.1.0",
"private": true,
"description": "心音後端服務(NestJS)",
"type": "module",
"main": "dist/main.js",
"scripts": {
"build": "tsc -b",
"start": "node dist/main.js"
},
"dependencies": {
"@kokorone/db": "*",
"@kokorone/shared": "*",
"@nestjs/common": "^11.1.29",
"@nestjs/core": "^11.1.29",
"@nestjs/platform-express": "^11.1.29",
"dotenv": "^17.4.2",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.2"
}
+2
View File
@@ -1,7 +1,9 @@
import { Module } from "@nestjs/common";
import { HealthController } from "./health/health.controller.js";
import { CharactersModule } from "./characters/characters.module.js";
@Module({
imports: [CharactersModule],
controllers: [HealthController],
})
export class AppModule {}
@@ -0,0 +1,12 @@
import { Controller, Get } from "@nestjs/common";
import { CharactersService } from "./characters.service.js";
@Controller("characters")
export class CharactersController {
constructor(private readonly charactersService: CharactersService) {}
@Get()
findAll() {
return this.charactersService.findAll();
}
}
@@ -0,0 +1,11 @@
import { Module } from "@nestjs/common";
import { PrismaModule } from "../prisma/prisma.module.js";
import { CharactersController } from "./characters.controller.js";
import { CharactersService } from "./characters.service.js";
@Module({
imports: [PrismaModule],
controllers: [CharactersController],
providers: [CharactersService],
})
export class CharactersModule {}
@@ -0,0 +1,37 @@
import { Injectable } from "@nestjs/common";
import type { Character } from "@kokorone/shared";
import { PrismaService } from "../prisma/prisma.service.js";
@Injectable()
export class CharactersService {
constructor(private readonly prisma: PrismaService) {}
async findAll(): Promise<Character[]> {
const rows = await this.prisma.client.character.findMany({
include: { aliases: true },
orderBy: { createdAt: "asc" },
});
return rows.map((row) => ({
id: row.id,
workId: row.workId,
source: row.source,
buildStatus: row.buildStatus,
basicInfo: row.basicInfo,
backgroundStory: row.backgroundStory,
personalityArchetype: row.personalityArchetype,
likesDislikes: row.likesDislikes,
goalsObsessions: row.goalsObsessions,
speechStyle: row.speechStyle,
initialRelationValue: row.initialRelationValue,
createdAt: row.createdAt.toISOString(),
updatedAt: row.updatedAt.toISOString(),
aliases: row.aliases.map((alias) => ({
id: alias.id,
formalName: alias.formalName,
nickname: alias.nickname,
calledByOthers: alias.calledByOthers,
})),
}));
}
}
+1
View File
@@ -1,3 +1,4 @@
import "dotenv/config";
import "reflect-metadata";
import { NestFactory } from "@nestjs/core";
import { log } from "@kokorone/shared";
+8
View File
@@ -0,0 +1,8 @@
import { Module } from "@nestjs/common";
import { PrismaService } from "./prisma.service.js";
@Module({
providers: [PrismaService],
exports: [PrismaService],
})
export class PrismaModule {}
+11
View File
@@ -0,0 +1,11 @@
import { Injectable, OnModuleDestroy } from "@nestjs/common";
import { createPrismaClient } from "@kokorone/db";
@Injectable()
export class PrismaService implements OnModuleDestroy {
readonly client = createPrismaClient();
onModuleDestroy() {
return this.client.$disconnect();
}
}
+1 -1
View File
@@ -7,5 +7,5 @@
"emitDecoratorMetadata": true
},
"include": ["src"],
"references": [{ "path": "../../packages/shared" }]
"references": [{ "path": "../../packages/shared" }, { "path": "../../packages/db" }]
}
+15
View File
@@ -0,0 +1,15 @@
export type {
Character,
CharacterAlias,
CharacterSource,
CharacterBuildStatus,
EpisodicMemory,
SemanticMemory,
ProceduralRule,
EmotionTag,
MemorySource,
EmotionState,
Relationship,
RelationshipStage,
SentimentLedgerEntry,
} from "@kokorone/shared";
+1
View File
@@ -9,6 +9,7 @@
"lint": "eslint"
},
"dependencies": {
"@kokorone/shared": "*",
"next": "16.3.0",
"react": "19.2.8",
"react-dom": "19.2.8"