How to Build a Notification System with Claude Code
Learn how to build a notification system using Claude Code. Includes practical code examples and step-by-step guidance.
通知システムの構築をClaude Codeで効率化する
Webアプリにおける通知は、トースト表示からプッシュ通知、リアルタイム更新まで多岐にわたります。Claude Codeを使えば、これらを統合した通知基盤を短時間で構築できます。
トースト通知コンポーネントの実装
まずはアプリ内で使うトースト通知を作ります。
> ライブラリを使わずにトースト通知コンポーネントをReactで作って。
> success/error/warning/infoの4種類。自動で消える。スタック表示対応。
import { createContext, useContext, useState, useCallback, type ReactNode } from "react";
type ToastType = "success" | "error" | "warning" | "info";
interface Toast {
id: string;
type: ToastType;
message: string;
}
interface ToastContextType {
addToast: (type: ToastType, message: string) => void;
}
const ToastContext = createContext<ToastContextType | null>(null);
const TOAST_STYLES: Record<ToastType, string> = {
success: "bg-green-500 text-white",
error: "bg-red-500 text-white",
warning: "bg-yellow-500 text-black",
info: "bg-blue-500 text-white",
};
const TOAST_ICONS: Record<ToastType, string> = {
success: "✓",
error: "✕",
warning: "⚠",
info: "ℹ",
};
export function ToastProvider({ children }: { children: ReactNode }) {
const [toasts, setToasts] = useState<Toast[]>([]);
const addToast = useCallback((type: ToastType, message: string) => {
const id = crypto.randomUUID();
setToasts((prev) => [...prev, { id, type, message }]);
setTimeout(() => {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, 4000);
}, []);
return (
<ToastContext.Provider value={{ addToast }}>
{children}
<div className="fixed bottom-4 right-4 flex flex-col gap-2 z-50">
{toasts.map((toast) => (
<div
key={toast.id}
className={`px-4 py-3 rounded-lg shadow-lg flex items-center gap-2 animate-slide-in ${TOAST_STYLES[toast.type]}`}
>
<span>{TOAST_ICONS[toast.type]}</span>
<span>{toast.message}</span>
<button
onClick={() => setToasts((prev) => prev.filter((t) => t.id !== toast.id))}
className="ml-2 opacity-70 hover:opacity-100"
>
✕
</button>
</div>
))}
</div>
</ToastContext.Provider>
);
}
export function useToast() {
const context = useContext(ToastContext);
if (!context) throw new Error("useToast must be used within ToastProvider");
return context;
}
WebSocketによるリアルタイム通知
サーバーからのリアルタイム通知を受け取る仕組みも構築できます。
// Server side(Node.js + ws)
import { WebSocketServer, WebSocket } from "ws";
interface Client {
ws: WebSocket;
userId: string;
}
const clients: Client[] = [];
const wss = new WebSocketServer({ port: 8080 });
wss.on("connection", (ws, req) => {
const userId = new URL(req.url!, `http://${req.headers.host}`).searchParams.get("userId");
if (!userId) return ws.close();
clients.push({ ws, userId });
ws.on("close", () => {
const index = clients.findIndex((c) => c.ws === ws);
if (index !== -1) clients.splice(index, 1);
});
});
// 特定ユーザーへの通知送信
export function sendNotification(userId: string, notification: object) {
clients
.filter((c) => c.userId === userId)
.forEach((c) => c.ws.send(JSON.stringify(notification)));
}
// Client sideのフック
import { useEffect, useRef, useCallback } from "react";
interface Notification {
id: string;
type: string;
title: string;
body: string;
}
export function useNotifications(userId: string, onNotification: (n: Notification) => void) {
const wsRef = useRef<WebSocket | null>(null);
const connect = useCallback(() => {
const ws = new WebSocket(`ws://localhost:8080?userId=${userId}`);
ws.onmessage = (event) => {
const notification = JSON.parse(event.data);
onNotification(notification);
};
ws.onclose = () => {
setTimeout(connect, 3000); // Reconnect
};
wsRef.current = ws;
}, [userId, onNotification]);
useEffect(() => {
connect();
return () => wsRef.current?.close();
}, [connect]);
}
通知の永続化と既読管理
通知をDBに保存して既読管理する機能も追加できます。
// Prismaスキーマから自動でAPI生成を依頼
// schema.prisma の内容をClaude Codeが読み取って実装
import { db } from "@/lib/database";
export async function getNotifications(userId: string) {
return db.notification.findMany({
where: { userId },
orderBy: { createdAt: "desc" },
take: 50,
});
}
export async function markAsRead(notificationId: string) {
return db.notification.update({
where: { id: notificationId },
data: { readAt: new Date() },
});
}
export async function getUnreadCount(userId: string) {
return db.notification.count({
where: { userId, readAt: null },
});
}
Claude Codeでの開発効率を上げるには生産性を3倍にする10のTipsを参考にしてください。フォームとの連携についてはフォームバリデーション設計も併せてご覧ください。
Summary
Claude Codeを使えば、トースト通知、リアルタイム通知、永続化まで含めた通知システム全体を効率的に構築できます。自然言語で要件を伝え、段階的に機能を追加していくのがおすすめです。
公式ドキュメントはClaude Codeから確認できます。
Free PDF: Claude Code Cheatsheet in 5 Minutes
Just enter your email and we'll send you the single-page A4 cheatsheet right away.
We handle your data with care and never send spam.
Level up your Claude Code workflow
50 battle-tested prompt templates you can copy-paste into Claude Code right now.
About the Author
Masa
Engineer obsessed with Claude Code. Runs claudecode-lab.com, a 10-language tech media with 2,000+ pages.
Related Posts
Safe Agent Harness Design for Claude Code and Codex: Permissions, Checks, and Rollback
Build a practical agent harness for Claude Code and Codex with policy, planning, verification, and recovery layers.
10 Powerful Subagent Patterns for Claude Code
Master Claude Code's subagent feature with 10 practical patterns. Learn how to use parallel processing, specialization, and context isolation to double your development speed.
Getting Started with Claude Code Agent SDK — Build Autonomous Agents Fast
Learn how to build autonomous AI agents with Claude Code Agent SDK. Covers setup, tool definitions, and multi-step execution with practical code examples.
Related Products
50 Battle-Tested Claude Code Prompt Templates
Copy, paste, ship. 50 production-ready prompts.
Use proven prompts for code review, refactoring, testing, documentation, debugging, architecture, and incident response.
The Complete Claude Code Setup & Configuration Guide
From install to team-ready workflow.
A practical guide to installation, CLAUDE.md, hooks, MCP servers, permissions, IDE setup, and CI/CD workflows.