Bkend Cookbook logo

Bkend Cookbook

Organization
ww-w-ai
bkend-cookbook

bkend.ai practical project tutorials and troubleshooting guide. Covers 4 full-guide projects (blog, recipe-app, shopping-mall, social-network) with step-by-step implementation patterns including schema design, architecture patterns, and AI prompt collections. Triggers: cookbook, tutorial, example project, todo app, blog app, shopping mall, 쿡북, 튜토리얼, 예제, 블로그, 쇼핑몰, 투두, 프로젝트 만들기, クックブック, チュートリアル, 例題, ブログ, ショッピング, 食谱, 教程, 示例, 博客, 商城, libro de cocina, tutorial, ejemplo, blog, tienda, livre de recettes, tutoriel, exemple, blog, boutique, Kochbuch, Tutorial, Beispiel, Blog, Shop, ricettario, tutorial, esempio, blog, negozio Do NOT use for: authentication details (use bkend-auth), database specifics (use bkend-data), security policies (use bkend-security)

Overview

Publisherww-w-ai
Repositorybkit-gemini
Skill namebkend-cookbook
Stars
66
Forks
16
Bundled files
Instructions only
LicenseApache-2.0
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by ww-w-ai on GitHub. Read the source before you install it.

Installation

Install the Bkend Cookbook AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/ww-w-ai/bkit-gemini.git /tmp/bkit-gemini
mkdir -p .claude/skills
cp -r /tmp/bkit-gemini/skills/bkend-cookbook .claude/skills/bkend-cookbook
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Bkend Cookbook in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Bkend Cookbook on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Bkend Cookbook is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

bkend-cookbook

bkend.ai practical project tutorials and troubleshooting guide

1. Projects Overview

ProjectLevelTablesFrontendDescription
BlogBeginner3Next.jsPersonal blog with posts, comments, and user profiles
Recipe AppIntermediate5Next.js + FlutterCross-platform recipe sharing with categories and favorites
Shopping MallIntermediate4Next.jsE-commerce with products, orders, and state machine workflow
Social NetworkBeginner5FlutterSocial feed with posts, comments, likes, and follow system

Choosing a Project

  • First time with bkend? Start with Blog -- minimal tables, straightforward CRUD.
  • Want cross-platform? Pick Recipe App -- covers both web and mobile patterns.
  • Need transactional logic? Go with Shopping Mall -- order state machine and payment flow.
  • Building a mobile-first app? Try Social Network -- Flutter-native with feed algorithms.

2. Blog Project

Level: Beginner | Tables: 3 | Frontend: Next.js | Time: ~2 hours

2.1 Schema Design (3 Tables)

users
ColumnTypeRequiredDescription
namestringYesDisplay name
emailstringYesUnique email address
avatarstringNoProfile image URL
posts
ColumnTypeRequiredDescription
titlestringYesPost title
contentstringYesPost body (Markdown supported)
authorIdstringYesReference to users table
statusstringYesdraft or published
tagsarrayNoList of tag strings
comments
ColumnTypeRequiredDescription
contentstringYesComment body
postIdstringYesReference to posts table
authorIdstringYesReference to users table

2.2 Quick Start (5 Minutes)

Step 1: Create the Project

Use the bkend Console or MCP tool to create a new project named my-blog.

> Create a new project called "my-blog"
Step 2: Create Tables

Create the three tables with the schemas defined above.

> Create a "users" table with columns: name (string, required), email (string, required), avatar (string)
> Create a "posts" table with columns: title (string, required), content (string, required), authorId (string, required), status (string, required), tags (array)
> Create a "comments" table with columns: content (string, required), postId (string, required), authorId (string, required)
Step 3: Test the API
bash
# Create a user
curl -X POST https://api-client.bkend.ai/v1/data/users \
  -H "Content-Type: application/json" \
  -H "X-Project-Id: <your-project-id>" \
  -H "X-Environment: dev" \
  -H "X-API-Key: <your-api-key>" \
  -d '{"name": "Alice", "email": "alice@example.com"}'

