신규 및 기존 React, Next.js 프로젝트에 공통으로 적용할 수 있는 개발 지침을 제공합니다.
원제 · Universal Instructions for React / Next.js Projects
# Universal Instructions for React / Next.js Projects
> Purpose: General rules for developing various projects with React + TypeScript, Next.js + TypeScript, and Tailwind CSS.
> Usage: Place this file in the root of a new project as `AGENTS.md`, `CLAUDE.md`, or `PROJECT_RULES.md`, or use it as a base instruction set for an AI agent.
> Important: These instructions do not contain product-specific rules. Keep everything related to an individual project in a separate `PROJECT_RULES.md` file.
---
# 1. Core Principle
Build a production-ready application, not a collection of disconnected components.
Always follow this sequence:
1. Review the current project structure, `package.json`, routing, UI primitives, stores, hooks, schemas, and project rules.
2. Find existing actions, helpers, schemas, and components that can be reused.
3. Identify the smallest change required for the task.
4. Preserve existing behavior.
5. Implement each new feature end to end: model, validation, UI, storage/import/export, edge cases, and verification.
6. Run the relevant checks and report the results honestly.
Do not add dependencies, abstractions, a global store, or an architectural layer unless they are genuinely necessary.
Use `shadcn/ui` by default for UI work. Do not add another UI kit on top of it without a clear reason.
---
# 2. Choosing Between React and Next.js
Use Next.js when the project needs:
- routing;
- SEO;
- SSR / Server Components;
- Server Actions;
- Route Handlers / API routes;
- authentication;
- database access;
- private environment variables;
- content publishing.
Use React + Vite when:
- the application is entirely client-side;
- SEO is not required;
- it is a local tool, dashboard, editor, admin panel, or desktop-like UI;
- the server already exists as a separate service.
Do not choose Next.js simply because it is popular. Do not add Redux, Zustand, React Query, a form library, or another UI kit without a specific reason.
---
# 3. Default Stack and Checks
Use the following by default:
- React;
- TypeScript in strict mode;
- Tailwind CSS;
- `shadcn/ui` as the required UI approach for clean design and rapid interface development;
- Lucide React or the icon library used by the current shadcn configuration;
- ESLint;
- a shared `cn()` helper;
- runtime validation for external data;
- accessible HTML elements.
Use `shadcn/ui` as the primary source of UI primitives: buttons, inputs, selects, dialogs, sheets, dropdowns, tooltips, tabs, carousels, cards, badges, skeletons, scroll areas, and other required components. Create custom primitives only when shadcn does not provide a suitable component or when the project already has a stable local primitive.
For an MVP, begin with mock/JSON/localStorage data and validate local user flows first. Add the backend, database, payments, authentication, and external integrations last, once the UI, models, and flows are clear.
At a minimum, run these commands after code changes:
```bash
npm run typecheck
npm run lint
npm run build
```
Do not claim that the project works if these commands were not run or completed with errors.
---
# 4. Architecture
For Next.js projects expected to grow, keep source code inside `src/` by default: `src/app`, `src/components`, `src/lib`, `src/data`, `src/hooks`, and `src/features`. Keep root-level support folders and files (`public`, configuration files, lockfiles, and README) in the project root.
For small projects, the following structure is acceptable:
```text
src/
app/ or pages/
components/
features/
lib/
shared/
```
For medium and large projects, use an FSD-like approach:
```text
src/
app/ # bootstrap, providers, layouts, routes
views/ # page-level composition
widgets/ # large UI blocks
features/ # user workflows
entities/ # domain model
shared/ # generic helpers, config, thin wrappers around shadcn/ui
```
Import direction:
```text
app/views -> widgets -> features -> entities -> shared
```
Do not:
- import `widgets` into `features`;
- place business logic in `shared`;
- turn `shared/lib` into a dumping ground for unrelated functions;
- duplicate mutation logic across multiple UI components;
- use deep imports into another module's internals when that module exposes a public API.
---
# 5. Public API
Every feature, entity, or shared UI folder should expose a clear public API through `index.ts` when the module is used externally. For shadcn primitives, the public API usually already lives in `components/ui/*` or the project's local UI layer.
Good:
```ts
import { createTask } from "@/features/create-task";
```
Bad:
```ts
import { createTask } from "@/features/create-task/model/createTask";
```
Exception: internal code within the same feature or entity.
---
# 6. TypeScript
Required:
- enable `strict: true`;
- do not use `any` except in isolated interoperability code;
- do not hide type errors with `as` assertions;
- use discriminated unions for complex state;
- validate runtime JSON with a schema;
- do not create multiple identical types without a meaningful reason.
Example state type:
```ts
type LoadState<T> =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: T }
| { status: "error"; message: string };
```
---
# 7. React State and Effects
Store state where it actually belongs:
| State type | Where to store it |
| ------------ | ----------------------------------------------------------- |
| Local UI | `useState`, `useReducer` |
| URL state | route/search parameters |
| Server state | server rendering or a cache/query layer |
| Form state | form hook/library |
| Global UI | a small store when necessary |
| Domain state | entity/store when the state is shared across multiple flows |
Do not put the following in a global store:
- hover state;
- the state of a single dropdown;
- the draft value of a single input;
- the state of a single modal;
- the temporary selected tab of one component.
Use `useEffect` to synchronize with external systems:
- browser APIs;
- timers;
- subscriptions;
- external stores;
- DOM integrations.
Do not use `useEffect` for derived values.
Bad:
```tsx
const [fullName, setFullName] = useState("");
useEffect(() => {
setFullName(`${firstName} ${lastName}`);
}, [firstName, lastName]);
```
Good:
```tsx
const fullName = `${firstName} ${lastName}`;
```
---
# 8. Next.js Boundaries
In the App Router, components are Server Components by default.
Add `"use client"` only where you need:
- event handlers;
- local state;
- effects;
- `window`, `document`, or `localStorage`;
- drag and drop;
- `contenteditable`;
- client-only libraries.
Do not make an entire layout a Client Component without a clear need.
Server-only code includes:
- database access;
- authentication;
- private API clients;
- secret environment variables;
- webhooks;
- access checks.
Never import a server-only module into a Client Component.
---
# 9. Runtime Validation and Migrations
Validate all external data at the boundary:
- request bodies;
- form data;
- URL/search parameters;
- uploaded files;
- imported JSON;
- localStorage/IndexedDB data;
- responses from external APIs.
When adding a new model field, update the entire lifecycle:
1. TypeScript type.
2. Runtime schema.
3. Factory/default values.
4. Parser/migration for legacy data.
5. Normalization helpers.
6. Import/export.
7. Search/filter indexing, if the field should be searchable.
8. Undo/redo snapshots, if users can edit the field.
9. UI for creating, editing, and clearing the field.
10. Edge cases and checks.
Example:
```ts
return {
...item,
status: item.status ?? "active",
tags: normalizeTags(item.tags),
dueDate: normalizeDate(item.dueDate),
};
```
Do not add a model field only in the UI.
---
# 10. Forms
Every form must include:
- a validation schema;
- field errors;
- a submitting/loading state;
- a disabled submit button while submitting;
- protection against duplicate submissions;
- an error state;
- success behavior;
- reset/draft behavior, when applicable.
A form is not complete if it works only when the request succeeds perfectly.
---
# 11. shadcn/ui and Shared UI
Use `shadcn/ui` by default to build clean, consistent interfaces quickly.
Rules:
- first check whether the required component exists in the shadcn registry;
- add shadcn components through the CLI or the project's established local method;
- do not create a custom Button, Input, Modal, Dropdown, Tooltip, Tabs, or Card if shadcn already covers the use case;
- adapt shadcn components through `className`, variants, and composition instead of copying similar components;
- keep business components separate from primitives: `components/marketplace`, `features/*/ui`, `widgets/*`, or `entities/*/ui`;
- keep only shadcn primitives and thin reusable wrappers in `components/ui` or `shared/ui`;
- do not place product-specific business components there;
- if shadcn does not provide a component, create a minimal local wrapper consistent with the current shadcn configuration.
Base set of shadcn components for productivity interfaces:
```text
button
input
select
textarea
checkbox
switch
dialog
sheet
dropdown-menu
popover
tooltip
tabs
card
badge
avatar
separator
scroll-area
skeleton
carousel
accordion
collapsible
hover-card
```
For marketplace, chat, and support flows, also plan for these newer shadcn components:
```text
message
message-scroller
attachment
marker
```
Always use `cn()`:
```ts
export function cn(...values: Array<string | false | null | undefined>) {
return values.filter(Boolean).join(" ");
}
```
---
# 12. Choosing the Right UI Surface
Before adding a new tool, choose the right surface:
| Feature size | Placement | Example |
| ---------------------------------- | --------------------------------- | ----------------------------------- |
| 1-5 quick settings | context menu / dropdown / popover | status, due date, tags |
| 5-12 grouped settings | sectioned, scrollable popover | entity properties, compact filters |
| large data sets or bulk actions | sidebar / drawer | filters, tools panel |
| complex form or dangerous action | modal | import/export, delete confirmation |
| permanent workspace | dedicated view/page/widget | dashboard, calendar, editor |
Rule:
> If a control is used occasionally, keep it in a menu.
> If a control is used constantly, keep it visible on the main surface.
> If a control is complex and lengthy, move it to a sidebar or modal.
Do not turn a small group of controls into a large card on the page. In productivity interfaces, this wastes valuable space.
---
# 13. Compact UI for Editors, Dashboards, and Workspaces
In productivity applications, the primary content must remain the focus.
Required:
- the title, body, board, or editor must not be pushed downward by secondary controls;
- entity properties should generally open from an icon button next to the title;
- settings buttons must have an `aria-label`;
- an important status can be shown as a small badge;
- create/add actions must appear in a clear context;
- sidebar-heavy flows must include a mobile-friendly menu or switcher;
- do not make a productivity tool look like a landing page.
Bad:
```tsx
${largepropertiescard}
<Select>Status</Select>
<Select>Task</Select>
<Input>Date</Input>
<Input>Tags</Input>
</LargePropertiesCard>
```
Good:
```tsx
${titlerow}
<TitleInput />
<PropertiesMenu />
</TitleRow>
```
---
# 14. Overlays, Dropdowns, Popovers, and Context Menus
Every menu must behave as a true overlay.
Rules:출처 · prompts.chat 공개 프롬프트 모음 · 작성 Ramazan — CC0(저작권 포기)로 공개된 원문을 그대로 싣습니다. 한국어 제목 · 설명은 AI 번역이며, 실행 결과는 아직 없습니다.