timsquad 2.1.0 → 3.4.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.ko.md +288 -0
- package/README.md +170 -763
- package/dist/commands/compile.d.ts +3 -0
- package/dist/commands/compile.d.ts.map +1 -0
- package/dist/commands/compile.js +170 -0
- package/dist/commands/compile.js.map +1 -0
- package/dist/commands/daemon.d.ts +7 -0
- package/dist/commands/daemon.d.ts.map +1 -0
- package/dist/commands/daemon.js +229 -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 +235 -14
- 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/init.d.ts.map +1 -1
- package/dist/commands/init.js +118 -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 +965 -0
- 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 +239 -4
- package/dist/commands/metrics.js.map +1 -1
- package/dist/commands/retro.js +154 -6
- package/dist/commands/retro.js.map +1 -1
- package/dist/commands/skills.d.ts +12 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +231 -0
- package/dist/commands/skills.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 +292 -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 +29 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +296 -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 +63 -0
- package/dist/daemon/meta-cache.d.ts.map +1 -0
- package/dist/daemon/meta-cache.js +249 -0
- package/dist/daemon/meta-cache.js.map +1 -0
- package/dist/daemon/session-state.d.ts +19 -0
- package/dist/daemon/session-state.d.ts.map +1 -0
- package/dist/daemon/session-state.js +132 -0
- package/dist/daemon/session-state.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 +164 -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/compile-rules.d.ts +66 -0
- package/dist/lib/compile-rules.d.ts.map +1 -0
- package/dist/lib/compile-rules.js +114 -0
- package/dist/lib/compile-rules.js.map +1 -0
- package/dist/lib/compiler.d.ts +105 -0
- package/dist/lib/compiler.d.ts.map +1 -0
- package/dist/lib/compiler.js +368 -0
- package/dist/lib/compiler.js.map +1 -0
- package/dist/lib/config.d.ts +7 -2
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +34 -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 +115 -20
- 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 +103 -2
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +184 -9
- package/dist/types/config.js.map +1 -1
- package/dist/types/feedback.d.ts +7 -0
- package/dist/types/feedback.d.ts.map +1 -1
- package/dist/types/feedback.js +1 -1
- 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 +23 -0
- 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/domain/mobile/_common.md +13 -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/controller/SKILL.md +111 -0
- package/templates/base/skills/controller/references/README.md +35 -0
- package/templates/base/skills/controller/rules/README.md +18 -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/mobile/dart/SKILL.md +69 -0
- package/templates/base/skills/mobile/dart/rules/async-patterns.md +112 -0
- package/templates/base/skills/mobile/dart/rules/code-style.md +96 -0
- package/templates/base/skills/mobile/dart/rules/null-safety.md +84 -0
- package/templates/base/skills/mobile/dart/rules/type-system.md +111 -0
- package/templates/base/skills/mobile/flutter/SKILL.md +89 -0
- package/templates/base/skills/mobile/flutter/ci-cd/SKILL.md +82 -0
- package/templates/base/skills/mobile/flutter/ci-cd/references/ci-cd-pipeline.md +314 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/code-signing.md +106 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/codemagic-setup.md +116 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/fastlane-setup.md +105 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/github-actions.md +112 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/store-deployment.md +106 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/versioning.md +107 -0
- package/templates/base/skills/mobile/flutter/i18n/SKILL.md +78 -0
- package/templates/base/skills/mobile/flutter/i18n/references/i18n-architecture.md +225 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/arb-files.md +182 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/locale-switching.md +226 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/localization-setup.md +137 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/plural-gender.md +159 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/text-direction.md +199 -0
- package/templates/base/skills/mobile/flutter/monitoring/SKILL.md +81 -0
- package/templates/base/skills/mobile/flutter/monitoring/references/monitoring-architecture.md +269 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/analytics.md +227 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/crashlytics-setup.md +195 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/logging.md +258 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/performance-monitoring.md +248 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/sentry-integration.md +249 -0
- package/templates/base/skills/mobile/flutter/networking/SKILL.md +88 -0
- package/templates/base/skills/mobile/flutter/networking/references/api-client-architecture.md +305 -0
- package/templates/base/skills/mobile/flutter/networking/rules/caching.md +212 -0
- package/templates/base/skills/mobile/flutter/networking/rules/connectivity.md +213 -0
- package/templates/base/skills/mobile/flutter/networking/rules/dio-setup.md +159 -0
- package/templates/base/skills/mobile/flutter/networking/rules/error-handling.md +209 -0
- package/templates/base/skills/mobile/flutter/networking/rules/interceptors.md +205 -0
- package/templates/base/skills/mobile/flutter/networking/rules/retrofit-patterns.md +194 -0
- package/templates/base/skills/mobile/flutter/push-notifications/SKILL.md +87 -0
- package/templates/base/skills/mobile/flutter/push-notifications/references/notification-architecture.md +340 -0
- package/templates/base/skills/mobile/flutter/push-notifications/references/platform-setup.md +286 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/background-processing.md +308 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/deep-linking.md +217 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/fcm-setup.md +164 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/local-notifications.md +262 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/notification-handling.md +210 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/notification-permissions.md +246 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/rich-notifications.md +320 -0
- package/templates/base/skills/mobile/flutter/references/freezed-patterns.md +162 -0
- package/templates/base/skills/mobile/flutter/references/project-structure.md +170 -0
- package/templates/base/skills/mobile/flutter/rules/animations.md +112 -0
- package/templates/base/skills/mobile/flutter/rules/architecture.md +121 -0
- package/templates/base/skills/mobile/flutter/rules/navigation-routing.md +117 -0
- package/templates/base/skills/mobile/flutter/rules/performance.md +112 -0
- package/templates/base/skills/mobile/flutter/rules/platform-adaptive.md +126 -0
- package/templates/base/skills/mobile/flutter/rules/state-management.md +110 -0
- package/templates/base/skills/mobile/flutter/rules/testing.md +131 -0
- package/templates/base/skills/mobile/flutter/rules/widget-conventions.md +122 -0
- package/templates/base/skills/mobile/flutter/security/SKILL.md +86 -0
- package/templates/base/skills/mobile/flutter/security/references/mobile-security-checklist.md +168 -0
- package/templates/base/skills/mobile/flutter/security/rules/api-key-protection.md +206 -0
- package/templates/base/skills/mobile/flutter/security/rules/authentication.md +248 -0
- package/templates/base/skills/mobile/flutter/security/rules/data-protection.md +271 -0
- package/templates/base/skills/mobile/flutter/security/rules/obfuscation.md +213 -0
- package/templates/base/skills/mobile/flutter/security/rules/secure-storage.md +171 -0
- package/templates/base/skills/mobile/flutter/security/rules/ssl-pinning.md +197 -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/{common → base}/timsquad/retrospective/metrics/metrics-schema.json +46 -1
- package/templates/platforms/claude-code/CLAUDE.md.template +89 -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/scripts/completion-guard.sh +57 -0
- package/templates/platforms/claude-code/scripts/phase-guard.sh +79 -0
- package/templates/platforms/claude-code/settings.json +98 -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/mobile-app/config.yaml +123 -0
- package/templates/project-types/mobile-app/process/workflow.xml +191 -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 -311
- package/templates/common/claude/agents/tsq-designer.md +0 -323
- package/templates/common/claude/agents/tsq-developer.md +0 -177
- package/templates/common/claude/agents/tsq-planner.md +0 -190
- package/templates/common/claude/agents/tsq-prompter.md +0 -356
- package/templates/common/claude/agents/tsq-qa.md +0 -168
- package/templates/common/claude/agents/tsq-retro.md +0 -193
- package/templates/common/claude/agents/tsq-security.md +0 -221
- package/templates/common/claude/hooks/auto-metrics.sh +0 -165
- package/templates/common/claude/hooks/auto-worklog.sh +0 -245
- package/templates/common/claude/hooks/event-logger.sh +0 -208
- package/templates/common/claude/settings.json +0 -86
- 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 -132
- /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/phase-checklist.yaml +0 -0
- /package/templates/{common → base}/timsquad/process/state-machine.xml +0 -0
- /package/templates/{common → base}/timsquad/process/validation-rules.xml +0 -0
- /package/templates/{common → base}/timsquad/process/workflow-base.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,185 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TDD Techniques
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: tdd, testing, techniques
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# TDD Techniques (Kent Beck)
|
|
8
|
+
|
|
9
|
+
## Fake It ('Til You Make It)
|
|
10
|
+
하드코딩으로 먼저 통과시킨 후, 점진적으로 일반화.
|
|
11
|
+
구현 방법이 불확실할 때, 작은 단계로 진행하고 싶을 때 사용.
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
// Step 1: 테스트 작성
|
|
15
|
+
it('should add two numbers', () => {
|
|
16
|
+
expect(add(2, 3)).toBe(5);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Step 2: Fake It - 하드코딩으로 통과
|
|
20
|
+
function add(a: number, b: number): number {
|
|
21
|
+
return 5; // ✅ 테스트 통과!
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Step 3: 테스트 추가로 일반화 강제
|
|
25
|
+
it('should add different numbers', () => {
|
|
26
|
+
expect(add(1, 1)).toBe(2);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Step 4: 이제 일반화 필요
|
|
30
|
+
function add(a: number, b: number): number {
|
|
31
|
+
return a + b;
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Triangulation
|
|
36
|
+
2개 이상의 테스트로 일반화를 강제. 일반화 방향이 불명확할 때 사용.
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// Test 1: 기본 케이스
|
|
40
|
+
it('should return 10% discount for $150', () => {
|
|
41
|
+
expect(calculateDiscount(150)).toBe(15);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Test 2: 삼각측량 - 다른 값으로 일반화 강제
|
|
45
|
+
it('should return 10% discount for $200', () => {
|
|
46
|
+
expect(calculateDiscount(200)).toBe(20);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Test 3: 경계 조건 삼각측량
|
|
50
|
+
it('should return 0 discount for $100 or less', () => {
|
|
51
|
+
expect(calculateDiscount(100)).toBe(0);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
function calculateDiscount(total: number): number {
|
|
55
|
+
if (total <= 100) return 0;
|
|
56
|
+
return total * 0.1;
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Obvious Implementation
|
|
61
|
+
구현이 명확하면 바로 작성. 자신감이 떨어지면 Fake It으로 돌아가기.
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
it('should return full name', () => {
|
|
65
|
+
const user = { firstName: 'John', lastName: 'Doe' };
|
|
66
|
+
expect(getFullName(user)).toBe('John Doe');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
function getFullName(user: { firstName: string; lastName: string }): string {
|
|
70
|
+
return `${user.firstName} ${user.lastName}`;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## One to Many
|
|
75
|
+
먼저 단일 항목으로 구현, 그 다음 컬렉션으로 확장.
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// Step 1: 단일 항목
|
|
79
|
+
it('should calculate total for one item', () => {
|
|
80
|
+
expect(calculateTotal([{ price: 100, quantity: 2 }])).toBe(200);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Step 2: 여러 항목으로 확장
|
|
84
|
+
it('should calculate total for multiple items', () => {
|
|
85
|
+
expect(calculateTotal([
|
|
86
|
+
{ price: 100, quantity: 2 },
|
|
87
|
+
{ price: 50, quantity: 1 },
|
|
88
|
+
])).toBe(250);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
function calculateTotal(items: Item[]): number {
|
|
92
|
+
return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Assert First
|
|
97
|
+
테스트 작성 시 assertion부터 시작, 역방향으로 구성.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// Step 1: Assertion 먼저 → Step 2: 함수 호출 → Step 3: Given 구성
|
|
101
|
+
it('should complete pending order', () => {
|
|
102
|
+
const order = createOrder({ id: '1', status: 'pending' });
|
|
103
|
+
const result = completeOrder(order);
|
|
104
|
+
expect(result).toEqual({ id: '1', status: 'completed' });
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Starter Test
|
|
109
|
+
가장 단순한 테스트로 시작하여 동작하는 코드 확보. 어디서 시작할지 모를 때 사용.
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// Good: 가장 단순한 케이스로 시작
|
|
113
|
+
it('should create an order', () => {
|
|
114
|
+
const order = createOrder({ userId: '1' });
|
|
115
|
+
expect(order).toBeDefined();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// 점진적 확장
|
|
119
|
+
it('should add item to order', () => { ... });
|
|
120
|
+
it('should calculate subtotal', () => { ... });
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Test Data Builder
|
|
124
|
+
테스트 데이터 생성을 빌더 패턴으로 추상화. 테스트마다 비슷한 객체 생성이 반복될 때 사용.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
class UserBuilder {
|
|
128
|
+
private user: Partial<User> = {
|
|
129
|
+
id: 'default-id',
|
|
130
|
+
email: 'test@example.com',
|
|
131
|
+
name: 'Test User',
|
|
132
|
+
role: 'user',
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
withRole(role: 'admin' | 'user') { this.user.role = role; return this; }
|
|
136
|
+
build(): User { return this.user as User; }
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
it('should allow admin to delete users', () => {
|
|
140
|
+
const admin = new UserBuilder().withRole('admin').build();
|
|
141
|
+
expect(deleteUser(admin, 'target-123')).toBe(true);
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Tidying
|
|
146
|
+
리팩토링 전 작은 정리. 변수 추출, 메서드 추출 등.
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
// Before: 지저분한 코드
|
|
150
|
+
function processOrder(order) {
|
|
151
|
+
if (order.items.reduce((s, i) => s + i.price * i.qty, 0) > 100 && order.user.level === 'gold') {
|
|
152
|
+
return order.items.reduce((s, i) => s + i.price * i.qty, 0) * 0.9;
|
|
153
|
+
}
|
|
154
|
+
return order.items.reduce((s, i) => s + i.price * i.qty, 0);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// After: 변수/함수 추출
|
|
158
|
+
function calculateSubtotal(items: Item[]): number {
|
|
159
|
+
return items.reduce((sum, item) => sum + item.price * item.qty, 0);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function processOrder(order) {
|
|
163
|
+
const subtotal = calculateSubtotal(order.items);
|
|
164
|
+
const qualifiesForDiscount = subtotal > 100 && order.user.level === 'gold';
|
|
165
|
+
return qualifiesForDiscount ? subtotal * 0.9 : subtotal;
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Learning Test
|
|
170
|
+
외부 라이브러리/API 학습용 테스트. 새 라이브러리 사용 전 동작 확인.
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
describe('Prisma Learning Tests', () => {
|
|
174
|
+
it('should create and find user', async () => {
|
|
175
|
+
const user = await prisma.user.create({ data: { email: 'test@test.com', name: 'Test' } });
|
|
176
|
+
const found = await prisma.user.findUnique({ where: { id: user.id } });
|
|
177
|
+
expect(found).toEqual(user);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should return null for non-existent user', async () => {
|
|
181
|
+
const found = await prisma.user.findUnique({ where: { id: 'non-existent' } });
|
|
182
|
+
expect(found).toBeNull();
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dart
|
|
3
|
+
description: Dart 언어 가이드라인. Sound null safety, 패턴 매칭, sealed class, 비동기 프로그래밍, Effective Dart 스타일.
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
tags: [dart, language, null-safety, async]
|
|
6
|
+
user-invocable: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Dart Language Guidelines
|
|
10
|
+
|
|
11
|
+
Dart 3+ 기반 언어 패턴과 컨벤션. Flutter/서버 공통 적용.
|
|
12
|
+
|
|
13
|
+
## Philosophy
|
|
14
|
+
|
|
15
|
+
- Null safety는 타협 없음 — `!` 대신 패턴으로 해결
|
|
16
|
+
- 비동기는 구조화 — Future 체이닝보다 async/await
|
|
17
|
+
- Sealed class로 불가능한 상태를 불가능하게
|
|
18
|
+
- Effective Dart가 스타일 기준
|
|
19
|
+
|
|
20
|
+
## Rules
|
|
21
|
+
|
|
22
|
+
| Priority | Rule | Description |
|
|
23
|
+
|----------|------|-------------|
|
|
24
|
+
| CRITICAL | [null-safety](rules/null-safety.md) | Sound null safety 패턴, late/! 남용 방지 |
|
|
25
|
+
| CRITICAL | [async-patterns](rules/async-patterns.md) | Future, Stream, Isolate, 에러 전파 |
|
|
26
|
+
| HIGH | [type-system](rules/type-system.md) | Sealed class, 패턴 매칭, Records (Dart 3+) |
|
|
27
|
+
| HIGH | [code-style](rules/code-style.md) | Effective Dart, 네이밍, 문서화, linter 규칙 |
|
|
28
|
+
|
|
29
|
+
## Quick Rules
|
|
30
|
+
|
|
31
|
+
### Null Safety
|
|
32
|
+
- `String?` 사용 시 반드시 null 체크 후 접근
|
|
33
|
+
- `!` (bang operator) 금지 — if/case/??로 해결
|
|
34
|
+
- `late` 는 lifecycle이 보장될 때만 (initState 등)
|
|
35
|
+
- collection은 `whereType<T>()`로 null 필터링
|
|
36
|
+
|
|
37
|
+
### 비동기
|
|
38
|
+
- async/await 우선, then() 체이닝 금지
|
|
39
|
+
- 독립 작업은 `Future.wait([])` 로 병렬 실행
|
|
40
|
+
- Stream 구독은 반드시 cancel (dispose)
|
|
41
|
+
- 무거운 연산은 `Isolate.run()` 또는 `compute()`
|
|
42
|
+
- Zone.current로 에러 포착하지 말 것 — try/catch 명시
|
|
43
|
+
|
|
44
|
+
### 타입 시스템 (Dart 3+)
|
|
45
|
+
- `sealed class` 로 상태/에러 모델링 → switch exhaustive 체크
|
|
46
|
+
- Records `(int, String)` 로 경량 튜플
|
|
47
|
+
- 패턴 매칭 `if (value case Pattern())` 적극 활용
|
|
48
|
+
- `extension type` 으로 zero-cost wrapper (ID 타입 등)
|
|
49
|
+
|
|
50
|
+
### 스타일
|
|
51
|
+
- `dart_style` 포매터 + `analysis_options.yaml` strict
|
|
52
|
+
- lowerCamelCase (변수/함수), UpperCamelCase (클래스/enum)
|
|
53
|
+
- 공개 API에 `///` dartdoc 필수
|
|
54
|
+
- `part`/`part of` 금지 — 파일 분리로 해결
|
|
55
|
+
|
|
56
|
+
## Checklist
|
|
57
|
+
|
|
58
|
+
| Priority | Item |
|
|
59
|
+
|----------|------|
|
|
60
|
+
| CRITICAL | Bang operator (!) 없음 |
|
|
61
|
+
| CRITICAL | async/await 사용 (then 체이닝 없음) |
|
|
62
|
+
| CRITICAL | Stream 구독 dispose 처리 |
|
|
63
|
+
| CRITICAL | sealed class로 상태 모델링 |
|
|
64
|
+
| HIGH | Future.wait으로 병렬 처리 |
|
|
65
|
+
| HIGH | late 사용 최소화 (lifecycle 보장 시만) |
|
|
66
|
+
| HIGH | Effective Dart 네이밍 준수 |
|
|
67
|
+
| HIGH | 공개 API dartdoc 작성 |
|
|
68
|
+
| MEDIUM | extension type으로 ID 타입 래핑 |
|
|
69
|
+
| MEDIUM | analysis_options strict 모드 |
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Async Patterns
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
tags: async, future, stream, isolate
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Async Patterns
|
|
8
|
+
|
|
9
|
+
Dart의 비동기 프로그래밍 핵심 패턴. async/await, Stream, Isolate.
|
|
10
|
+
|
|
11
|
+
### async/await 우선
|
|
12
|
+
|
|
13
|
+
**Incorrect:**
|
|
14
|
+
```dart
|
|
15
|
+
Future<User> fetchUser(String id) {
|
|
16
|
+
return api.get('/users/$id')
|
|
17
|
+
.then((response) => User.fromJson(response.data))
|
|
18
|
+
.catchError((e) => throw FetchException(e.toString()));
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct:**
|
|
23
|
+
```dart
|
|
24
|
+
Future<User> fetchUser(String id) async {
|
|
25
|
+
try {
|
|
26
|
+
final response = await api.get('/users/$id');
|
|
27
|
+
return User.fromJson(response.data);
|
|
28
|
+
} on DioException catch (e) {
|
|
29
|
+
throw FetchException(e.message ?? 'Unknown error');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 병렬 실행
|
|
35
|
+
|
|
36
|
+
**Incorrect:**
|
|
37
|
+
```dart
|
|
38
|
+
final user = await fetchUser(id); // 1초
|
|
39
|
+
final posts = await fetchPosts(id); // 1초
|
|
40
|
+
final friends = await fetchFriends(id); // 1초 → 총 3초
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Correct:**
|
|
44
|
+
```dart
|
|
45
|
+
final (user, posts, friends) = await (
|
|
46
|
+
fetchUser(id),
|
|
47
|
+
fetchPosts(id),
|
|
48
|
+
fetchFriends(id),
|
|
49
|
+
).wait; // 총 ~1초 (Dart 3 record destructuring)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Stream 관리
|
|
53
|
+
|
|
54
|
+
**Incorrect:**
|
|
55
|
+
```dart
|
|
56
|
+
class _ChatState extends State<ChatScreen> {
|
|
57
|
+
@override
|
|
58
|
+
void initState() {
|
|
59
|
+
super.initState();
|
|
60
|
+
chatStream.listen((msg) => setState(() => messages.add(msg)));
|
|
61
|
+
// 구독 해제 안 됨 → 메모리 누수
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Correct:**
|
|
67
|
+
```dart
|
|
68
|
+
class _ChatState extends State<ChatScreen> {
|
|
69
|
+
StreamSubscription<Message>? _subscription;
|
|
70
|
+
|
|
71
|
+
@override
|
|
72
|
+
void initState() {
|
|
73
|
+
super.initState();
|
|
74
|
+
_subscription = chatStream.listen(
|
|
75
|
+
(msg) => setState(() => messages.add(msg)),
|
|
76
|
+
onError: (e) => _handleError(e),
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@override
|
|
81
|
+
void dispose() {
|
|
82
|
+
_subscription?.cancel();
|
|
83
|
+
super.dispose();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Isolate (무거운 연산)
|
|
89
|
+
|
|
90
|
+
**Incorrect:**
|
|
91
|
+
```dart
|
|
92
|
+
// 메인 스레드에서 JSON 파싱 → UI 프레임 드롭
|
|
93
|
+
final data = jsonDecode(hugeJsonString) as Map<String, dynamic>;
|
|
94
|
+
final items = (data['items'] as List).map(Item.fromJson).toList();
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Correct:**
|
|
98
|
+
```dart
|
|
99
|
+
// Isolate에서 실행 → UI 프레임 유지
|
|
100
|
+
final items = await Isolate.run(() {
|
|
101
|
+
final data = jsonDecode(hugeJsonString) as Map<String, dynamic>;
|
|
102
|
+
return (data['items'] as List).map(Item.fromJson).toList();
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 규칙
|
|
107
|
+
|
|
108
|
+
- `then()` 체이닝 금지 → async/await
|
|
109
|
+
- 독립 Future는 `.wait` (Dart 3) 또는 `Future.wait([])`로 병렬
|
|
110
|
+
- Stream 구독은 반드시 `cancel()` (dispose에서)
|
|
111
|
+
- 100ms+ 연산은 `Isolate.run()` 검토
|
|
112
|
+
- `completer` 직접 사용 금지 (async/await로 대체 가능)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Code Style (Effective Dart)
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: style, naming, linting, documentation
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Code Style (Effective Dart)
|
|
8
|
+
|
|
9
|
+
Effective Dart 기반 코딩 컨벤션. `dart_style` 포매터 + strict analysis_options.
|
|
10
|
+
|
|
11
|
+
### analysis_options.yaml
|
|
12
|
+
|
|
13
|
+
```yaml
|
|
14
|
+
include: package:flutter_lints/flutter.yaml
|
|
15
|
+
# 또는 non-Flutter: package:lints/recommended.yaml
|
|
16
|
+
|
|
17
|
+
linter:
|
|
18
|
+
rules:
|
|
19
|
+
# 필수 추가 규칙
|
|
20
|
+
- prefer_const_constructors
|
|
21
|
+
- prefer_const_declarations
|
|
22
|
+
- avoid_dynamic_calls
|
|
23
|
+
- unawaited_futures
|
|
24
|
+
- cancel_subscriptions
|
|
25
|
+
- close_sinks
|
|
26
|
+
- prefer_final_locals
|
|
27
|
+
- avoid_print # debugPrint 사용
|
|
28
|
+
- require_trailing_commas
|
|
29
|
+
|
|
30
|
+
analyzer:
|
|
31
|
+
errors:
|
|
32
|
+
missing_return: error
|
|
33
|
+
unawaited_futures: warning
|
|
34
|
+
language:
|
|
35
|
+
strict-casts: true
|
|
36
|
+
strict-inference: true
|
|
37
|
+
strict-raw-types: true
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 네이밍
|
|
41
|
+
|
|
42
|
+
| 종류 | 규칙 | 예시 |
|
|
43
|
+
|------|------|------|
|
|
44
|
+
| 클래스, enum, typedef | UpperCamelCase | `UserProfile`, `AuthState` |
|
|
45
|
+
| 변수, 함수, 파라미터 | lowerCamelCase | `userName`, `fetchData()` |
|
|
46
|
+
| 상수 | lowerCamelCase | `defaultTimeout` (UPPER_SNAKE 금지) |
|
|
47
|
+
| 파일 | snake_case | `user_profile.dart` |
|
|
48
|
+
| 라이브러리 접두사 | snake_case | `import 'x' as my_lib` |
|
|
49
|
+
|
|
50
|
+
**Incorrect:**
|
|
51
|
+
```dart
|
|
52
|
+
const MAX_RETRY_COUNT = 3; // UPPER_SNAKE
|
|
53
|
+
class user_service { } // snake_case 클래스
|
|
54
|
+
String UserName = ''; // UpperCamel 변수
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Correct:**
|
|
58
|
+
```dart
|
|
59
|
+
const maxRetryCount = 3;
|
|
60
|
+
class UserService { }
|
|
61
|
+
String userName = '';
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Import 정리
|
|
65
|
+
|
|
66
|
+
```dart
|
|
67
|
+
// 1. dart: 표준 라이브러리
|
|
68
|
+
import 'dart:async';
|
|
69
|
+
import 'dart:convert';
|
|
70
|
+
|
|
71
|
+
// 2. package: 외부 패키지
|
|
72
|
+
import 'package:flutter/material.dart';
|
|
73
|
+
import 'package:riverpod/riverpod.dart';
|
|
74
|
+
|
|
75
|
+
// 3. 프로젝트 내부 (상대 경로 금지)
|
|
76
|
+
import 'package:my_app/features/auth/domain/user.dart';
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 문서화
|
|
80
|
+
|
|
81
|
+
```dart
|
|
82
|
+
/// 사용자 프로필을 가져온다.
|
|
83
|
+
///
|
|
84
|
+
/// [userId]에 해당하는 사용자가 없으면 null 반환.
|
|
85
|
+
/// 네트워크 에러 시 [FetchException] 발생.
|
|
86
|
+
Future<UserProfile?> fetchProfile(String userId) async { ... }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 규칙
|
|
90
|
+
|
|
91
|
+
- `dart format .` 자동 포매팅 (커밋 전 필수)
|
|
92
|
+
- 상대 import 금지 → `package:` import
|
|
93
|
+
- `print()` 금지 → `debugPrint()` 또는 logger
|
|
94
|
+
- `part`/`part of` 금지 → 파일 분리
|
|
95
|
+
- trailing comma 필수 (위젯 트리 가독성)
|
|
96
|
+
- `prefer_final_locals` 활성화
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Sound Null Safety
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
tags: null-safety, dart3, patterns
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Sound Null Safety
|
|
8
|
+
|
|
9
|
+
Dart의 null safety는 컴파일 타임에 null 참조를 방지한다.
|
|
10
|
+
`!`와 `late` 남용은 런타임 크래시를 초래하므로 패턴으로 해결.
|
|
11
|
+
|
|
12
|
+
### Bang Operator (!) 금지
|
|
13
|
+
|
|
14
|
+
**Incorrect:**
|
|
15
|
+
```dart
|
|
16
|
+
final user = users.firstWhere((u) => u.id == id);
|
|
17
|
+
print(user!.name); // NoSuchElementException 위험
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct:**
|
|
21
|
+
```dart
|
|
22
|
+
final user = users.where((u) => u.id == id).firstOrNull;
|
|
23
|
+
if (user case final found?) {
|
|
24
|
+
print(found.name);
|
|
25
|
+
} else {
|
|
26
|
+
throw UserNotFoundException(id);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Nullable Collection 처리
|
|
31
|
+
|
|
32
|
+
**Incorrect:**
|
|
33
|
+
```dart
|
|
34
|
+
final List<String?> items = getData();
|
|
35
|
+
for (final item in items) {
|
|
36
|
+
print(item!.length); // null이면 크래시
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Correct:**
|
|
41
|
+
```dart
|
|
42
|
+
final List<String?> items = getData();
|
|
43
|
+
final validItems = items.whereType<String>(); // null 필터링 + 타입 내로잉
|
|
44
|
+
for (final item in validItems) {
|
|
45
|
+
print(item.length); // String 보장
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### late 사용 기준
|
|
50
|
+
|
|
51
|
+
**Incorrect:**
|
|
52
|
+
```dart
|
|
53
|
+
class MyWidget extends StatefulWidget { ... }
|
|
54
|
+
class _MyWidgetState extends State<MyWidget> {
|
|
55
|
+
late final ApiService api; // dispose 전에 접근하면 크래시
|
|
56
|
+
late String userName; // 초기화 보장 없음
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Correct:**
|
|
61
|
+
```dart
|
|
62
|
+
class _MyWidgetState extends State<MyWidget> {
|
|
63
|
+
late final TextEditingController _controller; // initState에서 반드시 초기화
|
|
64
|
+
|
|
65
|
+
@override
|
|
66
|
+
void initState() {
|
|
67
|
+
super.initState();
|
|
68
|
+
_controller = TextEditingController();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@override
|
|
72
|
+
void dispose() {
|
|
73
|
+
_controller.dispose();
|
|
74
|
+
super.dispose();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 규칙
|
|
80
|
+
|
|
81
|
+
- `late` 는 lifecycle 보장 컨텍스트에서만: `initState`, `setUp`, 생성자 body
|
|
82
|
+
- `!` 대신 `case`, `??`, `?.` 사용
|
|
83
|
+
- `firstWhere` → `firstOrNull` + null 체크
|
|
84
|
+
- 함수 파라미터에서 `required` 키워드로 null 방지
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Type System (Dart 3+)
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: sealed-class, pattern-matching, records, extension-type
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Type System (Dart 3+)
|
|
8
|
+
|
|
9
|
+
Dart 3의 sealed class, 패턴 매칭, records, extension type으로 타입 안전한 코드 작성.
|
|
10
|
+
|
|
11
|
+
### Sealed Class (상태 모델링)
|
|
12
|
+
|
|
13
|
+
**Incorrect:**
|
|
14
|
+
```dart
|
|
15
|
+
enum LoadState { loading, success, error }
|
|
16
|
+
|
|
17
|
+
class ScreenState {
|
|
18
|
+
final LoadState state;
|
|
19
|
+
final List<Item>? data; // success일 때만 유효
|
|
20
|
+
final String? error; // error일 때만 유효
|
|
21
|
+
// 불가능한 조합이 가능: state=loading + data!=null
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Correct:**
|
|
26
|
+
```dart
|
|
27
|
+
sealed class ScreenState {}
|
|
28
|
+
class Loading extends ScreenState {}
|
|
29
|
+
class Success extends ScreenState {
|
|
30
|
+
final List<Item> data;
|
|
31
|
+
Success(this.data);
|
|
32
|
+
}
|
|
33
|
+
class Failure extends ScreenState {
|
|
34
|
+
final String message;
|
|
35
|
+
Failure(this.message);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// exhaustive switch — 새 상태 추가 시 컴파일 에러
|
|
39
|
+
Widget build(BuildContext context) => switch (state) {
|
|
40
|
+
Loading() => const CircularProgressIndicator(),
|
|
41
|
+
Success(:final data) => ItemList(items: data),
|
|
42
|
+
Failure(:final message) => ErrorView(message: message),
|
|
43
|
+
};
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 패턴 매칭
|
|
47
|
+
|
|
48
|
+
**Incorrect:**
|
|
49
|
+
```dart
|
|
50
|
+
if (response is Map<String, dynamic>) {
|
|
51
|
+
if (response.containsKey('data')) {
|
|
52
|
+
final data = response['data'];
|
|
53
|
+
if (data is List) {
|
|
54
|
+
// 중첩 if 지옥
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Correct:**
|
|
61
|
+
```dart
|
|
62
|
+
if (response case {'data': List<Map<String, dynamic>> items}) {
|
|
63
|
+
final users = items.map(User.fromJson).toList();
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Records (경량 튜플)
|
|
68
|
+
|
|
69
|
+
**Incorrect:**
|
|
70
|
+
```dart
|
|
71
|
+
// 위치 좌표를 위한 불필요한 클래스
|
|
72
|
+
class LatLng {
|
|
73
|
+
final double lat;
|
|
74
|
+
final double lng;
|
|
75
|
+
LatLng(this.lat, this.lng);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Correct:**
|
|
80
|
+
```dart
|
|
81
|
+
// Named record로 간결하게
|
|
82
|
+
typedef LatLng = ({double lat, double lng});
|
|
83
|
+
|
|
84
|
+
LatLng getLocation() => (lat: 1.3521, lng: 103.8198);
|
|
85
|
+
|
|
86
|
+
final (:lat, :lng) = getLocation(); // 구조 분해
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Extension Type (Zero-Cost Wrapper)
|
|
90
|
+
|
|
91
|
+
```dart
|
|
92
|
+
extension type UserId(String value) {
|
|
93
|
+
factory UserId.fromInt(int id) => UserId('user_$id');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
extension type PostId(String value) {}
|
|
97
|
+
|
|
98
|
+
// 컴파일 타임에 타입 구분, 런타임 오버헤드 0
|
|
99
|
+
void fetchUser(UserId id) { ... }
|
|
100
|
+
void fetchPost(PostId id) { ... }
|
|
101
|
+
|
|
102
|
+
fetchUser(PostId('abc')); // 컴파일 에러!
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 규칙
|
|
106
|
+
|
|
107
|
+
- 상태/에러/결과는 `sealed class` + exhaustive switch
|
|
108
|
+
- Map 접근은 패턴 매칭 `case` 사용
|
|
109
|
+
- 2-3개 값 반환은 Record `(int, String)` 사용 (클래스 불필요)
|
|
110
|
+
- ID 타입은 `extension type`으로 구분
|
|
111
|
+
- `dynamic` 타입 금지 → `Object?` + 패턴 매칭
|