# Create a post
curl -X POST https://api-client.bkend.ai/v1/data/posts \
  -H "Content-Type: application/json" \
  -H "X-Project-Id: <your-project-id>" \
  -H "X-Environment: dev" \
  -H "X-API-Key: <your-api-key>" \
  -d '{"title": "Hello World", "content": "My first post!", "authorId": "<user-id>", "status": "published", "tags": ["intro"]}'

# List all published posts
curl "https://api-client.bkend.ai/v1/data/posts?filter=%7B%22status%22%3A%22published%22%7D" \
  -H "X-Project-Id: <your-project-id>" \
  -H "X-Environment: dev" \
  -H "X-API-Key: <your-api-key>"

2.3 AI Prompt Collection

Use these prompts with Gemini CLI or Claude Code to accelerate development:

Schema & Data:

> Create a blog schema with users, posts, and comments tables
> Add 5 sample blog posts with different tags and statuses
> Query all published posts sorted by newest first
> Find posts tagged with "tutorial" by author Alice

Frontend:

> Generate a Next.js blog layout with header, sidebar, and post list
> Create a Markdown editor component for writing blog posts
> Build a comment section with nested replies
> Add tag filtering to the blog post list page

API Integration:

> Create a bkendFetch wrapper for the blog API
> Build TanStack Query hooks for posts CRUD operations
> Add optimistic update for the comment submission form
> Implement infinite scroll pagination for the post feed

3. Recipe App Project

Level: Intermediate | Tables: 5 | Frontend: Next.js + Flutter | Time: ~4 hours

3.1 Schema Design (5 Tables)

users
ColumnTypeRequiredDescription
namestringYesDisplay name
emailstringYesUnique email address
avatarstringNoProfile image URL
biostringNoShort biography
recipes
ColumnTypeRequiredDescription
titlestringYesRecipe name
descriptionstringYesShort summary
instructionsstringYesStep-by-step cooking instructions
authorIdstringYesReference to users table
categoryIdstringYesReference to categories table
cookTimeintNoCooking time in minutes
servingsintNoNumber of servings
imageUrlstringNoMain recipe image
ingredients
ColumnTypeRequiredDescription
recipeIdstringYesReference to recipes table
namestringYesIngredient name
quantitystringYesAmount (e.g., "2 cups")
unitstringNoMeasurement unit
orderintYesDisplay order
categories
ColumnTypeRequiredDescription
namestringYesCategory name (e.g., "Italian", "Dessert")
slugstringYesURL-friendly identifier
iconstringNoEmoji or icon identifier
favorites
ColumnTypeRequiredDescription
userIdstringYesReference to users table
recipeIdstringYesReference to recipes table

3.2 Architecture

Web (Next.js):

Stack: Next.js App Router + TanStack Query + Zustand
  • Next.js App Router -- file-based routing with server components
  • TanStack Query -- server state management, caching, and background refetching
  • Zustand -- lightweight client state (UI state, filters, modals)

Mobile (Flutter):

Stack: Flutter + Dio + Riverpod
  • Flutter -- cross-platform UI framework
  • Dio -- HTTP client with interceptor support
  • Riverpod -- state management with dependency injection

3.3 AI Prompt Collection

> Create the recipe app schema with users, recipes, ingredients, categories, and favorites
> Build a recipe card grid component with image, title, and cook time
> Implement category-based filtering with a sidebar navigation
> Create a favorites toggle button with optimistic update
> Generate a Flutter recipe detail screen with ingredient checklist

4. Shopping Mall Project

Level: Intermediate | Tables: 4 | Frontend: Next.js | Time: ~5 hours

4.1 Schema Design (4 Tables)

