기능 전용 API
API 원본은 src/extensions/[feature]/api/.../route.ts에 두고 기능의 routes.json에서 src/app/api/.../route.ts와 연결합니다. exports에 실제 HTTP 메서드를, configs에 필요한 runtime 등을 선언한 뒤 npm run extensions:sync를 실행합니다. [연결 예시](/docs/extensions)를 참고하세요.
서버에서 인증·권한·입력값을 검증합니다. 공용 업로드 API와 모바일 bootstrap처럼 여러 기능을 잇는 통합 API는 특정 기능 폴더로 무조건 이동하지 않습니다.
Proxy 확장
src/proxy.ts는 Next.js가 찾는 고정 파일이라 삭제하거나 gitignore 처리하지 않습니다. 현재 프로젝트는 기본 proxy 구현을 @core/proxy/defaultProxy에서 직접 가져옵니다.
// src/extensions/proxy.ts
import type { NextRequest } from "next/server";
import { proxy as defaultProxy } from "@/core/proxy/defaultProxy";
export async function proxy(request: NextRequest) {
return defaultProxy(request);
}기본 proxy에는 관리자 접근 제어, 로그인 사용자 접근 제어, Redis active session 확인, CSRF origin 검증이 포함되어 있습니다.
위 확장 파일을 만드는 것만으로 적용되지는 않습니다. 현재 src/proxy.ts는 기본 proxy를 직접 export하므로 프로젝트 proxy를 사용하려면 해당 연결을 명시적으로 변경하고 기존 보안 처리가 유지되는지 검증해야 합니다.
Prisma 확장
DB 모델의 원본은 기능 폴더에 둡니다. 코어 원본은 src/core/prisma/schema.prisma이고 루트 prisma/schema.prisma는 생성 결과입니다. npm run prisma:sync로 코어와 확장 정의를 합칩니다.
// src/extensions/posts/issuetracker/prisma/schema/issue.prisma (새 모델 예시)
model IssueMeta {
id Int @id @default(autoincrement())
documentId Int @unique
priority String?
createdAt DateTime @default(now())
@@index([documentId])
}코어 모델과 관계를 맺고 싶을 때는 우선 scalar 컬럼을 사용하세요. 예를 들어 documentId Int, userId Int를 두고 query에서 조합하면 코어 모델에 back relation을 추가하지 않아도 됩니다.
기능의 prisma/schema.prisma 단일 파일 또는 prisma/schema/*.prisma 조각을 지원합니다. 기존 extensions/prisma도 호환되지만 같은 모델을 두 위치에 중복 선언하면 안 됩니다.
Prisma 명령
npm run prisma:sync
npm run prisma:generate위 명령은 스키마 합성과 클라이언트 생성이며 DB 테이블을 만들지 않습니다. 개발 DB 변경이 승인되면 npm run migrate:dev로 마이그레이션을 준비하고 검토한 SQL을 저장소에 포함합니다. 운영 환경은 대상 DB와 백업을 확인한 뒤 승인된 배포 절차에서 npx prisma migrate deploy로 적용합니다. db push를 운영 마이그레이션의 대체로 사용하지 않습니다.
현재 마이그레이션 경로는 prisma.config.ts의 src/core/prisma/migrations입니다. 기능 폴더의 prisma/migrations를 자동 수집하는 기능은 없습니다. 이미 적용된 이력은 폴더 정리 때문에 이동·삭제·재실행하지 않습니다.
migrate status가 최신이어도 모델에 대응하는 마이그레이션 자체가 없으면 테이블이 누락될 수 있습니다. 실제 DB와 합성 스키마의 차이도 확인해야 합니다. DB migration, push, seed는 사용자의 명시 요청 없이 실행하지 않습니다.
Extension seed
프로젝트별 초기 데이터가 필요하면 src/extensions/prisma/seed.js를 추가합니다. 이 파일은 기본 seed 트랜잭션 안에서 실행됩니다.
module.exports = async ({ client }) => {
await client.query(`
INSERT INTO "IssueMeta" ("documentId", "priority", "createdAt")
VALUES ($1, $2, NOW())
ON CONFLICT ("documentId") DO NOTHING
`, [1, "normal"]);
};extension seed는 여러 번 실행해도 데이터가 중복되지 않게 작성해야 합니다. 위 예시는 문서당 메타데이터 하나를 가정하며 documentId의 UNIQUE 제약으로 중복을 막습니다. 실제 존재하는 문서 ID를 사용하고 서비스 요구에 맞게 제약을 설계하세요.
현재 seed 로더는 프로젝트 공용 src/extensions/prisma/seed.js를 사용합니다. 기능 폴더에 seed 파일을 넣는 것만으로 자동 실행되지 않으며 공용 seed에서 명시적으로 호출해야 합니다.