diff --git a/src/pages/agent-office/components/AgentCard.jsx b/src/pages/agent-office/components/AgentCard.jsx
new file mode 100644
index 0000000..50e1089
--- /dev/null
+++ b/src/pages/agent-office/components/AgentCard.jsx
@@ -0,0 +1,30 @@
+// src/pages/agent-office/components/AgentCard.jsx
+import { AGENT_META, STATE_COLORS, DEFAULT_STATE_COLOR } from '../constants.js';
+
+export default function AgentCard({ agentId, agentState, notificationCount = 0, active = false, onClick }) {
+ const meta = AGENT_META[agentId];
+ if (!meta) return null;
+
+ const state = agentState?.state || 'idle';
+ const stateInfo = STATE_COLORS[state] || DEFAULT_STATE_COLOR;
+ const dotClass = `ao-card-dot ${state}${stateInfo.pulse ? ' pulse' : ''}`;
+ const badgeText = notificationCount > 9 ? '9+' : String(notificationCount);
+
+ return (
+
+ );
+}
diff --git a/src/pages/agent-office/components/AgentCard.test.jsx b/src/pages/agent-office/components/AgentCard.test.jsx
new file mode 100644
index 0000000..2d51148
--- /dev/null
+++ b/src/pages/agent-office/components/AgentCard.test.jsx
@@ -0,0 +1,60 @@
+// src/pages/agent-office/components/AgentCard.test.jsx
+import { describe, it, expect, vi } from 'vitest';
+import { render, screen, fireEvent } from '@testing-library/react';
+import AgentCard from './AgentCard.jsx';
+
+describe('AgentCard', () => {
+ it('에이전트의 displayName을 표시', () => {
+ render( {}} />);
+ expect(screen.getByText('주식 트레이더')).toBeInTheDocument();
+ });
+
+ it('working 상태일 때 dot에 working 클래스 부여', () => {
+ const { container } = render(
+ {}} />
+ );
+ const dot = container.querySelector('.ao-card-dot');
+ expect(dot).toHaveClass('working');
+ });
+
+ it('agentState 없으면 idle로 fallback', () => {
+ const { container } = render(
+ {}} />
+ );
+ const dot = container.querySelector('.ao-card-dot');
+ expect(dot).toHaveClass('idle');
+ });
+
+ it('notificationCount > 0이면 뱃지 표시', () => {
+ render( {}} />);
+ expect(screen.getByText('3')).toBeInTheDocument();
+ });
+
+ it('notificationCount === 0이면 뱃지 없음', () => {
+ const { container } = render(
+ {}} />
+ );
+ expect(container.querySelector('.ao-card-badge')).toBeNull();
+ });
+
+ it('notificationCount > 9이면 9+ 표시', () => {
+ render( {}} />);
+ expect(screen.getByText('9+')).toBeInTheDocument();
+ });
+
+ it('클릭 시 onClick 호출', () => {
+ const onClick = vi.fn();
+ const { container } = render(
+
+ );
+ fireEvent.click(container.querySelector('.ao-card'));
+ expect(onClick).toHaveBeenCalledTimes(1);
+ });
+
+ it('active prop 시 카드에 active 클래스 부여', () => {
+ const { container } = render(
+ {}} />
+ );
+ expect(container.querySelector('.ao-card')).toHaveClass('active');
+ });
+});