users
ColumnTypeRequiredDescription
namestringYesDisplay name
emailstringYesUnique email address
addressobjectNoShipping address object
phonestringNoContact phone number
products
ColumnTypeRequiredDescription
namestringYesProduct name
descriptionstringYesProduct description
priceintYesPrice in cents (to avoid floating point issues)
stockintYesAvailable inventory count
categorystringYesProduct category
imageUrlsarrayNoList of product image URLs
isActiveboolYesWhether the product is listed
orders
ColumnTypeRequiredDescription
userIdstringYesReference to users table
statusstringYesOrder status (see state machine below)
totalAmountintYesTotal price in cents
shippingAddressobjectYesSnapshot of delivery address
paymentMethodstringNoPayment method identifier
paidAtdateNoTimestamp of payment confirmation
shippedAtdateNoTimestamp of shipment
deliveredAtdateNoTimestamp of delivery
order_items
ColumnTypeRequiredDescription
orderIdstringYesReference to orders table
productIdstringYesReference to products table
quantityintYesNumber of items
unitPriceintYesPrice per item at time of order (snapshot)
subtotalintYesquantity * unitPrice

4.2 Order State Machine

                          +--> cancelled
                          |
draft --> pending --> paid --> shipped --> delivered --> completed
                     |                       |
                     +--> cancelled           +--> cancelled

State Transitions:

FromToTriggerSide Effect
draftpendingUser submits orderValidate stock availability
pendingpaidPayment confirmedDeduct stock, record paidAt
pendingcancelledPayment timeout / user cancelsRelease reserved stock
paidshippedAdmin ships orderRecord shippedAt, generate tracking
paidcancelledAdmin cancelsRefund payment, restore stock
shippeddeliveredDelivery confirmedRecord deliveredAt
deliveredcompletedAuto after 7 days or user confirmsFinalize order
deliveredcancelledReturn / refund requestProcess refund, restore stock

Implementation Pattern:

typescript
// application/services/order-state-machine.ts

type OrderStatus =
  | "draft"
  | "pending"
  | "paid"
  | "shipped"
  | "delivered"
  | "completed"
  | "cancelled";

const VALID_TRANSITIONS: Record<OrderStatus, OrderStatus[]> = {
  draft: ["pending"],
  pending: ["paid", "cancelled"],
  paid: ["shipped", "cancelled"],
  shipped: ["delivered"],
  delivered: ["completed", "cancelled"],
  completed: [],
  cancelled: [],
};

export function canTransition(
  currentStatus: OrderStatus,
  nextStatus: OrderStatus
): boolean {
  return VALID_TRANSITIONS[currentStatus]?.includes(nextStatus) ?? false;
}

export async function transitionOrder(
  orderId: string,
  nextStatus: OrderStatus
): Promise<void> {
  const order = await bkendFetch(`/v1/data/orders/${orderId}`);
  const current = order.data.status as OrderStatus;

  if (!canTransition(current, nextStatus)) {
    throw new Error(
      `Invalid transition: ${current} -> ${nextStatus}`
    );
  }

  const updates: Record<string, any> = { status: nextStatus };

  if (nextStatus === "paid") updates.paidAt = new Date().toISOString();
  if (nextStatus === "shipped") updates.shippedAt = new Date().toISOString();
  if (nextStatus === "delivered") updates.deliveredAt = new Date().toISOString();

  await bkendFetch(`/v1/data/orders/${orderId}`, {
    method: "PUT",
    body: JSON.stringify(updates),
  });
}

4.3 AI Prompt Collection

> Create the shopping mall schema with users, products, orders, and order_items tables
> Build a product catalog page with grid view, filters, and sorting
> Implement a shopping cart with Zustand state management
> Create an order checkout flow with address form and payment step
> Build an admin dashboard for order management with status transitions
> Add stock validation before order submission

5. Social Network Project

Level: Beginner | Tables: 5 | Frontend: Flutter | Time: ~3 hours

5.1 Schema Design (5 Tables)

