반응형
파일구조
src/features/auth/action.ts -> src/features/auth/queries.ts 로 변경
- actions.ts: 서버 액션 (사용자 상호작용, form submission)
- queries.ts: 데이터 조회 (read-only 서버 함수)
src/
├── lib/
│ └── appwrite.ts # ⭐ 클라이언트 팩토리 함수
├── features/
│ ├── auth/
│ │ └── (action.ts 변경) queries.ts # getCurrent()
│ ├── workspaces/
│ │ └── (action.ts 변경) queries.ts # getWorkspaces(), getWorkspace() 특정 워크스페이스 조회 (권한 확인)
│ └── members/
│ └── utils.ts # getMember()
src/lib/appwrite.ts
- 재사용 가능한 클라이언트 초기화 함수 createSessionClient() 추가
- Getter함수는 실제 호출할 때만 생성되서 메모리를 절약할 수 있다.
export async function createSessionClient(){
const client = new Client()
.setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!)
.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT!)
const session = await cookies().get(AUTH_COOKIE);
if(!session || !session.value){
throw new Error("Unauthorized")
}
client.setSession(session.value);
return{
get account() {
return new Account(client);
},
get databases() {
return new Databases(client)
}
}
}
src/features/auth/queries.ts
"use server"
import { createSessionClient } from '@/lib/appwrite'
export const getCurrent = async () => {
try{
// const client = new Client()
// .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!)
// .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT!)
// const session = await cookies().get(AUTH_COOKIE)
// if(!session) return null
// client.setSession(session.value);
// const account = new Account(client);
// createSessionClient: 일반 조회 (getCurrent, getWorkspaces)
const {account} = await createSessionClient()
return await account.get();
}catch{
return null
}
}
src/features/workspaces/queries.ts
"use server"
import { cookies } from 'next/headers'
import { Client, Databases, Query, Account } from 'node-appwrite'
import { AUTH_COOKIE } from '@/features/auth/constants'
import { DATABASE_ID, MEMBERS_ID, WORKSPACES_ID } from '@/config'
import { Workspace } from './type'
import { getMember } from '../members/utils'
import { createSessionClient } from '@/lib/appwrite'
export const getWorkspaces = async () => {
try{
// const client = new Client()
// .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!)
// .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT!)
// const session = await cookies().get(AUTH_COOKIE)
// if(!session) return {documents: [], total:0}
// client.setSession(session.value);
// const databases = new Databases(client);
// const account = new Account(client);
const { databases, account } = await createSessionClient();
const user = await account.get();
// getMember 유틸로 권한 확인
const members = await databases.listDocuments(
DATABASE_ID,
MEMBERS_ID,
[Query.equal("userId", user.$id)]
);
if(members.total === 0){
return {documents: [], total:0}
}
const workspaceIds = members.documents.map((member) => member.workspaceId)
// 워크스페이스 정보 조회
const workspace = await databases.listDocuments(
DATABASE_ID,
WORKSPACES_ID,
[
Query.orderDesc("$createdAt"),
Query.contains("$id", workspaceIds)
]
);
return workspace
}catch{
return {documents: [], total:0}
}
}
interface GetWorkspaceProps{
workspaceId:string
}
export const getWorkspace = async ({workspaceId}:GetWorkspaceProps) => {
try{
// const client = new Client()
// .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!)
// .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT!)
// const session = await cookies().get(AUTH_COOKIE)
// if(!session) return null
// client.setSession(session.value);
// const databases = new Databases(client);
// const account = new Account(client);
const {databases, account} = await createSessionClient();
const user = await account.get();
const member = await getMember({
databases,
userId:user.$id,
workspaceId
})
if(!member) return null
const workspace = await databases.getDocument<Workspace>(
DATABASE_ID,
WORKSPACES_ID,
workspaceId
);
return workspace
}catch{
return null
}
}
핵심
- 팩토리 함수 패턴: 반복되는 초기화 코드를 한 곳에 집중
- 파일 분리: actions.ts → queries.ts 로 의도 명확화
- Getter 패턴: 필요한 것만 필요할 때 생성
- 에러 처리: 중앙화된 함수에서 일관되게 처리
- 확장성: 새로운 Appwrite 서비스 추가 시 appwrite.ts만 수정
- 보안: "server-only" import로 클라이언트 실행 방지
반응형
'Clone Coding' 카테고리의 다른 글
| Jira-clone - 워크스페이스 초대 링크 기능 구현 (0) | 2025.10.12 |
|---|---|
| Jira-clone - 워크스페이스 삭제(Delete) 기능 구현 (0) | 2025.10.12 |
| Jira-clone - 워크스페이스 수정(Update) 기능 구현 (0) | 2025.10.10 |
| Jira-clone - 독립 실행형 레이아웃과 워크스페이스 생성 페이지 구현 (0) | 2025.10.10 |
| Jira-clone - 개별 작업 공간 ID 페이지 만들기 (0) | 2025.10.02 |