Loading...
Loading...
Use when creating or modifying API functions in */api/ directories. Enforces Firestore patterns and data fetching conventions.
npx skill4agent add bumgeunsong/daily-writing-friends api-layer[feature]/api/src/
├── post/
│ └── api/
│ ├── post.ts # CRUD operations
│ └── postQueries.ts # React Query hooksimport { collection, addDoc, query, where, getDocs } from 'firebase/firestore';
import { db } from '@/firebase';
import type { Post } from '../model/Post';
export async function createPost(
boardId: string,
postData: Omit<Post, 'id' | 'createdAt'>,
): Promise<Post> {
const postsRef = collection(db, 'boards', boardId, 'posts');
const docRef = await addDoc(postsRef, {
...postData,
createdAt: new Date(),
});
return { ...postData, id: docRef.id, createdAt: new Date() };
}import { writeBatch, doc } from 'firebase/firestore';
const batch = writeBatch(db);
batch.set(doc(db, 'posts', postId), postData);
batch.update(doc(db, 'users', userId), { postCount: increment(1) });
await batch.commit();users/{userId}
users/{userId}/postings/{postingId}
users/{userId}/commentings/{commentingId}
boards/{boardId}/posts/{postId}
boards/{boardId}/posts/{postId}/comments/{commentId}
boards/{boardId}/posts/{postId}/comments/{commentId}/replies/{replyId}const mutation = useMutation({
mutationFn: createPost,
onMutate: async (newPost) => {
await queryClient.cancelQueries({ queryKey: ['posts'] });
const previous = queryClient.getQueryData(['posts']);
queryClient.setQueryData(['posts'], (old) => [...old, newPost]);
return { previous };
},
onError: (err, newPost, context) => {
queryClient.setQueryData(['posts'], context.previous);
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['posts'] });
},
});| Pattern | When |
|---|---|
| Create with auto-ID |
| Create/overwrite with known ID |
| Partial update |
| Multiple related writes |
| Listeners | Real-time features |