users
ColumnTypeRequiredDescription
namestringYesDisplay name
emailstringYesUnique email address
avatarstringNoProfile image URL
biostringNoShort biography
followersCountintNoCounter cache for followers
followingCountintNoCounter cache for following
posts
ColumnTypeRequiredDescription
contentstringYesPost text content
authorIdstringYesReference to users table
imageUrlsarrayNoAttached image URLs
likesCountintNoCounter cache for likes
commentsCountintNoCounter cache for comments
comments
ColumnTypeRequiredDescription
contentstringYesComment body
postIdstringYesReference to posts table
authorIdstringYesReference to users table
likes
ColumnTypeRequiredDescription
postIdstringYesReference to posts table
userIdstringYesReference to users table
follows
ColumnTypeRequiredDescription
followerIdstringYesUser who follows
followingIdstringYesUser being followed

5.2 Feed Algorithm Pattern

The social feed displays posts from users that the current user follows, sorted by newest first.

Step 1: Get the list of users the current user follows

GET /v1/data/follows?filter={"followerId":"<current-user-id>"}&limit=100

Step 2: Extract the followingIds

typescript
const followingIds = followsData.data.map(
  (f: { followingId: string }) => f.followingId
);

Step 3: Query posts from followed users

GET /v1/data/posts?filter={"authorId":{"$in":[...followingIds]}}&sort={"createdAt":-1}&limit=20

Complete Feed Implementation (Flutter + Riverpod):

dart
// lib/features/feed/providers/feed_provider.dart

final feedProvider = FutureProvider.autoDispose<List<Post>>((ref) async {
  final currentUserId = ref.read(authProvider).userId;
  final client = ref.read(bkendClientProvider);

  // Step 1: Get following list
  final followsRes = await client.get('/v1/data/follows', queryParameters: {
    'filter': '{"followerId":"$currentUserId"}',
    'limit': '100',
  });

  final followingIds = (followsRes.data['data'] as List)
      .map((f) => f['followingId'] as String)
      .toList();

  if (followingIds.isEmpty) return [];

  // Step 2: Get posts from followed users
  final idsJson = followingIds.map((id) => '"$id"').join(',');
  final postsRes = await client.get('/v1/data/posts', queryParameters: {
    'filter': '{"authorId":{"\$in":[$idsJson]}}',
    'sort': '{"createdAt":-1}',
    'limit': '20',
  });

  return (postsRes.data['data'] as List)
      .map((json) => Post.fromJson(json))
      .toList();
});

5.3 Counter Cache Pattern

Counter caches denormalize counts for performance. When a user likes a post, update both the likes table and the likesCount on the post.

dart
Future<void> toggleLike(String postId, String userId, bool isLiked) async {
  if (isLiked) {
    // Unlike: remove like record and decrement counter
    final likesRes = await client.get('/v1/data/likes', queryParameters: {
      'filter': '{"postId":"$postId","userId":"$userId"}',
    });
    final likeId = likesRes.data['data'][0]['_id'];
    await client.delete('/v1/data/likes/$likeId');

    // Decrement counter
    final post = await client.get('/v1/data/posts/$postId');
    final currentCount = post.data['data']['likesCount'] ?? 0;
    await client.put('/v1/data/posts/$postId', data: {
      'likesCount': currentCount - 1,
    });
  } else {
    // Like: create like record and increment counter
    await client.post('/v1/data/likes', data: {
      'postId': postId,
      'userId': userId,
    });

    final post = await client.get('/v1/data/posts/$postId');
    final currentCount = post.data['data']['likesCount'] ?? 0;
    await client.put('/v1/data/posts/$postId', data: {
      'likesCount': currentCount + 1,
    });
  }
}

5.4 AI Prompt Collection

> Create the social network schema with users, posts, comments, likes, and follows tables
> Build a Flutter feed screen with pull-to-refresh and infinite scroll
> Implement a like button with optimistic update and counter cache
> Create a user profile screen with follower/following counts
> Build a follow/unfollow toggle with real-time count update
> Generate a comment bottom sheet with auto-focus text input

6. Common Architecture Patterns

6.1 Next.js App Structure

