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,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Freezed + JSON Serializable Patterns
|
|
3
|
+
category: guide
|
|
4
|
+
tags: freezed, json-serializable, immutable, dto
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Freezed + JSON Serializable
|
|
8
|
+
|
|
9
|
+
불변 데이터 모델 + JSON 직렬화 패턴. Domain Entity와 DTO 분리.
|
|
10
|
+
|
|
11
|
+
### 기본 설정
|
|
12
|
+
|
|
13
|
+
```yaml
|
|
14
|
+
# pubspec.yaml
|
|
15
|
+
dependencies:
|
|
16
|
+
freezed_annotation: ^2.4.0
|
|
17
|
+
json_annotation: ^4.9.0
|
|
18
|
+
|
|
19
|
+
dev_dependencies:
|
|
20
|
+
freezed: ^2.5.0
|
|
21
|
+
json_serializable: ^6.8.0
|
|
22
|
+
build_runner: ^2.4.0
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# 코드 생성
|
|
27
|
+
dart run build_runner build --delete-conflicting-outputs
|
|
28
|
+
|
|
29
|
+
# 감시 모드 (개발 중)
|
|
30
|
+
dart run build_runner watch --delete-conflicting-outputs
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Domain Entity (freezed)
|
|
34
|
+
|
|
35
|
+
```dart
|
|
36
|
+
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
37
|
+
|
|
38
|
+
part 'match.freezed.dart';
|
|
39
|
+
|
|
40
|
+
@freezed
|
|
41
|
+
class Match with _$Match {
|
|
42
|
+
const factory Match({
|
|
43
|
+
required String id,
|
|
44
|
+
required Sport sport,
|
|
45
|
+
required String title,
|
|
46
|
+
required DateTime scheduledAt,
|
|
47
|
+
required MatchLocation location,
|
|
48
|
+
required int maxPlayers,
|
|
49
|
+
@Default([]) List<String> playerIds,
|
|
50
|
+
@Default(MatchStatus.open) MatchStatus status,
|
|
51
|
+
}) = _Match;
|
|
52
|
+
|
|
53
|
+
// 커스텀 getter (const factory 밑에 private 생성자 필요)
|
|
54
|
+
const Match._();
|
|
55
|
+
|
|
56
|
+
bool get isFull => playerIds.length >= maxPlayers;
|
|
57
|
+
bool get isUpcoming => scheduledAt.isAfter(DateTime.now());
|
|
58
|
+
int get availableSlots => maxPlayers - playerIds.length;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
enum Sport { tennis, badminton, pickleball, paddle }
|
|
62
|
+
enum MatchStatus { open, full, inProgress, completed, cancelled }
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### DTO (freezed + json_serializable)
|
|
66
|
+
|
|
67
|
+
```dart
|
|
68
|
+
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
69
|
+
|
|
70
|
+
part 'match_dto.freezed.dart';
|
|
71
|
+
part 'match_dto.g.dart';
|
|
72
|
+
|
|
73
|
+
@freezed
|
|
74
|
+
class MatchDto with _$MatchDto {
|
|
75
|
+
const factory MatchDto({
|
|
76
|
+
required String id,
|
|
77
|
+
required String sport,
|
|
78
|
+
required String title,
|
|
79
|
+
@JsonKey(name: 'scheduled_at') required String scheduledAt,
|
|
80
|
+
required MatchLocationDto location,
|
|
81
|
+
@JsonKey(name: 'max_players') required int maxPlayers,
|
|
82
|
+
@JsonKey(name: 'player_ids') @Default([]) List<String> playerIds,
|
|
83
|
+
@Default('open') String status,
|
|
84
|
+
}) = _MatchDto;
|
|
85
|
+
|
|
86
|
+
factory MatchDto.fromJson(Map<String, dynamic> json) =>
|
|
87
|
+
_$MatchDtoFromJson(json);
|
|
88
|
+
|
|
89
|
+
const MatchDto._();
|
|
90
|
+
|
|
91
|
+
/// DTO → Domain 변환
|
|
92
|
+
Match toDomain() => Match(
|
|
93
|
+
id: id,
|
|
94
|
+
sport: Sport.values.byName(sport),
|
|
95
|
+
title: title,
|
|
96
|
+
scheduledAt: DateTime.parse(scheduledAt),
|
|
97
|
+
location: location.toDomain(),
|
|
98
|
+
maxPlayers: maxPlayers,
|
|
99
|
+
playerIds: playerIds,
|
|
100
|
+
status: MatchStatus.values.byName(status),
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
/// Domain → DTO 변환
|
|
104
|
+
factory MatchDto.fromDomain(Match match) => MatchDto(
|
|
105
|
+
id: match.id,
|
|
106
|
+
sport: match.sport.name,
|
|
107
|
+
title: match.title,
|
|
108
|
+
scheduledAt: match.scheduledAt.toIso8601String(),
|
|
109
|
+
location: MatchLocationDto.fromDomain(match.location),
|
|
110
|
+
maxPlayers: match.maxPlayers,
|
|
111
|
+
playerIds: match.playerIds,
|
|
112
|
+
status: match.status.name,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Sealed Class + Freezed (상태)
|
|
118
|
+
|
|
119
|
+
```dart
|
|
120
|
+
@freezed
|
|
121
|
+
sealed class AuthState with _$AuthState {
|
|
122
|
+
const factory AuthState.initial() = AuthInitial;
|
|
123
|
+
const factory AuthState.loading() = AuthLoading;
|
|
124
|
+
const factory AuthState.authenticated(User user) = AuthAuthenticated;
|
|
125
|
+
const factory AuthState.unauthenticated() = AuthUnauthenticated;
|
|
126
|
+
const factory AuthState.error(String message) = AuthError;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// 사용: 패턴 매칭
|
|
130
|
+
Widget build(BuildContext context) {
|
|
131
|
+
final authState = ref.watch(authProvider);
|
|
132
|
+
|
|
133
|
+
return authState.when(
|
|
134
|
+
initial: () => const SplashScreen(),
|
|
135
|
+
loading: () => const LoadingScreen(),
|
|
136
|
+
authenticated: (user) => const HomeScreen(),
|
|
137
|
+
unauthenticated: () => const LoginScreen(),
|
|
138
|
+
error: (msg) => ErrorScreen(message: msg),
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### copyWith (불변 업데이트)
|
|
144
|
+
|
|
145
|
+
```dart
|
|
146
|
+
// freezed가 자동 생성하는 copyWith
|
|
147
|
+
final updatedMatch = match.copyWith(
|
|
148
|
+
status: MatchStatus.full,
|
|
149
|
+
playerIds: [...match.playerIds, newPlayerId],
|
|
150
|
+
);
|
|
151
|
+
// 원본 match는 변경 없음 (불변)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 규칙
|
|
155
|
+
|
|
156
|
+
- Domain Entity: `@freezed` (JSON 직렬화 없음, 순수 도메인)
|
|
157
|
+
- DTO: `@freezed` + `@JsonKey` + `fromJson`/`toJson`
|
|
158
|
+
- DTO → Domain: `.toDomain()` 메서드
|
|
159
|
+
- Domain → DTO: `DTO.fromDomain()` factory
|
|
160
|
+
- API 응답 key naming: `@JsonKey(name: 'snake_case')`
|
|
161
|
+
- 상태 모델: `@freezed sealed class` + `.when()` 패턴 매칭
|
|
162
|
+
- `build_runner watch` 개발 중 항상 실행
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Project Structure (Feature-First + Melos)
|
|
3
|
+
category: guide
|
|
4
|
+
tags: structure, monorepo, melos, feature-first
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Project Structure
|
|
8
|
+
|
|
9
|
+
Flutter Feature-first 디렉토리 구조 + Melos 모노레포 관리.
|
|
10
|
+
|
|
11
|
+
### 단일 앱 구조
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
my_app/
|
|
15
|
+
├── lib/
|
|
16
|
+
│ ├── main.dart # 엔트리포인트
|
|
17
|
+
│ ├── app.dart # MaterialApp + ProviderScope
|
|
18
|
+
│ ├── core/
|
|
19
|
+
│ │ ├── constants/
|
|
20
|
+
│ │ │ ├── app_colors.dart
|
|
21
|
+
│ │ │ ├── app_spacing.dart
|
|
22
|
+
│ │ │ └── api_endpoints.dart
|
|
23
|
+
│ │ ├── extensions/
|
|
24
|
+
│ │ │ ├── context_ext.dart # BuildContext 확장
|
|
25
|
+
│ │ │ └── string_ext.dart
|
|
26
|
+
│ │ ├── router/
|
|
27
|
+
│ │ │ ├── app_router.dart # GoRouter 정의
|
|
28
|
+
│ │ │ └── route_names.dart # 경로 상수
|
|
29
|
+
│ │ ├── theme/
|
|
30
|
+
│ │ │ ├── app_theme.dart # ThemeData
|
|
31
|
+
│ │ │ └── typography.dart
|
|
32
|
+
│ │ ├── network/
|
|
33
|
+
│ │ │ ├── api_client.dart # Dio/http 설정
|
|
34
|
+
│ │ │ └── api_interceptor.dart
|
|
35
|
+
│ │ └── providers/
|
|
36
|
+
│ │ ├── auth_provider.dart # 전역 인증 상태
|
|
37
|
+
│ │ └── locale_provider.dart
|
|
38
|
+
│ │
|
|
39
|
+
│ ├── features/
|
|
40
|
+
│ │ ├── auth/
|
|
41
|
+
│ │ │ ├── data/
|
|
42
|
+
│ │ │ │ ├── datasources/
|
|
43
|
+
│ │ │ │ │ └── auth_remote_datasource.dart
|
|
44
|
+
│ │ │ │ ├── dtos/
|
|
45
|
+
│ │ │ │ │ └── auth_response_dto.dart
|
|
46
|
+
│ │ │ │ │ └── auth_response_dto.g.dart # json_serializable
|
|
47
|
+
│ │ │ │ │ └── auth_response_dto.freezed.dart
|
|
48
|
+
│ │ │ │ └── repositories/
|
|
49
|
+
│ │ │ │ └── auth_repository_impl.dart
|
|
50
|
+
│ │ │ ├── domain/
|
|
51
|
+
│ │ │ │ ├── entities/
|
|
52
|
+
│ │ │ │ │ └── user.dart
|
|
53
|
+
│ │ │ │ │ └── user.freezed.dart
|
|
54
|
+
│ │ │ │ └── repositories/
|
|
55
|
+
│ │ │ │ └── auth_repository.dart # abstract
|
|
56
|
+
│ │ │ └── presentation/
|
|
57
|
+
│ │ │ ├── providers/
|
|
58
|
+
│ │ │ │ └── auth_provider.dart
|
|
59
|
+
│ │ │ ├── screens/
|
|
60
|
+
│ │ │ │ ├── login_screen.dart
|
|
61
|
+
│ │ │ │ └── signup_screen.dart
|
|
62
|
+
│ │ │ └── widgets/
|
|
63
|
+
│ │ │ └── social_login_buttons.dart
|
|
64
|
+
│ │ │
|
|
65
|
+
│ │ ├── match/
|
|
66
|
+
│ │ │ ├── data/...
|
|
67
|
+
│ │ │ ├── domain/...
|
|
68
|
+
│ │ │ └── presentation/...
|
|
69
|
+
│ │ │
|
|
70
|
+
│ │ └── community/
|
|
71
|
+
│ │ ├── data/...
|
|
72
|
+
│ │ ├── domain/...
|
|
73
|
+
│ │ └── presentation/...
|
|
74
|
+
│ │
|
|
75
|
+
│ └── shared/
|
|
76
|
+
│ ├── widgets/
|
|
77
|
+
│ │ ├── app_button.dart
|
|
78
|
+
│ │ ├── app_text_field.dart
|
|
79
|
+
│ │ └── loading_indicator.dart
|
|
80
|
+
│ └── utils/
|
|
81
|
+
│ ├── date_formatter.dart
|
|
82
|
+
│ └── validators.dart
|
|
83
|
+
│
|
|
84
|
+
├── test/
|
|
85
|
+
│ ├── features/
|
|
86
|
+
│ │ ├── auth/
|
|
87
|
+
│ │ │ ├── data/repositories/auth_repository_impl_test.dart
|
|
88
|
+
│ │ │ └── presentation/providers/auth_provider_test.dart
|
|
89
|
+
│ │ └── match/...
|
|
90
|
+
│ ├── fixtures/
|
|
91
|
+
│ │ └── test_data.dart # 공유 테스트 데이터
|
|
92
|
+
│ └── helpers/
|
|
93
|
+
│ └── pump_app.dart # testWidgets 헬퍼
|
|
94
|
+
│
|
|
95
|
+
├── integration_test/
|
|
96
|
+
│ └── match_flow_test.dart
|
|
97
|
+
│
|
|
98
|
+
├── assets/
|
|
99
|
+
│ ├── images/
|
|
100
|
+
│ ├── icons/
|
|
101
|
+
│ └── translations/ # ARB 파일 (i18n)
|
|
102
|
+
│
|
|
103
|
+
├── pubspec.yaml
|
|
104
|
+
├── analysis_options.yaml
|
|
105
|
+
└── l10n.yaml # 국제화 설정
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Melos 모노레포 구조
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
project_root/
|
|
112
|
+
├── melos.yaml
|
|
113
|
+
├── apps/
|
|
114
|
+
│ ├── mobile/ # Flutter 앱
|
|
115
|
+
│ │ ├── lib/
|
|
116
|
+
│ │ └── pubspec.yaml
|
|
117
|
+
│ └── admin/ # 관리자 웹 (선택)
|
|
118
|
+
│ ├── lib/
|
|
119
|
+
│ └── pubspec.yaml
|
|
120
|
+
├── packages/
|
|
121
|
+
│ ├── core/ # 공유 코어 (모델, 유틸)
|
|
122
|
+
│ │ ├── lib/
|
|
123
|
+
│ │ └── pubspec.yaml
|
|
124
|
+
│ ├── ui_kit/ # 공유 UI 컴포넌트
|
|
125
|
+
│ │ ├── lib/
|
|
126
|
+
│ │ └── pubspec.yaml
|
|
127
|
+
│ ├── api_client/ # API 클라이언트
|
|
128
|
+
│ │ ├── lib/
|
|
129
|
+
│ │ └── pubspec.yaml
|
|
130
|
+
│ └── auth/ # 인증 모듈
|
|
131
|
+
│ ├── lib/
|
|
132
|
+
│ └── pubspec.yaml
|
|
133
|
+
└── tools/
|
|
134
|
+
└── custom_lint_rules/ # 프로젝트 커스텀 린트
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### melos.yaml
|
|
138
|
+
|
|
139
|
+
```yaml
|
|
140
|
+
name: my_project
|
|
141
|
+
packages:
|
|
142
|
+
- apps/*
|
|
143
|
+
- packages/*
|
|
144
|
+
|
|
145
|
+
scripts:
|
|
146
|
+
analyze:
|
|
147
|
+
exec: dart analyze --fatal-infos
|
|
148
|
+
test:
|
|
149
|
+
exec: flutter test --coverage
|
|
150
|
+
format:
|
|
151
|
+
exec: dart format --set-exit-if-changed .
|
|
152
|
+
build_runner:
|
|
153
|
+
exec: dart run build_runner build --delete-conflicting-outputs
|
|
154
|
+
packageFilters:
|
|
155
|
+
dependsOn: build_runner
|
|
156
|
+
clean:
|
|
157
|
+
exec: flutter clean
|
|
158
|
+
|
|
159
|
+
command:
|
|
160
|
+
bootstrap:
|
|
161
|
+
usePubspecOverrides: true
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### 규칙
|
|
165
|
+
|
|
166
|
+
- feature 안에서 다른 feature 직접 import 금지
|
|
167
|
+
- 공유 로직은 `core/` 또는 `shared/`
|
|
168
|
+
- 모노레포: `melos bootstrap`으로 의존성 연결
|
|
169
|
+
- 테스트 디렉토리는 `lib/` 미러링 구조
|
|
170
|
+
- generated 파일 (`.g.dart`, `.freezed.dart`) → `.gitignore`에 추가하지 않음 (CI에서 재생성 비용)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Animations
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: animation, implicit, explicit, hero
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Animations
|
|
8
|
+
|
|
9
|
+
Flutter 애니메이션 패턴. 암시적(간단) → 명시적(복잡) 선택 기준.
|
|
10
|
+
|
|
11
|
+
### 선택 기준
|
|
12
|
+
|
|
13
|
+
| 복잡도 | 사용 | 예시 |
|
|
14
|
+
|--------|------|------|
|
|
15
|
+
| 단순 속성 변경 | `AnimatedContainer`, `AnimatedOpacity` | 페이드, 크기 변경 |
|
|
16
|
+
| 여러 위젯 전환 | `AnimatedSwitcher` | 탭 전환, 상태 전환 |
|
|
17
|
+
| 화면 간 공유 요소 | `Hero` | 카드 → 상세 전환 |
|
|
18
|
+
| 커스텀 곡선/시퀀스 | `AnimationController` + `Tween` | 복잡한 모션 |
|
|
19
|
+
| 반복/물리 기반 | `AnimationController` + `SpringSimulation` | 풀투리프레시 |
|
|
20
|
+
|
|
21
|
+
### 암시적 애니메이션 (간단)
|
|
22
|
+
|
|
23
|
+
```dart
|
|
24
|
+
// 상태에 따라 자동 전환
|
|
25
|
+
AnimatedContainer(
|
|
26
|
+
duration: const Duration(milliseconds: 300),
|
|
27
|
+
curve: Curves.easeInOut,
|
|
28
|
+
width: isExpanded ? 200 : 100,
|
|
29
|
+
height: isExpanded ? 200 : 100,
|
|
30
|
+
decoration: BoxDecoration(
|
|
31
|
+
color: isSelected ? Colors.blue : Colors.grey,
|
|
32
|
+
borderRadius: BorderRadius.circular(isExpanded ? 16 : 8),
|
|
33
|
+
),
|
|
34
|
+
child: content,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// 위젯 교체 시 전환
|
|
38
|
+
AnimatedSwitcher(
|
|
39
|
+
duration: const Duration(milliseconds: 200),
|
|
40
|
+
child: isLoading
|
|
41
|
+
? const CircularProgressIndicator(key: ValueKey('loading'))
|
|
42
|
+
: ContentView(key: ValueKey('content'), data: data),
|
|
43
|
+
);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Hero 전환
|
|
47
|
+
|
|
48
|
+
```dart
|
|
49
|
+
// 리스트 아이템
|
|
50
|
+
Hero(
|
|
51
|
+
tag: 'match-${match.id}',
|
|
52
|
+
child: MatchCard(match: match),
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// 상세 화면
|
|
56
|
+
Hero(
|
|
57
|
+
tag: 'match-${match.id}',
|
|
58
|
+
child: MatchDetailHeader(match: match),
|
|
59
|
+
);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 명시적 애니메이션 (복잡)
|
|
63
|
+
|
|
64
|
+
```dart
|
|
65
|
+
class PulseWidget extends StatefulWidget {
|
|
66
|
+
const PulseWidget({super.key, required this.child});
|
|
67
|
+
final Widget child;
|
|
68
|
+
|
|
69
|
+
@override
|
|
70
|
+
State<PulseWidget> createState() => _PulseWidgetState();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
class _PulseWidgetState extends State<PulseWidget>
|
|
74
|
+
with SingleTickerProviderStateMixin {
|
|
75
|
+
late final AnimationController _controller;
|
|
76
|
+
late final Animation<double> _scale;
|
|
77
|
+
|
|
78
|
+
@override
|
|
79
|
+
void initState() {
|
|
80
|
+
super.initState();
|
|
81
|
+
_controller = AnimationController(
|
|
82
|
+
duration: const Duration(milliseconds: 1000),
|
|
83
|
+
vsync: this,
|
|
84
|
+
)..repeat(reverse: true);
|
|
85
|
+
|
|
86
|
+
_scale = Tween(begin: 1.0, end: 1.1).animate(
|
|
87
|
+
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@override
|
|
92
|
+
void dispose() {
|
|
93
|
+
_controller.dispose();
|
|
94
|
+
super.dispose();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@override
|
|
98
|
+
Widget build(BuildContext context) {
|
|
99
|
+
return ScaleTransition(scale: _scale, child: widget.child);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 규칙
|
|
105
|
+
|
|
106
|
+
- 단순 속성 변경 → 암시적 (`Animated*` 위젯) 우선
|
|
107
|
+
- 위젯 교체 → `AnimatedSwitcher` + `key` 필수
|
|
108
|
+
- 화면 전환 공유 요소 → `Hero` (동일 tag)
|
|
109
|
+
- 커스텀 애니메이션 → `AnimationController` + `dispose()` 필수
|
|
110
|
+
- duration: 200-300ms (UI), 300-500ms (페이지 전환)
|
|
111
|
+
- `vsync: this` + `TickerProviderStateMixin` (프레임 동기화)
|
|
112
|
+
- 복잡한 시퀀스는 `staggered_animations` 패키지 검토
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Architecture (Feature-First + MVVM)
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
tags: architecture, feature-first, mvvm, clean-architecture
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Architecture (Feature-First + MVVM)
|
|
8
|
+
|
|
9
|
+
Flutter 공식 아키텍처 가이드(MVVM) + VGV 4-layer + Feature-first 구조 종합.
|
|
10
|
+
|
|
11
|
+
### 3-Layer 아키텍처
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
┌─ Presentation (UI) ─────────────────┐
|
|
15
|
+
│ Widget → ViewModel (Notifier) │ UI 렌더링 + 사용자 입력
|
|
16
|
+
│ ref.watch로 상태 구독 │
|
|
17
|
+
└─────────────────────────────────────┘
|
|
18
|
+
↕ (Domain Model)
|
|
19
|
+
┌─ Domain ────────────────────────────┐
|
|
20
|
+
│ Entity, ValueObject, UseCase │ 비즈니스 규칙 (선택 레이어)
|
|
21
|
+
│ 플랫폼/프레임워크 의존성 없음 │
|
|
22
|
+
└─────────────────────────────────────┘
|
|
23
|
+
↕ (Domain Model)
|
|
24
|
+
┌─ Data ──────────────────────────────┐
|
|
25
|
+
│ Repository → DataSource │ API/DB/캐시 접근
|
|
26
|
+
│ DTO ↔ Domain Model 변환 │
|
|
27
|
+
└─────────────────────────────────────┘
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Feature-First 디렉토리
|
|
31
|
+
|
|
32
|
+
**Incorrect:**
|
|
33
|
+
```
|
|
34
|
+
lib/
|
|
35
|
+
models/ # 모든 모델이 한 폴더
|
|
36
|
+
screens/ # 모든 화면이 한 폴더
|
|
37
|
+
services/ # 모든 서비스가 한 폴더
|
|
38
|
+
widgets/ # 모든 위젯이 한 폴더
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Correct:**
|
|
42
|
+
```
|
|
43
|
+
lib/
|
|
44
|
+
core/ # 공유 인프라
|
|
45
|
+
constants/
|
|
46
|
+
extensions/
|
|
47
|
+
router/
|
|
48
|
+
theme/
|
|
49
|
+
providers/ # 전역 provider (auth, locale 등)
|
|
50
|
+
features/
|
|
51
|
+
auth/
|
|
52
|
+
data/
|
|
53
|
+
datasources/ # AuthRemoteDataSource
|
|
54
|
+
dtos/ # AuthResponseDto (JSON 매핑)
|
|
55
|
+
repositories/ # AuthRepositoryImpl
|
|
56
|
+
domain/
|
|
57
|
+
entities/ # User
|
|
58
|
+
repositories/ # AuthRepository (abstract)
|
|
59
|
+
presentation/
|
|
60
|
+
providers/ # authProvider, loginNotifier
|
|
61
|
+
screens/ # LoginScreen, SignUpScreen
|
|
62
|
+
widgets/ # AuthForm, SocialLoginButtons
|
|
63
|
+
match/
|
|
64
|
+
data/...
|
|
65
|
+
domain/...
|
|
66
|
+
presentation/...
|
|
67
|
+
shared/
|
|
68
|
+
widgets/ # 재사용 UI 컴포넌트
|
|
69
|
+
utils/ # 순수 유틸리티 함수
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Repository 패턴
|
|
73
|
+
|
|
74
|
+
```dart
|
|
75
|
+
// Domain layer — 추상 인터페이스
|
|
76
|
+
abstract class MatchRepository {
|
|
77
|
+
Future<List<Match>> getMatches({required Sport sport});
|
|
78
|
+
Future<void> joinMatch(String matchId);
|
|
79
|
+
Stream<Match> watchMatch(String matchId);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Data layer — 구현
|
|
83
|
+
class MatchRepositoryImpl implements MatchRepository {
|
|
84
|
+
const MatchRepositoryImpl({
|
|
85
|
+
required this.remoteDataSource,
|
|
86
|
+
required this.localDataSource,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
final MatchRemoteDataSource remoteDataSource;
|
|
90
|
+
final MatchLocalDataSource localDataSource;
|
|
91
|
+
|
|
92
|
+
@override
|
|
93
|
+
Future<List<Match>> getMatches({required Sport sport}) async {
|
|
94
|
+
try {
|
|
95
|
+
final dtos = await remoteDataSource.fetchMatches(sport.name);
|
|
96
|
+
final matches = dtos.map((dto) => dto.toDomain()).toList();
|
|
97
|
+
await localDataSource.cacheMatches(matches);
|
|
98
|
+
return matches;
|
|
99
|
+
} on NetworkException {
|
|
100
|
+
return localDataSource.getCachedMatches(sport);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Provider 연결
|
|
106
|
+
final matchRepositoryProvider = Provider<MatchRepository>((ref) {
|
|
107
|
+
return MatchRepositoryImpl(
|
|
108
|
+
remoteDataSource: ref.watch(matchRemoteDataSourceProvider),
|
|
109
|
+
localDataSource: ref.watch(matchLocalDataSourceProvider),
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 규칙
|
|
115
|
+
|
|
116
|
+
- **Feature-first**: `lib/features/{name}/` 구조 필수
|
|
117
|
+
- **레이어 방향**: Presentation → Domain ← Data (의존성 역전)
|
|
118
|
+
- **Domain layer**: Flutter import 금지 (`dart:` 만 허용)
|
|
119
|
+
- **DTO ↔ Model 분리**: API 응답 구조와 도메인 모델 분리
|
|
120
|
+
- **Repository**: abstract (domain) + impl (data) 분리
|
|
121
|
+
- **1 feature = 1 독립 단위**: feature 간 직접 import 금지 → 공유 도메인은 `core/`
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Navigation & Routing
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: go-router, navigation, deep-link, routing
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Navigation & Routing
|
|
8
|
+
|
|
9
|
+
go_router 기반 선언적 라우팅. 딥링크, 가드, 중첩 네비게이션.
|
|
10
|
+
|
|
11
|
+
### 라우터 설정
|
|
12
|
+
|
|
13
|
+
```dart
|
|
14
|
+
final routerProvider = Provider<GoRouter>((ref) {
|
|
15
|
+
final authState = ref.watch(authStateProvider);
|
|
16
|
+
|
|
17
|
+
return GoRouter(
|
|
18
|
+
initialLocation: '/',
|
|
19
|
+
redirect: (context, state) {
|
|
20
|
+
final isLoggedIn = authState.valueOrNull != null;
|
|
21
|
+
final isAuthRoute = state.matchedLocation.startsWith('/auth');
|
|
22
|
+
|
|
23
|
+
if (!isLoggedIn && !isAuthRoute) return '/auth/login';
|
|
24
|
+
if (isLoggedIn && isAuthRoute) return '/';
|
|
25
|
+
return null; // 리다이렉트 불필요
|
|
26
|
+
},
|
|
27
|
+
routes: [
|
|
28
|
+
// 인증 라우트 (바텀 네비 없음)
|
|
29
|
+
GoRoute(
|
|
30
|
+
path: '/auth/login',
|
|
31
|
+
builder: (context, state) => const LoginScreen(),
|
|
32
|
+
),
|
|
33
|
+
// 메인 앱 (바텀 네비 + 중첩 라우팅)
|
|
34
|
+
StatefulShellRoute.indexedStack(
|
|
35
|
+
builder: (context, state, child) => MainShell(child: child),
|
|
36
|
+
branches: [
|
|
37
|
+
StatefulShellBranch(routes: [
|
|
38
|
+
GoRoute(
|
|
39
|
+
path: '/',
|
|
40
|
+
builder: (_, __) => const HomeScreen(),
|
|
41
|
+
routes: [
|
|
42
|
+
GoRoute(
|
|
43
|
+
path: 'match/:id',
|
|
44
|
+
builder: (_, state) => MatchDetailScreen(
|
|
45
|
+
matchId: state.pathParameters['id']!,
|
|
46
|
+
),
|
|
47
|
+
),
|
|
48
|
+
],
|
|
49
|
+
),
|
|
50
|
+
]),
|
|
51
|
+
StatefulShellBranch(routes: [
|
|
52
|
+
GoRoute(
|
|
53
|
+
path: '/community',
|
|
54
|
+
builder: (_, __) => const CommunityScreen(),
|
|
55
|
+
),
|
|
56
|
+
]),
|
|
57
|
+
StatefulShellBranch(routes: [
|
|
58
|
+
GoRoute(
|
|
59
|
+
path: '/profile',
|
|
60
|
+
builder: (_, __) => const ProfileScreen(),
|
|
61
|
+
),
|
|
62
|
+
]),
|
|
63
|
+
],
|
|
64
|
+
),
|
|
65
|
+
],
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 네비게이션 호출
|
|
71
|
+
|
|
72
|
+
**Incorrect:**
|
|
73
|
+
```dart
|
|
74
|
+
// 명령형 — 히스토리 관리 어려움
|
|
75
|
+
Navigator.push(
|
|
76
|
+
context,
|
|
77
|
+
MaterialPageRoute(builder: (_) => MatchDetailScreen(id: matchId)),
|
|
78
|
+
);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Correct:**
|
|
82
|
+
```dart
|
|
83
|
+
// 선언적 — URL 기반
|
|
84
|
+
context.go('/match/$matchId'); // 교체
|
|
85
|
+
context.push('/match/$matchId'); // 스택 추가
|
|
86
|
+
context.pop(); // 뒤로가기
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 딥링크 설정
|
|
90
|
+
|
|
91
|
+
```dart
|
|
92
|
+
// go_router는 자동으로 URL 파싱
|
|
93
|
+
// Android: AndroidManifest.xml
|
|
94
|
+
// <intent-filter android:autoVerify="true">
|
|
95
|
+
// <data android:scheme="https" android:host="app.example.com" />
|
|
96
|
+
// </intent-filter>
|
|
97
|
+
|
|
98
|
+
// iOS: Info.plist
|
|
99
|
+
// Associated Domains: applinks:app.example.com
|
|
100
|
+
|
|
101
|
+
// Flutter 측: 라우트만 정의하면 딥링크 자동 처리
|
|
102
|
+
GoRoute(
|
|
103
|
+
path: '/match/:id',
|
|
104
|
+
builder: (_, state) => MatchDetailScreen(
|
|
105
|
+
matchId: state.pathParameters['id']!,
|
|
106
|
+
),
|
|
107
|
+
),
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 규칙
|
|
111
|
+
|
|
112
|
+
- `go_router` 선언적 라우팅 사용 (Navigator.push 금지)
|
|
113
|
+
- 라우트 정의는 `core/router/` 에 중앙화
|
|
114
|
+
- `redirect` 로 인증 가드 구현 (미들웨어 패턴)
|
|
115
|
+
- `StatefulShellRoute` 로 바텀 네비 + 각 탭 스택 유지
|
|
116
|
+
- path parameter는 `/:id` 패턴, query는 `state.uri.queryParameters`
|
|
117
|
+
- 라우트 경로 상수화 (`RouteNames` 또는 `RoutePaths` 클래스)
|