timsquad 2.0.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +168 -234
- package/dist/commands/daemon.d.ts +7 -0
- package/dist/commands/daemon.d.ts.map +1 -0
- package/dist/commands/daemon.js +140 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/feedback.d.ts +9 -0
- package/dist/commands/feedback.d.ts.map +1 -1
- package/dist/commands/feedback.js +251 -11
- package/dist/commands/feedback.js.map +1 -1
- package/dist/commands/full.js +2 -2
- package/dist/commands/full.js.map +1 -1
- package/dist/commands/git/commit.d.ts.map +1 -1
- package/dist/commands/git/commit.js +1 -4
- package/dist/commands/git/commit.js.map +1 -1
- package/dist/commands/improve.d.ts +3 -0
- package/dist/commands/improve.d.ts.map +1 -0
- package/dist/commands/improve.js +286 -0
- package/dist/commands/improve.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +110 -22
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/knowledge.d.ts +3 -0
- package/dist/commands/knowledge.d.ts.map +1 -0
- package/dist/commands/knowledge.js +316 -0
- package/dist/commands/knowledge.js.map +1 -0
- package/dist/commands/log.d.ts +27 -0
- package/dist/commands/log.d.ts.map +1 -1
- package/dist/commands/log.js +1167 -2
- package/dist/commands/log.js.map +1 -1
- package/dist/commands/meta-index.d.ts +3 -0
- package/dist/commands/meta-index.d.ts.map +1 -0
- package/dist/commands/meta-index.js +401 -0
- package/dist/commands/meta-index.js.map +1 -0
- package/dist/commands/metrics.d.ts.map +1 -1
- package/dist/commands/metrics.js +640 -100
- package/dist/commands/metrics.js.map +1 -1
- package/dist/commands/retro.d.ts.map +1 -1
- package/dist/commands/retro.js +606 -58
- package/dist/commands/retro.js.map +1 -1
- package/dist/commands/session.d.ts +3 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +346 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/upgrade.d.ts +8 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +287 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/workflow.d.ts +3 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/commands/workflow.js +607 -0
- package/dist/commands/workflow.js.map +1 -0
- package/dist/daemon/context-writer.d.ts +16 -0
- package/dist/daemon/context-writer.d.ts.map +1 -0
- package/dist/daemon/context-writer.js +35 -0
- package/dist/daemon/context-writer.js.map +1 -0
- package/dist/daemon/entry.d.ts +7 -0
- package/dist/daemon/entry.d.ts.map +1 -0
- package/dist/daemon/entry.js +17 -0
- package/dist/daemon/entry.js.map +1 -0
- package/dist/daemon/event-queue.d.ts +52 -0
- package/dist/daemon/event-queue.d.ts.map +1 -0
- package/dist/daemon/event-queue.js +255 -0
- package/dist/daemon/event-queue.js.map +1 -0
- package/dist/daemon/file-watcher.d.ts +19 -0
- package/dist/daemon/file-watcher.d.ts.map +1 -0
- package/dist/daemon/file-watcher.js +87 -0
- package/dist/daemon/file-watcher.js.map +1 -0
- package/dist/daemon/index.d.ts +28 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +204 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/jsonl-watcher.d.ts +49 -0
- package/dist/daemon/jsonl-watcher.d.ts.map +1 -0
- package/dist/daemon/jsonl-watcher.js +258 -0
- package/dist/daemon/jsonl-watcher.js.map +1 -0
- package/dist/daemon/meta-cache.d.ts +62 -0
- package/dist/daemon/meta-cache.d.ts.map +1 -0
- package/dist/daemon/meta-cache.js +240 -0
- package/dist/daemon/meta-cache.js.map +1 -0
- package/dist/daemon/shutdown.d.ts +21 -0
- package/dist/daemon/shutdown.d.ts.map +1 -0
- package/dist/daemon/shutdown.js +158 -0
- package/dist/daemon/shutdown.js.map +1 -0
- package/dist/index.js +24 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-composer.d.ts +38 -0
- package/dist/lib/agent-composer.d.ts.map +1 -0
- package/dist/lib/agent-composer.js +128 -0
- package/dist/lib/agent-composer.js.map +1 -0
- package/dist/lib/agent-generator.d.ts +22 -0
- package/dist/lib/agent-generator.d.ts.map +1 -0
- package/dist/lib/agent-generator.js +150 -0
- package/dist/lib/agent-generator.js.map +1 -0
- package/dist/lib/ast-parser.d.ts +11 -0
- package/dist/lib/ast-parser.d.ts.map +1 -0
- package/dist/lib/ast-parser.js +282 -0
- package/dist/lib/ast-parser.js.map +1 -0
- package/dist/lib/config.d.ts +6 -2
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +27 -3
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/meta-index.d.ts +19 -0
- package/dist/lib/meta-index.d.ts.map +1 -0
- package/dist/lib/meta-index.js +573 -0
- package/dist/lib/meta-index.js.map +1 -0
- package/dist/lib/project.js +1 -1
- package/dist/lib/project.js.map +1 -1
- package/dist/lib/skill-generator.d.ts +32 -0
- package/dist/lib/skill-generator.d.ts.map +1 -0
- package/dist/lib/skill-generator.js +187 -0
- package/dist/lib/skill-generator.js.map +1 -0
- package/dist/lib/template.d.ts +16 -2
- package/dist/lib/template.d.ts.map +1 -1
- package/dist/lib/template.js +175 -21
- package/dist/lib/template.js.map +1 -1
- package/dist/lib/ui-index.d.ts +12 -0
- package/dist/lib/ui-index.d.ts.map +1 -0
- package/dist/lib/ui-index.js +239 -0
- package/dist/lib/ui-index.js.map +1 -0
- package/dist/lib/ui-parser.d.ts +12 -0
- package/dist/lib/ui-parser.d.ts.map +1 -0
- package/dist/lib/ui-parser.js +472 -0
- package/dist/lib/ui-parser.js.map +1 -0
- package/dist/lib/update-check.d.ts +6 -0
- package/dist/lib/update-check.d.ts.map +1 -0
- package/dist/lib/update-check.js +121 -0
- package/dist/lib/update-check.js.map +1 -0
- package/dist/lib/upgrade-backup.d.ts +33 -0
- package/dist/lib/upgrade-backup.d.ts.map +1 -0
- package/dist/lib/upgrade-backup.js +101 -0
- package/dist/lib/upgrade-backup.js.map +1 -0
- package/dist/lib/version.d.ts +19 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +35 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/lib/workflow-state.d.ts +48 -0
- package/dist/lib/workflow-state.d.ts.map +1 -0
- package/dist/lib/workflow-state.js +67 -0
- package/dist/lib/workflow-state.js.map +1 -0
- package/dist/types/config.d.ts +102 -2
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +173 -9
- package/dist/types/config.js.map +1 -1
- package/dist/types/feedback.d.ts +59 -1
- package/dist/types/feedback.d.ts.map +1 -1
- package/dist/types/feedback.js +1 -4
- package/dist/types/feedback.js.map +1 -1
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/meta-index.d.ts +146 -0
- package/dist/types/meta-index.d.ts.map +1 -0
- package/dist/types/meta-index.js +7 -0
- package/dist/types/meta-index.js.map +1 -0
- package/dist/types/project.d.ts +19 -3
- package/dist/types/project.d.ts.map +1 -1
- package/dist/types/project.js +24 -1
- package/dist/types/project.js.map +1 -1
- package/dist/types/task-log.d.ts +208 -0
- package/dist/types/task-log.d.ts.map +1 -0
- package/dist/types/task-log.js +6 -0
- package/dist/types/task-log.js.map +1 -0
- package/dist/types/ui-meta.d.ts +118 -0
- package/dist/types/ui-meta.d.ts.map +1 -0
- package/dist/types/ui-meta.js +7 -0
- package/dist/types/ui-meta.js.map +1 -0
- package/package.json +12 -4
- package/templates/base/agents/base/tsq-architect.md +68 -0
- package/templates/base/agents/base/tsq-dba.md +56 -0
- package/templates/base/agents/base/tsq-designer.md +72 -0
- package/templates/base/agents/base/tsq-developer.md +67 -0
- package/templates/base/agents/base/tsq-qa.md +55 -0
- package/templates/base/agents/base/tsq-security.md +65 -0
- package/templates/base/agents/overlays/domain/general-web/_common.md +11 -0
- package/templates/base/agents/overlays/platform/claude-code.md +12 -0
- package/templates/base/config.template.yaml +213 -0
- package/templates/base/knowledge/checklists/accessibility.md +37 -0
- package/templates/base/knowledge/checklists/architecture-review.md +28 -0
- package/templates/base/knowledge/checklists/database-standards.md +84 -0
- package/templates/base/knowledge/checklists/design-reference.md +97 -0
- package/templates/base/knowledge/checklists/security.md +50 -0
- package/templates/base/knowledge/checklists/ssot-validation.md +19 -0
- package/templates/base/knowledge/domains/_template.md +16 -0
- package/templates/base/knowledge/platforms/_template.md +16 -0
- package/templates/base/knowledge/templates/sequence-report.md +44 -0
- package/templates/base/knowledge/templates/task-result.md +105 -0
- package/templates/base/skills/_template/SKILL.md +59 -0
- package/templates/base/skills/_template/references/_template.md +35 -0
- package/templates/base/skills/_template/rules/_sections.md +34 -0
- package/templates/base/skills/_template/rules/_template.md +32 -0
- package/templates/base/skills/_template/scripts/_template.sh +31 -0
- package/templates/base/skills/architecture/SKILL.md +54 -0
- package/templates/base/skills/architecture/references/adr-template.md +50 -0
- package/templates/base/skills/architecture/references/api-design.md +64 -0
- package/templates/base/skills/backend/node/SKILL.md +81 -0
- package/templates/base/skills/backend/node/rules/async-patterns.md +81 -0
- package/templates/base/skills/backend/node/rules/deployment.md +33 -0
- package/templates/base/skills/backend/node/rules/env-config.md +41 -0
- package/templates/base/skills/backend/node/rules/error-handling.md +83 -0
- package/templates/base/skills/backend/node/rules/hono-app-setup.md +98 -0
- package/templates/base/skills/backend/node/rules/jwt-auth.md +76 -0
- package/templates/base/skills/backend/node/rules/middleware.md +56 -0
- package/templates/base/skills/backend/node/rules/testing.md +82 -0
- package/templates/base/skills/coding/SKILL.md +47 -0
- package/templates/base/skills/coding/rules/patterns.md +81 -0
- package/templates/base/skills/database/SKILL.md +98 -0
- package/templates/base/skills/database/prisma/SKILL.md +57 -0
- package/templates/base/skills/database/prisma/rules/queries.md +133 -0
- package/templates/base/skills/database/prisma/rules/schema-design.md +80 -0
- package/templates/base/skills/frontend/nextjs/SKILL.md +59 -0
- package/templates/base/skills/frontend/nextjs/rules/app-router.md +138 -0
- package/templates/base/skills/frontend/react/SKILL.md +86 -0
- package/templates/base/skills/frontend/react/rules/_sections.md +88 -0
- package/templates/base/skills/frontend/react/rules/anti-patterns.md +67 -0
- package/templates/base/skills/frontend/react/rules/async-api-routes.md +38 -0
- package/templates/base/skills/frontend/react/rules/async-defer-await.md +80 -0
- package/templates/base/skills/frontend/react/rules/async-dependencies.md +36 -0
- package/templates/base/skills/frontend/react/rules/async-parallel.md +28 -0
- package/templates/base/skills/frontend/react/rules/async-suspense-boundaries.md +99 -0
- package/templates/base/skills/frontend/react/rules/bundle-barrel-imports.md +59 -0
- package/templates/base/skills/frontend/react/rules/bundle-defer-third-party.md +49 -0
- package/templates/base/skills/frontend/react/rules/bundle-dynamic-imports.md +35 -0
- package/templates/base/skills/frontend/react/rules/component-conventions.md +74 -0
- package/templates/base/skills/frontend/react/rules/js-combine-iterations.md +32 -0
- package/templates/base/skills/frontend/react/rules/js-early-exit.md +50 -0
- package/templates/base/skills/frontend/react/rules/js-index-maps.md +37 -0
- package/templates/base/skills/frontend/react/rules/js-set-map-lookups.md +24 -0
- package/templates/base/skills/frontend/react/rules/rendering-conditional-render.md +40 -0
- package/templates/base/skills/frontend/react/rules/rendering-content-visibility.md +38 -0
- package/templates/base/skills/frontend/react/rules/rendering-hoist-jsx.md +46 -0
- package/templates/base/skills/frontend/react/rules/rerender-defer-reads.md +39 -0
- package/templates/base/skills/frontend/react/rules/rerender-derived-state.md +29 -0
- package/templates/base/skills/frontend/react/rules/rerender-memo.md +44 -0
- package/templates/base/skills/frontend/react/rules/rerender-transitions.md +40 -0
- package/templates/base/skills/frontend/react/rules/server-after-nonblocking.md +73 -0
- package/templates/base/skills/frontend/react/rules/server-cache-react.md +26 -0
- package/templates/base/skills/frontend/react/rules/server-parallel-fetching.md +79 -0
- package/templates/base/skills/frontend/react/rules/state-location.md +55 -0
- package/templates/base/skills/methodology/bdd/SKILL.md +69 -0
- package/templates/base/skills/methodology/bdd/rules/gherkin-patterns.md +113 -0
- package/templates/base/skills/methodology/ddd/SKILL.md +74 -0
- package/templates/base/skills/methodology/ddd/rules/strategic-patterns.md +98 -0
- package/templates/base/skills/methodology/debugging/SKILL.md +60 -0
- package/templates/base/skills/methodology/debugging/references/root-cause-tracing.md +84 -0
- package/templates/base/skills/methodology/tdd/SKILL.md +66 -0
- package/templates/base/skills/methodology/tdd/rules/real-world-example.md +88 -0
- package/templates/base/skills/methodology/tdd/rules/techniques.md +185 -0
- package/templates/base/skills/planning/SKILL.md +58 -0
- package/templates/base/skills/planning/references/prd-guide.md +47 -0
- package/templates/base/skills/planning/references/requirements-guide.md +46 -0
- package/templates/base/skills/prompt-engineering/SKILL.md +103 -0
- package/templates/base/skills/retrospective/SKILL.md +102 -0
- package/templates/base/skills/security/SKILL.md +55 -0
- package/templates/base/skills/security/rules/owasp-examples.md +119 -0
- package/templates/base/skills/security/scripts/check-secrets.sh +55 -0
- package/templates/base/skills/testing/SKILL.md +63 -0
- package/templates/base/skills/testing/references/testing-patterns.md +103 -0
- package/templates/base/skills/tsq-protocol/SKILL.md +51 -0
- package/templates/base/skills/typescript/SKILL.md +67 -0
- package/templates/base/skills/typescript/rules/type-patterns.md +135 -0
- package/templates/base/skills/typescript/rules/utility-types.md +76 -0
- package/templates/base/skills/ui-design/SKILL.md +70 -0
- package/templates/{common → base}/timsquad/feedback/routing-rules.yaml +1 -1
- package/templates/base/timsquad/process/phase-checklist.yaml +174 -0
- package/templates/{common → base}/timsquad/process/state-machine.xml +12 -0
- package/templates/{common → base}/timsquad/process/workflow-base.xml +124 -0
- package/templates/{common → base}/timsquad/retrospective/metrics/metrics-schema.json +46 -1
- package/templates/platforms/claude-code/CLAUDE.md.template +64 -0
- package/templates/platforms/claude-code/rules/adr-rules.md +32 -0
- package/templates/platforms/claude-code/rules/feedback-routing.md +18 -0
- package/templates/platforms/claude-code/rules/phase-management.md +23 -0
- package/templates/platforms/claude-code/rules/reporting-format.md +26 -0
- package/templates/platforms/claude-code/rules/sequence-management.md +72 -0
- package/templates/platforms/claude-code/rules/workspace-sync.md +33 -0
- package/templates/platforms/claude-code/settings.json +26 -0
- package/templates/project-types/api-backend/config.yaml +227 -0
- package/templates/project-types/api-backend/process/workflow.xml +214 -0
- package/templates/project-types/fintech/config.yaml +151 -0
- package/templates/project-types/fintech/process/workflow.xml +316 -0
- package/templates/project-types/infra/config.yaml +327 -0
- package/templates/project-types/infra/process/workflow.xml +296 -0
- package/templates/project-types/platform/config.yaml +254 -0
- package/templates/project-types/platform/process/workflow.xml +254 -0
- package/templates/project-types/web-app/config.yaml +198 -0
- package/templates/project-types/web-app/process/workflow.xml +210 -0
- package/templates/project-types/web-service/config.yaml +136 -0
- package/templates/project-types/web-service/process/workflow.xml +184 -0
- package/templates/common/CLAUDE.md.template +0 -254
- package/templates/common/claude/agents/tsq-dba.md +0 -290
- package/templates/common/claude/agents/tsq-designer.md +0 -304
- package/templates/common/claude/agents/tsq-developer.md +0 -118
- package/templates/common/claude/agents/tsq-planner.md +0 -90
- package/templates/common/claude/agents/tsq-prompter.md +0 -336
- package/templates/common/claude/agents/tsq-qa.md +0 -134
- package/templates/common/claude/agents/tsq-retro.md +0 -168
- package/templates/common/claude/agents/tsq-security.md +0 -190
- package/templates/common/claude/skills/architecture/SKILL.md +0 -123
- package/templates/common/claude/skills/backend/node/SKILL.md +0 -1015
- package/templates/common/claude/skills/coding/SKILL.md +0 -171
- package/templates/common/claude/skills/database/prisma/SKILL.md +0 -357
- package/templates/common/claude/skills/frontend/nextjs/SKILL.md +0 -279
- package/templates/common/claude/skills/frontend/react/SKILL.md +0 -1729
- package/templates/common/claude/skills/methodology/bdd/SKILL.md +0 -234
- package/templates/common/claude/skills/methodology/ddd/SKILL.md +0 -311
- package/templates/common/claude/skills/methodology/tdd/SKILL.md +0 -512
- package/templates/common/claude/skills/planning/SKILL.md +0 -90
- package/templates/common/claude/skills/security/SKILL.md +0 -234
- package/templates/common/claude/skills/testing/SKILL.md +0 -146
- package/templates/common/claude/skills/typescript/SKILL.md +0 -435
- package/templates/common/config.template.yaml +0 -131
- /package/templates/{common → base}/timsquad/architectures/clean/ARCHITECTURE.md +0 -0
- /package/templates/{common → base}/timsquad/architectures/clean/backend.xml +0 -0
- /package/templates/{common → base}/timsquad/architectures/clean/frontend.xml +0 -0
- /package/templates/{common → base}/timsquad/architectures/fsd/ARCHITECTURE.md +0 -0
- /package/templates/{common → base}/timsquad/architectures/fsd/frontend.xml +0 -0
- /package/templates/{common → base}/timsquad/architectures/hexagonal/ARCHITECTURE.md +0 -0
- /package/templates/{common → base}/timsquad/architectures/hexagonal/backend.xml +0 -0
- /package/templates/{common → base}/timsquad/constraints/competency-framework.xml +0 -0
- /package/templates/{common → base}/timsquad/constraints/ssot-schema.xml +0 -0
- /package/templates/{common → base}/timsquad/feedback/feedback-router.sh +0 -0
- /package/templates/{common → base}/timsquad/generators/data-design.xml +0 -0
- /package/templates/{common → base}/timsquad/generators/prd.xml +0 -0
- /package/templates/{common → base}/timsquad/generators/requirements.xml +0 -0
- /package/templates/{common → base}/timsquad/generators/service-spec.xml +0 -0
- /package/templates/{common → base}/timsquad/logs/_example.md +0 -0
- /package/templates/{common → base}/timsquad/logs/_template.md +0 -0
- /package/templates/{common → base}/timsquad/patterns/cqrs.xml +0 -0
- /package/templates/{common → base}/timsquad/patterns/event-sourcing.xml +0 -0
- /package/templates/{common → base}/timsquad/patterns/repository.xml +0 -0
- /package/templates/{common → base}/timsquad/process/validation-rules.xml +0 -0
- /package/templates/{common → base}/timsquad/retrospective/cycle-report.template.md +0 -0
- /package/templates/{common → base}/timsquad/retrospective/patterns/failure-patterns.md +0 -0
- /package/templates/{common → base}/timsquad/retrospective/patterns/success-patterns.md +0 -0
- /package/templates/{common → base}/timsquad/retrospective/retrospective-config.xml +0 -0
- /package/templates/{common → base}/timsquad/retrospective/retrospective-state.xml +0 -0
- /package/templates/{common → base}/timsquad/ssot/adr/ADR-000-template.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/adr/ADR-001-example.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/data-design.template.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/deployment-spec.template.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/env-config.template.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/error-codes.template.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/functional-spec.template.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/glossary.template.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/integration-spec.template.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/planning.template.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/prd.template.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/requirements.template.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/security-spec.template.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/service-spec.template.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/test-spec.template.md +0 -0
- /package/templates/{common → base}/timsquad/ssot/ui-ux-spec.template.md +0 -0
- /package/templates/{common → base}/timsquad/state/workspace.xml +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: prisma
|
|
3
|
+
description: Prisma ORM 개발 가이드라인
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
tags: [prisma, orm, database]
|
|
6
|
+
user-invocable: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Prisma ORM Guidelines
|
|
10
|
+
|
|
11
|
+
## 철학
|
|
12
|
+
- Schema as SSOT — 스키마가 진실의 원천
|
|
13
|
+
- Type Safety — 자동 생성 타입 활용
|
|
14
|
+
- Migration First — 스키마 변경은 마이그레이션으로
|
|
15
|
+
|
|
16
|
+
## 마이그레이션 워크플로우
|
|
17
|
+
|
|
18
|
+
| 명령어 | 용도 |
|
|
19
|
+
|--------|------|
|
|
20
|
+
| `npx prisma migrate dev --name {name}` | 개발 환경 마이그레이션 |
|
|
21
|
+
| `npx prisma migrate deploy` | 프로덕션 적용 |
|
|
22
|
+
| `npx prisma migrate reset` | DB 초기화 + 재적용 |
|
|
23
|
+
| `npx prisma db push` | 빠른 프로토타이핑 (마이그레이션 없이) |
|
|
24
|
+
| `npx prisma generate` | 클라이언트 재생성 |
|
|
25
|
+
|
|
26
|
+
**순서**: schema.prisma 수정 → migrate dev → SQL 검토 → 커밋
|
|
27
|
+
|
|
28
|
+
## Rules
|
|
29
|
+
|
|
30
|
+
### 스키마
|
|
31
|
+
- 모든 모델에 `id`, `createdAt`, `updatedAt`
|
|
32
|
+
- 명시적 인덱스 정의 (`@@index`)
|
|
33
|
+
- `@@map`으로 테이블명 명시
|
|
34
|
+
- 관계는 명확히 정의
|
|
35
|
+
|
|
36
|
+
### 쿼리
|
|
37
|
+
- `select`로 필요한 필드만 조회 (성능)
|
|
38
|
+
- 페이지네이션 적용 (`take`, `skip`)
|
|
39
|
+
- 복잡한 작업은 트랜잭션 사용
|
|
40
|
+
- **금지**: N+1 쿼리, 무한 결과 조회
|
|
41
|
+
|
|
42
|
+
### 마이그레이션
|
|
43
|
+
- `migrate dev`로 개발, `migrate deploy`로 배포
|
|
44
|
+
- 마이그레이션 파일 커밋 필수
|
|
45
|
+
- **금지**: 프로덕션에서 `db push`
|
|
46
|
+
|
|
47
|
+
## Checklist
|
|
48
|
+
- [ ] 싱글톤 인스턴스 사용
|
|
49
|
+
- [ ] 마이그레이션으로 스키마 관리
|
|
50
|
+
- [ ] 트랜잭션으로 데이터 정합성
|
|
51
|
+
- [ ] select로 필요한 필드만 조회
|
|
52
|
+
- [ ] 인덱스 적절히 설정
|
|
53
|
+
- [ ] Repository 패턴 적용
|
|
54
|
+
|
|
55
|
+
## 참조
|
|
56
|
+
- `rules/schema-design.md` — 모델 정의, 공통 필드, 소프트 삭제 패턴
|
|
57
|
+
- `rules/queries.md` — 싱글톤, CRUD, Relations, 트랜잭션, Repository 패턴
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Prisma Query Patterns
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: prisma, database, queries
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Prisma Query Patterns
|
|
8
|
+
|
|
9
|
+
## 싱글톤 인스턴스
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// lib/prisma.ts
|
|
13
|
+
import { PrismaClient } from '@prisma/client';
|
|
14
|
+
|
|
15
|
+
const globalForPrisma = globalThis as unknown as {
|
|
16
|
+
prisma: PrismaClient | undefined;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const prisma = globalForPrisma.prisma ?? new PrismaClient({
|
|
20
|
+
log: process.env.NODE_ENV === 'development'
|
|
21
|
+
? ['query', 'error', 'warn']
|
|
22
|
+
: ['error'],
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
26
|
+
globalForPrisma.prisma = prisma;
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Extensions (소프트 삭제 자동 필터)
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
export const prisma = prismaBase.$extends({
|
|
34
|
+
query: {
|
|
35
|
+
$allModels: {
|
|
36
|
+
async findMany({ model, operation, args, query }) {
|
|
37
|
+
args.where = { ...args.where, deletedAt: null };
|
|
38
|
+
return query(args);
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 기본 CRUD
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// Create
|
|
49
|
+
const user = await prisma.user.create({
|
|
50
|
+
data: { email: 'test@example.com', name: 'Test', password: hashedPassword },
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Read
|
|
54
|
+
const user = await prisma.user.findUnique({ where: { id: userId } });
|
|
55
|
+
const users = await prisma.user.findMany({
|
|
56
|
+
where: { role: 'USER' },
|
|
57
|
+
orderBy: { createdAt: 'desc' },
|
|
58
|
+
take: 10, skip: 0,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Update
|
|
62
|
+
const updated = await prisma.user.update({
|
|
63
|
+
where: { id: userId },
|
|
64
|
+
data: { name: 'New Name' },
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Delete
|
|
68
|
+
await prisma.user.delete({ where: { id: userId } });
|
|
69
|
+
|
|
70
|
+
// Upsert
|
|
71
|
+
const user = await prisma.user.upsert({
|
|
72
|
+
where: { email: 'test@example.com' },
|
|
73
|
+
update: { name: 'Updated Name' },
|
|
74
|
+
create: { email: 'test@example.com', name: 'New User', password },
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Relations 로딩
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
// include: 관계 데이터 포함
|
|
82
|
+
const userWithPosts = await prisma.user.findUnique({
|
|
83
|
+
where: { id: userId },
|
|
84
|
+
include: { posts: true, profile: true },
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// select: 특정 필드만 선택 (성능 최적화)
|
|
88
|
+
const userWithPosts = await prisma.user.findUnique({
|
|
89
|
+
where: { id: userId },
|
|
90
|
+
select: {
|
|
91
|
+
id: true, name: true,
|
|
92
|
+
posts: { select: { id: true, title: true }, where: { published: true }, take: 5 },
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 트랜잭션
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
const result = await prisma.$transaction(async (tx) => {
|
|
101
|
+
const user = await tx.user.create({ data: { email, name, password } });
|
|
102
|
+
await tx.profile.create({ data: { userId: user.id, bio: '' } });
|
|
103
|
+
await tx.notification.create({ data: { userId: user.id, message: 'Welcome!' } });
|
|
104
|
+
return user;
|
|
105
|
+
});
|
|
106
|
+
// 실패 시 모두 롤백
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Repository 패턴
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
export interface UserRepository {
|
|
113
|
+
findById(id: string): Promise<User | null>;
|
|
114
|
+
findByEmail(email: string): Promise<User | null>;
|
|
115
|
+
save(user: User): Promise<User>;
|
|
116
|
+
delete(id: string): Promise<void>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export class PrismaUserRepository implements UserRepository {
|
|
120
|
+
async findById(id: string) {
|
|
121
|
+
return prisma.user.findUnique({ where: { id } });
|
|
122
|
+
}
|
|
123
|
+
async findByEmail(email: string) {
|
|
124
|
+
return prisma.user.findUnique({ where: { email } });
|
|
125
|
+
}
|
|
126
|
+
async save(data: Omit<User, 'id' | 'createdAt' | 'updatedAt'>) {
|
|
127
|
+
return prisma.user.create({ data });
|
|
128
|
+
}
|
|
129
|
+
async delete(id: string) {
|
|
130
|
+
await prisma.user.delete({ where: { id } });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Prisma Schema Design Patterns
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: prisma, database, schema
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Prisma Schema Design Patterns
|
|
8
|
+
|
|
9
|
+
## 기본 모델 정의
|
|
10
|
+
|
|
11
|
+
```prisma
|
|
12
|
+
generator client {
|
|
13
|
+
provider = "prisma-client-js"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
datasource db {
|
|
17
|
+
provider = "postgresql"
|
|
18
|
+
url = env("DATABASE_URL")
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
model User {
|
|
22
|
+
id String @id @default(cuid())
|
|
23
|
+
email String @unique
|
|
24
|
+
name String
|
|
25
|
+
password String
|
|
26
|
+
role Role @default(USER)
|
|
27
|
+
|
|
28
|
+
createdAt DateTime @default(now())
|
|
29
|
+
updatedAt DateTime @updatedAt
|
|
30
|
+
|
|
31
|
+
posts Post[]
|
|
32
|
+
profile Profile?
|
|
33
|
+
|
|
34
|
+
@@index([email])
|
|
35
|
+
@@map("users")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
model Post {
|
|
39
|
+
id String @id @default(cuid())
|
|
40
|
+
title String
|
|
41
|
+
content String?
|
|
42
|
+
published Boolean @default(false)
|
|
43
|
+
|
|
44
|
+
createdAt DateTime @default(now())
|
|
45
|
+
updatedAt DateTime @updatedAt
|
|
46
|
+
|
|
47
|
+
author User @relation(fields: [authorId], references: [id])
|
|
48
|
+
authorId String
|
|
49
|
+
|
|
50
|
+
@@index([authorId])
|
|
51
|
+
@@map("posts")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
enum Role {
|
|
55
|
+
USER
|
|
56
|
+
ADMIN
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## 공통 필드 패턴
|
|
61
|
+
모든 모델에 공통으로 들어가는 필드 (Prisma는 상속 미지원, 컨벤션으로 관리):
|
|
62
|
+
- `id String @id @default(cuid())`
|
|
63
|
+
- `createdAt DateTime @default(now())`
|
|
64
|
+
- `updatedAt DateTime @updatedAt`
|
|
65
|
+
|
|
66
|
+
## 소프트 삭제
|
|
67
|
+
|
|
68
|
+
```prisma
|
|
69
|
+
model User {
|
|
70
|
+
id String @id @default(cuid())
|
|
71
|
+
deletedAt DateTime? // null이면 활성, 값 있으면 삭제됨
|
|
72
|
+
@@index([deletedAt])
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
const activeUsers = await prisma.user.findMany({
|
|
78
|
+
where: { deletedAt: null },
|
|
79
|
+
});
|
|
80
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nextjs
|
|
3
|
+
description: Next.js App Router 개발 가이드라인
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
tags: [nextjs, react, frontend]
|
|
6
|
+
user-invocable: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Next.js 15+ App Router
|
|
10
|
+
|
|
11
|
+
## 철학
|
|
12
|
+
- Server First — 기본은 서버 컴포넌트
|
|
13
|
+
- Progressive Enhancement — 필요할 때만 클라이언트
|
|
14
|
+
- Colocation — 관련 파일은 가까이
|
|
15
|
+
|
|
16
|
+
## Server vs Client 판단
|
|
17
|
+
|
|
18
|
+
| 조건 | 컴포넌트 |
|
|
19
|
+
|------|---------|
|
|
20
|
+
| 데이터 페칭, DB 접근, 민감 정보 | Server (기본) |
|
|
21
|
+
| 인터랙션, 이벤트, useState/useEffect | Client (`'use client'`) |
|
|
22
|
+
| 브라우저 API 필요 | Client |
|
|
23
|
+
| 그 외 | Server |
|
|
24
|
+
|
|
25
|
+
## Rules
|
|
26
|
+
|
|
27
|
+
### 컴포넌트
|
|
28
|
+
- 기본은 Server Component
|
|
29
|
+
- 인터랙션 필요할 때만 `'use client'`
|
|
30
|
+
- Client Component는 작게 유지 (leaf에 배치)
|
|
31
|
+
- **금지**: Server Component에서 useState/useEffect, 불필요한 `'use client'`
|
|
32
|
+
|
|
33
|
+
### 데이터
|
|
34
|
+
- Server Component에서 데이터 페칭
|
|
35
|
+
- mutation은 Server Actions 사용
|
|
36
|
+
- 적절한 캐싱 전략 설정
|
|
37
|
+
- **금지**: Client Component에서 직접 DB 접근
|
|
38
|
+
|
|
39
|
+
### 라우팅
|
|
40
|
+
- 파일 기반 라우팅 규칙 준수
|
|
41
|
+
- Route Group으로 레이아웃 관리
|
|
42
|
+
- `loading.tsx`, `error.tsx` 제공
|
|
43
|
+
|
|
44
|
+
## 성능 최적화
|
|
45
|
+
- `next/image`: sizes 속성
|
|
46
|
+
- `next/font`: 폰트 최적화
|
|
47
|
+
- `next/link`: 프리페칭
|
|
48
|
+
- 동적 import: 무거운 컴포넌트 지연 로딩
|
|
49
|
+
|
|
50
|
+
## Checklist
|
|
51
|
+
- [ ] Server Component 기본 사용
|
|
52
|
+
- [ ] 'use client' 최소화
|
|
53
|
+
- [ ] Server Actions로 mutation
|
|
54
|
+
- [ ] 적절한 캐싱 전략
|
|
55
|
+
- [ ] loading.tsx, error.tsx 구현
|
|
56
|
+
- [ ] Metadata 설정
|
|
57
|
+
|
|
58
|
+
## 참조
|
|
59
|
+
- `rules/app-router.md` — 디렉토리 구조, Server/Client 예시, Data Fetching, Metadata, Loading/Error 패턴
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Next.js App Router Patterns
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: nextjs, frontend, app-router
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Next.js App Router Patterns
|
|
8
|
+
|
|
9
|
+
## 디렉토리 구조
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
app/
|
|
13
|
+
├── layout.tsx # 루트 레이아웃 (필수)
|
|
14
|
+
├── page.tsx # 홈페이지 (/)
|
|
15
|
+
├── loading.tsx # 로딩 UI
|
|
16
|
+
├── error.tsx # 에러 UI
|
|
17
|
+
├── not-found.tsx # 404 UI
|
|
18
|
+
│
|
|
19
|
+
├── (auth)/ # Route Group (URL에 미포함)
|
|
20
|
+
│ ├── login/page.tsx # /login
|
|
21
|
+
│ └── register/page.tsx # /register
|
|
22
|
+
│
|
|
23
|
+
├── dashboard/
|
|
24
|
+
│ ├── layout.tsx # 대시보드 레이아웃
|
|
25
|
+
│ ├── page.tsx # /dashboard
|
|
26
|
+
│ └── settings/page.tsx # /dashboard/settings
|
|
27
|
+
│
|
|
28
|
+
├── users/
|
|
29
|
+
│ ├── page.tsx # /users (목록)
|
|
30
|
+
│ └── [id]/
|
|
31
|
+
│ ├── page.tsx # /users/:id
|
|
32
|
+
│ └── edit/page.tsx # /users/:id/edit
|
|
33
|
+
│
|
|
34
|
+
└── api/users/route.ts # /api/users
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Server vs Client Component
|
|
38
|
+
|
|
39
|
+
### 판단 기준
|
|
40
|
+
```
|
|
41
|
+
데이터 페칭 필요? → Server Component
|
|
42
|
+
인터랙션/이벤트 필요? → Client Component ('use client')
|
|
43
|
+
브라우저 API 필요? → Client Component
|
|
44
|
+
그 외 → Server Component (기본)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Server Component (기본)
|
|
48
|
+
```typescript
|
|
49
|
+
// app/users/page.tsx
|
|
50
|
+
import { db } from '@/lib/db';
|
|
51
|
+
|
|
52
|
+
export default async function UsersPage() {
|
|
53
|
+
const users = await db.user.findMany();
|
|
54
|
+
return (
|
|
55
|
+
<ul>
|
|
56
|
+
{users.map(user => <li key={user.id}>{user.name}</li>)}
|
|
57
|
+
</ul>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Client Component
|
|
63
|
+
```typescript
|
|
64
|
+
// components/counter.tsx
|
|
65
|
+
'use client';
|
|
66
|
+
import { useState } from 'react';
|
|
67
|
+
|
|
68
|
+
export function Counter() {
|
|
69
|
+
const [count, setCount] = useState(0);
|
|
70
|
+
return <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Data Fetching
|
|
75
|
+
|
|
76
|
+
### Server Component에서 직접 fetch
|
|
77
|
+
```typescript
|
|
78
|
+
async function getPosts() {
|
|
79
|
+
const res = await fetch('https://api.example.com/posts', {
|
|
80
|
+
next: { revalidate: 60 },
|
|
81
|
+
});
|
|
82
|
+
return res.json();
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Server Actions
|
|
87
|
+
```typescript
|
|
88
|
+
// app/actions/user.ts
|
|
89
|
+
'use server';
|
|
90
|
+
import { revalidatePath } from 'next/cache';
|
|
91
|
+
|
|
92
|
+
export async function createUser(formData: FormData) {
|
|
93
|
+
const name = formData.get('name') as string;
|
|
94
|
+
await db.user.create({ data: { name, email: formData.get('email') as string } });
|
|
95
|
+
revalidatePath('/users');
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 캐싱 전략
|
|
100
|
+
| 옵션 | 설명 |
|
|
101
|
+
|------|------|
|
|
102
|
+
| `force-cache` | 기본값, 캐시 사용 |
|
|
103
|
+
| `no-store` | 캐시 안 함, 항상 새로 요청 |
|
|
104
|
+
| `revalidate: N` | N초마다 재검증 |
|
|
105
|
+
| `revalidatePath()` | 특정 경로 재검증 |
|
|
106
|
+
| `revalidateTag()` | 태그로 재검증 |
|
|
107
|
+
|
|
108
|
+
## Metadata
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// 정적
|
|
112
|
+
export const metadata: Metadata = { title: 'About Us' };
|
|
113
|
+
|
|
114
|
+
// 동적
|
|
115
|
+
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|
116
|
+
const { id } = await params;
|
|
117
|
+
const user = await getUser(id);
|
|
118
|
+
return { title: user.name };
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Loading & Error
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
// loading.tsx
|
|
126
|
+
export default function Loading() { return <DashboardSkeleton />; }
|
|
127
|
+
|
|
128
|
+
// error.tsx
|
|
129
|
+
'use client';
|
|
130
|
+
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
|
131
|
+
return (
|
|
132
|
+
<div>
|
|
133
|
+
<h2>Something went wrong!</h2>
|
|
134
|
+
<button onClick={reset}>Try again</button>
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
```
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: react
|
|
3
|
+
description: React 컴포넌트 개발 가이드라인. 단일 책임, UI/로직 분리, 명시적 데이터 흐름, 서버/클라이언트 상태 분리.
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
tags: [react, components, frontend]
|
|
6
|
+
user-invocable: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# React Development Guidelines
|
|
10
|
+
|
|
11
|
+
프로젝트 전체에서 일관된 React 컴포넌트 개발을 위한 컨벤션.
|
|
12
|
+
|
|
13
|
+
## Philosophy
|
|
14
|
+
|
|
15
|
+
- 컴포넌트는 단일 책임
|
|
16
|
+
- UI와 로직 분리 (커스텀 훅)
|
|
17
|
+
- Props로 명시적 데이터 흐름
|
|
18
|
+
- 서버 상태와 클라이언트 상태 분리
|
|
19
|
+
|
|
20
|
+
## Resources
|
|
21
|
+
|
|
22
|
+
25개 규칙 (TimSquad 3 + Vercel 22). 카테고리 인덱스: [_sections.md](rules/_sections.md)
|
|
23
|
+
|
|
24
|
+
| Priority | Type | Resource | Description |
|
|
25
|
+
|----------|------|----------|-------------|
|
|
26
|
+
| CRITICAL | rule | [async-parallel](rules/async-parallel.md) | Promise.all 병렬 실행 (2-10x) |
|
|
27
|
+
| CRITICAL | rule | [bundle-barrel-imports](rules/bundle-barrel-imports.md) | barrel import 피하기 |
|
|
28
|
+
| HIGH | rule | [component-conventions](rules/component-conventions.md) | 컴포넌트 구조, export, 크기 제한 |
|
|
29
|
+
| HIGH | rule | [state-location](rules/state-location.md) | 상태 관리 선택 기준 |
|
|
30
|
+
| HIGH | rule | [server-parallel-fetching](rules/server-parallel-fetching.md) | 서버 병렬 fetch |
|
|
31
|
+
| HIGH | rule | [rerender-memo](rules/rerender-memo.md) | React.memo 최적화 |
|
|
32
|
+
| MEDIUM | rule | [anti-patterns](rules/anti-patterns.md) | Props Drilling, useEffect 남용 |
|
|
33
|
+
|
|
34
|
+
## Quick Rules
|
|
35
|
+
|
|
36
|
+
### 컴포넌트
|
|
37
|
+
- 함수형 컴포넌트 + Props interface
|
|
38
|
+
- named export (`export function`, default export 금지)
|
|
39
|
+
- 200줄 이하
|
|
40
|
+
- forwardRef로 ref 전달 지원
|
|
41
|
+
|
|
42
|
+
### 훅
|
|
43
|
+
- 커스텀 훅으로 로직 분리 (`use` 접두사)
|
|
44
|
+
- 의존성 배열 정확히 관리
|
|
45
|
+
- 함수형 setState로 stale closure 방지
|
|
46
|
+
- 조건문/반복문 안에서 훅 호출 금지
|
|
47
|
+
- useEffect 남용 금지 (파생 상태는 useMemo)
|
|
48
|
+
|
|
49
|
+
### 상태 관리
|
|
50
|
+
- 서버 상태: React Query (TanStack Query)
|
|
51
|
+
- 전역 UI 상태: Zustand
|
|
52
|
+
- 로컬 상태: useState
|
|
53
|
+
- 복잡한 로직: useReducer
|
|
54
|
+
- 비싼 초기값: lazy init (`useState(() => ...)`)
|
|
55
|
+
- Props drilling 3단계 이상 → Context 또는 Zustand
|
|
56
|
+
|
|
57
|
+
### 성능 (vercel-react-best-practices 참조)
|
|
58
|
+
- 리스트에 고유 key (index 금지)
|
|
59
|
+
- Promise.all로 병렬 fetch
|
|
60
|
+
- barrel import 피하기 (직접 import)
|
|
61
|
+
- dynamic import로 무거운 컴포넌트 분리
|
|
62
|
+
- content-visibility로 대량 리스트 최적화
|
|
63
|
+
- toSorted()로 배열 불변성
|
|
64
|
+
|
|
65
|
+
### 폼
|
|
66
|
+
- React Hook Form + Zod (zodResolver)
|
|
67
|
+
- onBlur 유효성 검사, submit 시 첫 에러 필드 포커스
|
|
68
|
+
|
|
69
|
+
## Checklist
|
|
70
|
+
|
|
71
|
+
| Priority | Item |
|
|
72
|
+
|----------|------|
|
|
73
|
+
| CRITICAL | 함수형 컴포넌트 + Props 타입 정의 |
|
|
74
|
+
| CRITICAL | 커스텀 훅으로 로직 분리 |
|
|
75
|
+
| CRITICAL | 서버 상태는 React Query |
|
|
76
|
+
| CRITICAL | Error Boundary로 에러 격리 |
|
|
77
|
+
| CRITICAL | Waterfall 제거 (Promise.all) |
|
|
78
|
+
| CRITICAL | Barrel import 피하기 |
|
|
79
|
+
| HIGH | 의존성 배열 정확히 관리 |
|
|
80
|
+
| HIGH | 리스트에 고유 key (index 금지) |
|
|
81
|
+
| HIGH | 폼은 React Hook Form + Zod |
|
|
82
|
+
| HIGH | 함수형 setState 사용 |
|
|
83
|
+
| HIGH | Dynamic import 분리 |
|
|
84
|
+
| MEDIUM | 대량 리스트 가상화 / content-visibility |
|
|
85
|
+
| MEDIUM | 불필요한 useEffect 제거 |
|
|
86
|
+
| MEDIUM | RSC 경계에서 필요한 데이터만 전달 |
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: React Rule Categories
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# React Rule Categories
|
|
6
|
+
|
|
7
|
+
25개 규칙을 카테고리별로 정리. TimSquad 커스텀 + Vercel react-best-practices 통합.
|
|
8
|
+
|
|
9
|
+
## TimSquad Custom (tsq-)
|
|
10
|
+
|
|
11
|
+
**Impact:** HIGH
|
|
12
|
+
**Description:** 프로젝트 컨벤션 및 아키텍처 규칙
|
|
13
|
+
|
|
14
|
+
| Rule | Description |
|
|
15
|
+
|------|-------------|
|
|
16
|
+
| [component-conventions](component-conventions.md) | 컴포넌트 구조 템플릿, export, 크기 제한 |
|
|
17
|
+
| [state-location](state-location.md) | useState/Context/Zustand/React Query 선택 기준 |
|
|
18
|
+
| [anti-patterns](anti-patterns.md) | Props Drilling, useEffect 남용, God Component |
|
|
19
|
+
|
|
20
|
+
## Eliminating Waterfalls (async-)
|
|
21
|
+
|
|
22
|
+
**Impact:** CRITICAL
|
|
23
|
+
**Description:** Waterfalls are the #1 performance killer. Each sequential await adds full network latency.
|
|
24
|
+
|
|
25
|
+
| Rule | Description |
|
|
26
|
+
|------|-------------|
|
|
27
|
+
| [async-parallel](async-parallel.md) | Promise.all for independent operations (2-10x) |
|
|
28
|
+
| [async-defer-await](async-defer-await.md) | Start async work before awaiting |
|
|
29
|
+
| [async-api-routes](async-api-routes.md) | Parallel data fetching in API routes |
|
|
30
|
+
| [async-dependencies](async-dependencies.md) | Break async dependency chains |
|
|
31
|
+
| [async-suspense-boundaries](async-suspense-boundaries.md) | Granular Suspense boundaries |
|
|
32
|
+
|
|
33
|
+
## Bundle Size (bundle-)
|
|
34
|
+
|
|
35
|
+
**Impact:** CRITICAL
|
|
36
|
+
**Description:** Reducing initial bundle size improves TTI and LCP.
|
|
37
|
+
|
|
38
|
+
| Rule | Description |
|
|
39
|
+
|------|-------------|
|
|
40
|
+
| [bundle-barrel-imports](bundle-barrel-imports.md) | Avoid barrel files, use direct imports |
|
|
41
|
+
| [bundle-dynamic-imports](bundle-dynamic-imports.md) | Dynamic import for heavy components |
|
|
42
|
+
| [bundle-defer-third-party](bundle-defer-third-party.md) | Defer non-critical third-party scripts |
|
|
43
|
+
|
|
44
|
+
## Server-Side Performance (server-)
|
|
45
|
+
|
|
46
|
+
**Impact:** HIGH
|
|
47
|
+
**Description:** Optimizing server-side rendering and data fetching.
|
|
48
|
+
|
|
49
|
+
| Rule | Description |
|
|
50
|
+
|------|-------------|
|
|
51
|
+
| [server-cache-react](server-cache-react.md) | React cache() for request dedup |
|
|
52
|
+
| [server-parallel-fetching](server-parallel-fetching.md) | Parallel server data fetching |
|
|
53
|
+
| [server-after-nonblocking](server-after-nonblocking.md) | after() for non-blocking work |
|
|
54
|
+
|
|
55
|
+
## Re-render Optimization (rerender-)
|
|
56
|
+
|
|
57
|
+
**Impact:** MEDIUM
|
|
58
|
+
**Description:** Reducing unnecessary re-renders.
|
|
59
|
+
|
|
60
|
+
| Rule | Description |
|
|
61
|
+
|------|-------------|
|
|
62
|
+
| [rerender-memo](rerender-memo.md) | React.memo for stable components |
|
|
63
|
+
| [rerender-defer-reads](rerender-defer-reads.md) | Defer state reads to minimize scope |
|
|
64
|
+
| [rerender-derived-state](rerender-derived-state.md) | Derive state instead of syncing |
|
|
65
|
+
| [rerender-transitions](rerender-transitions.md) | useTransition for non-urgent updates |
|
|
66
|
+
|
|
67
|
+
## Rendering Performance (rendering-)
|
|
68
|
+
|
|
69
|
+
**Impact:** MEDIUM
|
|
70
|
+
**Description:** Optimizing the rendering process.
|
|
71
|
+
|
|
72
|
+
| Rule | Description |
|
|
73
|
+
|------|-------------|
|
|
74
|
+
| [rendering-content-visibility](rendering-content-visibility.md) | content-visibility: auto for large lists |
|
|
75
|
+
| [rendering-hoist-jsx](rendering-hoist-jsx.md) | Hoist JSX out of loops/conditions |
|
|
76
|
+
| [rendering-conditional-render](rendering-conditional-render.md) | Efficient conditional rendering |
|
|
77
|
+
|
|
78
|
+
## JavaScript Performance (js-)
|
|
79
|
+
|
|
80
|
+
**Impact:** LOW-MEDIUM
|
|
81
|
+
**Description:** Micro-optimizations for hot paths.
|
|
82
|
+
|
|
83
|
+
| Rule | Description |
|
|
84
|
+
|------|-------------|
|
|
85
|
+
| [js-index-maps](js-index-maps.md) | Pre-index data with Maps |
|
|
86
|
+
| [js-early-exit](js-early-exit.md) | Early return for cheaper checks first |
|
|
87
|
+
| [js-set-map-lookups](js-set-map-lookups.md) | Set/Map for O(1) lookups |
|
|
88
|
+
| [js-combine-iterations](js-combine-iterations.md) | Combine array iterations |
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Anti-Patterns
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: anti-pattern, performance, useEffect
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Anti-Patterns
|
|
8
|
+
|
|
9
|
+
### 1. useEffect for Derived State
|
|
10
|
+
|
|
11
|
+
**Incorrect:**
|
|
12
|
+
```tsx
|
|
13
|
+
const [items, setItems] = useState([]);
|
|
14
|
+
const [total, setTotal] = useState(0);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
setTotal(items.reduce((sum, i) => sum + i.price, 0));
|
|
18
|
+
}, [items]);
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Correct:**
|
|
22
|
+
```tsx
|
|
23
|
+
const total = useMemo(
|
|
24
|
+
() => items.reduce((sum, i) => sum + i.price, 0),
|
|
25
|
+
[items]
|
|
26
|
+
);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Inline Object/Array in JSX
|
|
30
|
+
|
|
31
|
+
**Incorrect:**
|
|
32
|
+
```tsx
|
|
33
|
+
// 매 렌더링마다 새 참조 → memo 무효화
|
|
34
|
+
<Child style={{ color: 'red' }} items={[1, 2, 3]} />
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Correct:**
|
|
38
|
+
```tsx
|
|
39
|
+
const style = useMemo(() => ({ color: 'red' }), []);
|
|
40
|
+
const items = useMemo(() => [1, 2, 3], []);
|
|
41
|
+
<Child style={style} items={items} />
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 3. Props Drilling (3+ levels)
|
|
45
|
+
|
|
46
|
+
3단계 이상 Props 전달 → Context 또는 Zustand 사용.
|
|
47
|
+
|
|
48
|
+
### 4. God Component (500+ lines)
|
|
49
|
+
|
|
50
|
+
하나의 거대한 컴포넌트 → 작은 단위로 분리, 훅으로 로직 추출.
|
|
51
|
+
|
|
52
|
+
### 5. Stale Closure in Callbacks
|
|
53
|
+
|
|
54
|
+
**Incorrect:**
|
|
55
|
+
```tsx
|
|
56
|
+
const [items, setItems] = useState(initialItems);
|
|
57
|
+
const addItems = useCallback((newItems: Item[]) => {
|
|
58
|
+
setItems([...items, ...newItems]); // items 참조 고정됨
|
|
59
|
+
}, [items]); // items 변경마다 재생성
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Correct:**
|
|
63
|
+
```tsx
|
|
64
|
+
const addItems = useCallback((newItems: Item[]) => {
|
|
65
|
+
setItems(curr => [...curr, ...newItems]); // 함수형 setState
|
|
66
|
+
}, []); // 의존성 없음, 안정적
|
|
67
|
+
```
|