app/
  (app)/                    # Authenticated layout group
    dashboard/
      page.tsx
    posts/
      page.tsx
      [id]/
        page.tsx
    settings/
      page.tsx
    layout.tsx              # App shell with sidebar + header
  (auth)/                   # Auth layout group
    login/
      page.tsx
    signup/
      page.tsx
    layout.tsx              # Minimal auth layout
  api/                      # API routes (if needed)
    webhooks/
      route.ts
  layout.tsx                # Root layout
  page.tsx                  # Landing page

application/
  dto/                      # Data Transfer Objects
    post.dto.ts
    user.dto.ts
    order.dto.ts
  hooks/
    queries/                # TanStack Query hooks
      use-posts.ts
      use-users.ts
      use-orders.ts
    mutations/              # TanStack Mutation hooks
      use-create-post.ts
      use-update-order.ts
  services/                 # Business logic
    order-state-machine.ts

infrastructure/
  api/
    client.ts               # bkendFetch wrapper
    endpoints.ts             # API endpoint constants
  auth/
    middleware.ts            # Auth middleware
    session.ts               # Session helpers

components/
  ui/                        # Radix UI primitives
  shared/                    # Shared components
  features/                  # Feature-specific components

6.2 Flutter App Structure

lib/
  core/
    network/
      bkend_client.dart      # Dio client setup
      auth_interceptor.dart   # Token refresh interceptor
      endpoints.dart          # API endpoint constants
    constants/
      app_constants.dart
    theme/
      app_theme.dart
    utils/
      validators.dart

  features/
    auth/
      data/
        auth_repository.dart
      models/
        user_model.dart
      presentation/
        login_screen.dart
        signup_screen.dart
      providers/
        auth_provider.dart

    feed/
      data/
        feed_repository.dart
      models/
        post_model.dart
      presentation/
        feed_screen.dart
        post_card.dart
      providers/
        feed_provider.dart

    profile/
      data/
        profile_repository.dart
      models/
        profile_model.dart
      presentation/
        profile_screen.dart
      providers/
        profile_provider.dart

  shared/
    widgets/
      loading_indicator.dart
      error_widget.dart
      empty_state.dart
    extensions/
      string_extensions.dart
      date_extensions.dart

  app.dart                    # MaterialApp with router
  main.dart                   # Entry point

7. Key Implementation Patterns

Pattern 1: bkendFetch Wrapper

Centralized API client that handles headers, auth tokens, and error formatting.

typescript
// infrastructure/api/client.ts
export async function bkendFetch<T = any>(
  path: string,
  options: BkendFetchOptions = {}
): Promise<{ success: boolean; data: T; meta?: any }> {
  const { token, headers: customHeaders, ...rest } = options;
  const headers: Record<string, string> = {
    "Content-Type": "application/json",
    "X-Project-Id": process.env.NEXT_PUBLIC_BKEND_PROJECT_ID!,
    "X-Environment": process.env.NEXT_PUBLIC_BKEND_ENVIRONMENT!,
    ...customHeaders as Record<string, string>,
  };
  if (typeof window === "undefined" && process.env.BKEND_API_KEY) {
    headers["X-API-Key"] = process.env.BKEND_API_KEY;
  }
  if (token) {
    headers["Authorization"] = `Bearer ${token}`;
  }
  const res = await fetch(
    `${process.env.NEXT_PUBLIC_BKEND_API_URL}${path}`,
    { headers, ...rest }
  );
  if (!res.ok) {
    const error = await res.json();
    throw new Error(error.error?.message || "bkend API error");
  }
  return res.json();
}

Pattern 2: Mock Mode Toggle

Switch between real API and mock data for offline development.

typescript
// infrastructure/api/client.ts
const USE_MOCK = process.env.NEXT_PUBLIC_USE_MOCK === "true";

export async function bkendFetch<T>(path: string, options?: BkendFetchOptions): Promise<T> {
  if (USE_MOCK) {
    const { getMockData } = await import("@/mocks/handlers");
    return getMockData<T>(path, options);
  }
  // ... real fetch implementation
}

Pattern 3: DTO Layer

Transform API responses into typed application objects.

typescript
// application/dto/post.dto.ts
export interface PostDTO {
  _id: string;
  title: string;
  content: string;
  authorId: string;
  status: "draft" | "published";
  tags: string[];
  createdAt: string;
  updatedAt: string;
}

export interface CreatePostDTO {
  title: string;
  content: string;
  authorId: string;
  status: "draft" | "published";
  tags?: string[];
}

export function toPost(dto: PostDTO): Post {
  return {
    id: dto._id,
    title: dto.title,
    content: dto.content,
    authorId: dto.authorId,
    status: dto.status,
    tags: dto.tags ?? [],
    createdAt: new Date(dto.createdAt),
    updatedAt: new Date(dto.updatedAt),
  };
}

Pattern 4: Query Key Factory

Organized query keys for TanStack Query cache management.

typescript
// application/hooks/queries/query-keys.ts
export const postKeys = {
  all: ["posts"] as const,
  lists: () => [...postKeys.all, "list"] as const,
  list: (filters: PostFilters) => [...postKeys.lists(), filters] as const,
  details: () => [...postKeys.all, "detail"] as const,
  detail: (id: string) => [...postKeys.details(), id] as const,
};

// Usage:
// queryClient.invalidateQueries({ queryKey: postKeys.lists() });

Pattern 5: Counter Cache

Maintain denormalized counts to avoid expensive aggregate queries.

typescript
// When creating a comment, also update the post's commentsCount
await bkendFetch("/v1/data/comments", {
  method: "POST",
  body: JSON.stringify({ content, postId, authorId }),
});

const post = await bkendFetch(`/v1/data/posts/${postId}`);
await bkendFetch(`/v1/data/posts/${postId}`, {
  method: "PUT",
  body: JSON.stringify({
    commentsCount: (post.data.commentsCount ?? 0) + 1,
  }),
});

Pattern 6: Order State Machine

See Section 4.2 for the full order state machine implementation.

Pattern 7: Optimistic Updates

Update the UI before the server confirms, then rollback on error.

typescript
// application/hooks/mutations/use-toggle-like.ts
export function useToggleLike(postId: string) {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (isLiked: boolean) => toggleLikeAPI(postId, isLiked),
    onMutate: async (isLiked) => {
      await queryClient.cancelQueries({ queryKey: postKeys.detail(postId) });
      const previous = queryClient.getQueryData(postKeys.detail(postId));
      queryClient.setQueryData(postKeys.detail(postId), (old: any) => ({
        ...old,
        likesCount: old.likesCount + (isLiked ? -1 : 1),
        isLiked: !isLiked,
      }));
      return { previous };
    },
    onError: (_err, _vars, context) => {
      queryClient.setQueryData(postKeys.detail(postId), context?.previous);
    },
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: postKeys.detail(postId) });
    },
  });
}

Pattern 8: Image Upload with Preview

Upload images to bkend storage with client-side preview.

typescript
export function useImageUpload() {
  const [preview, setPreview] = useState<string | null>(null);

  const handleUpload = async (file: File): Promise<string> => {
    // Client-side preview
    const reader = new FileReader();
    reader.onload = (e) => setPreview(e.target?.result as string);
    reader.readAsDataURL(file);

    // Upload to bkend storage
    const formData = new FormData();
    formData.append("file", file);
    const res = await fetch(
      `${process.env.NEXT_PUBLIC_BKEND_API_URL}/v1/storage/upload`,
      {
        method: "POST",
        headers: {
          "X-Project-Id": process.env.NEXT_PUBLIC_BKEND_PROJECT_ID!,
          "X-Environment": process.env.NEXT_PUBLIC_BKEND_ENVIRONMENT!,
        },
        body: formData,
      }
    );
    const data = await res.json();
    return data.data.url;
  };

  return { preview, handleUpload };
}

Pattern 9: Infinite Scroll Pagination

Cursor-based pagination for feeds and lists.

typescript
// application/hooks/queries/use-posts-infinite.ts
export function usePostsInfinite(filters?: PostFilters) {
  return useInfiniteQuery({
    queryKey: postKeys.list(filters ?? {}),
    queryFn: async ({ pageParam }) => {
      const params = new URLSearchParams();
      params.set("limit", "20");
      if (pageParam) params.set("cursor", pageParam);
      if (filters?.status) {
        params.set("filter", JSON.stringify({ status: filters.status }));
      }
      params.set("sort", JSON.stringify({ createdAt: -1 }));

      return bkendFetch<PostsResponse>(
        `/v1/data/posts?${params.toString()}`
      );
    },
    initialPageParam: undefined as string | undefined,
    getNextPageParam: (lastPage) => lastPage.meta?.nextCursor ?? undefined,
  });
}

Pattern 10: Real-time Subscription (Planned)

Note: Real-time subscriptions are planned for a future bkend.ai release.

typescript
// Planned API (not yet available)
// const unsubscribe = bkend.subscribe("posts", {
//   filter: { status: "published" },
//   onInsert: (post) => queryClient.invalidateQueries(postKeys.lists()),
//   onUpdate: (post) => queryClient.invalidateQueries(postKeys.detail(post._id)),
//   onDelete: (id) => queryClient.invalidateQueries(postKeys.lists()),
// });

Pattern 11: Auth Middleware

See the bkend-quickstart skill for the full Next.js middleware implementation. Key points:

  • Check for bkend_access_token cookie
  • Auto-refresh using bkend_refresh_token when access token expires
  • Redirect to /login for unauthenticated requests
  • Skip auth for public routes

Pattern 12: Error Boundary

Catch and display errors gracefully at the component level.

typescript
// components/shared/error-boundary.tsx
"use client";
import { useQueryErrorResetBoundary } from "@tanstack/react-query";
import { ErrorBoundary as ReactErrorBoundary } from "react-error-boundary";

export function QueryErrorBoundary({ children }: { children: React.ReactNode }) {
  const { reset } = useQueryErrorResetBoundary();
  return (
    <ReactErrorBoundary
      onReset={reset}
      fallbackRender={({ error, resetErrorBoundary }) => (
        <div className="flex flex-col items-center gap-4 p-8">
          <p className="text-red-500">Something went wrong: {error.message}</p>
          <button onClick={resetErrorBoundary} className="btn btn-primary">
            Try Again
          </button>
        </div>
      )}
    >
      {children}
    </ReactErrorBoundary>
  );
}

Pattern 13: Loading Skeleton

Display placeholder UI while data is loading.

typescript
// components/shared/post-skeleton.tsx
export function PostSkeleton() {
  return (
    <div className="animate-pulse space-y-3 p-4 border rounded-lg">
      <div className="flex items-center gap-3">
        <div className="w-10 h-10 bg-gray-200 rounded-full" />
        <div className="h-4 bg-gray-200 rounded w-24" />
      </div>
      <div className="h-4 bg-gray-200 rounded w-full" />
      <div className="h-4 bg-gray-200 rounded w-3/4" />
      <div className="h-32 bg-gray-200 rounded w-full" />
    </div>
  );
}

Pattern 14: Form Validation (Zod)

Schema-based validation for forms.

typescript
// application/dto/post.dto.ts
import { z } from "zod";

export const createPostSchema = z.object({
  title: z.string().min(1, "Title is required").max(200, "Title too long"),
  content: z.string().min(1, "Content is required"),
  status: z.enum(["draft", "published"]),
  tags: z.array(z.string()).max(10, "Maximum 10 tags").optional(),
});

export type CreatePostInput = z.infer<typeof createPostSchema>;

// Usage with react-hook-form:
// const form = useForm<CreatePostInput>({
//   resolver: zodResolver(createPostSchema),
// });

Pattern 15: Search Debounce

Debounce search input to reduce API calls.

typescript
// application/hooks/use-debounced-search.ts
import { useState, useEffect } from "react";

export function useDebouncedSearch(delay = 300) {
  const [searchTerm, setSearchTerm] = useState("");
  const [debouncedTerm, setDebouncedTerm] = useState("");

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedTerm(searchTerm), delay);
    return () => clearTimeout(timer);
  }, [searchTerm, delay]);

  return { searchTerm, setSearchTerm, debouncedTerm };
}

// Usage:
// const { searchTerm, setSearchTerm, debouncedTerm } = useDebouncedSearch();
// const { data } = useQuery({
//   queryKey: ["posts", "search", debouncedTerm],
//   queryFn: () => bkendFetch(`/v1/data/posts?filter={"title":{"$regex":"${debouncedTerm}"}}`),
//   enabled: debouncedTerm.length > 0,
// });

8. Dependencies

Next.js Projects

PackageVersionPurpose
next16+React framework with App Router
react19+UI library
@tanstack/react-query5Server state management
zustand5+Client state management
@radix-ui/react-*latestAccessible UI primitives
tailwindcss4Utility-first CSS
zod3+Schema validation
react-hook-form7+Form state management
@hookform/resolvers3+Zod integration for react-hook-form
date-fns4+Date utility library
lucide-reactlatestIcon library

Flutter Projects

PackageVersionPurpose
dio5+HTTP client
riverpod2+State management
flutter_riverpod2+Flutter bindings for Riverpod
go_router14+Declarative routing
flutter_secure_storage9+Secure token storage
cached_network_image3+Image caching
intl0.19+Internationalization
json_annotation4+JSON serialization
freezed_annotation2+Immutable data classes

9. Quick Reference

API Endpoints Used Across Projects

OperationMethodEndpoint
List recordsGET/v1/data/{table}
Get recordGET/v1/data/{table}/{id}
Create recordPOST/v1/data/{table}
Update recordPUT/v1/data/{table}/{id}
Delete recordDELETE/v1/data/{table}/{id}
Upload filePOST/v1/storage/upload
Register userPOST/v1/auth/register
LoginPOST/v1/auth/login
Refresh tokenPOST/v1/auth/token/refresh

Query Parameters

ParameterExampleDescription
filter{"status":"published"}MongoDB-style filter
sort{"createdAt":-1}Sort order (1=asc, -1=desc)
limit20Max records per page (max 100)
cursorabc123Cursor for pagination
selecttitle,contentFields to include

Next Steps

After completing a cookbook project, consider these skills for deeper topics:

SkillWhen to Use
/bkend-authImplement email/social login, JWT, MFA
/bkend-dataAdvanced queries, relations, aggregations
/bkend-securityRLS policies, rate limiting, CORS
/bkend-mcpMCP tool reference and advanced usage
/bkend-guidesMigration, troubleshooting, performance tips

Frequently asked questions

What does the Bkend Cookbook AI skill do?

bkend.ai practical project tutorials and troubleshooting guide. Covers 4 full-guide projects (blog, recipe-app, shopping-mall, social-network) with step-by-step implementation patterns including schema design, architecture patterns, and AI prompt collections. Triggers: cookbook, tutorial, example project, todo app, blog app, shopping mall, 쿡북, 튜토리얼, 예제, 블로그, 쇼핑몰, 투두, 프로젝트 만들기, クックブック, チュートリアル, 例題, ブログ, ショッピング, 食谱, 教程, 示例, 博客, 商城, libro de cocina, tutorial, ejemplo, blog, tienda, livre de recettes, tutoriel, exemple, blog, boutique, Kochbuch, Tutorial, Beispiel, Blog, Shop, ricettario, tutor...

Why use Bkend Cookbook on TypingMind?

Because you install it once and use it with any model. Bkend Cookbook is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Bkend Cookbook in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/ww-w-ai/bkit-gemini/tree/main/skills/bkend-cookbook. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Bkend Cookbook?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Bkend Cookbook?

As many as you like. As long as a model supports skills, you can use Bkend Cookbook with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Bkend Cookbook AI skill free?

Yes. It is published on GitHub by ww-w-ai under the Apache-2.0 license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