@codyswann/lisa 1.0.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/LICENSE +21 -0
- package/README.md +867 -0
- package/all/copy-overwrite/.claude/README.md +205 -0
- package/all/copy-overwrite/.claude/agents/agent-architect.md +311 -0
- package/all/copy-overwrite/.claude/agents/codebase-analyzer.md +146 -0
- package/all/copy-overwrite/.claude/agents/codebase-locator.md +125 -0
- package/all/copy-overwrite/.claude/agents/codebase-pattern-finder.md +237 -0
- package/all/copy-overwrite/.claude/agents/git-history-analyzer.md +183 -0
- package/all/copy-overwrite/.claude/agents/hooks-expert.md +74 -0
- package/all/copy-overwrite/.claude/agents/skill-evaluator.md +246 -0
- package/all/copy-overwrite/.claude/agents/slash-command-architect.md +87 -0
- package/all/copy-overwrite/.claude/agents/web-search-researcher.md +112 -0
- package/all/copy-overwrite/.claude/commands/git/commit-and-submit-pr.md +8 -0
- package/all/copy-overwrite/.claude/commands/git/commit.md +44 -0
- package/all/copy-overwrite/.claude/commands/git/prune.md +34 -0
- package/all/copy-overwrite/.claude/commands/git/submit-pr.md +50 -0
- package/all/copy-overwrite/.claude/commands/jira/create.md +50 -0
- package/all/copy-overwrite/.claude/commands/jira/verify.md +34 -0
- package/all/copy-overwrite/.claude/commands/project/archive.md +8 -0
- package/all/copy-overwrite/.claude/commands/project/bootstrap.md +49 -0
- package/all/copy-overwrite/.claude/commands/project/complete-task.md +7 -0
- package/all/copy-overwrite/.claude/commands/project/debrief.md +65 -0
- package/all/copy-overwrite/.claude/commands/project/execute.md +94 -0
- package/all/copy-overwrite/.claude/commands/project/implement.md +42 -0
- package/all/copy-overwrite/.claude/commands/project/local-code-review.md +88 -0
- package/all/copy-overwrite/.claude/commands/project/lower-code-complexity.md +74 -0
- package/all/copy-overwrite/.claude/commands/project/plan.md +314 -0
- package/all/copy-overwrite/.claude/commands/project/research.md +248 -0
- package/all/copy-overwrite/.claude/commands/project/review.md +63 -0
- package/all/copy-overwrite/.claude/commands/project/setup.md +19 -0
- package/all/copy-overwrite/.claude/commands/project/verify.md +38 -0
- package/all/copy-overwrite/.claude/commands/pull-request/review.md +12 -0
- package/all/copy-overwrite/.claude/commands/rules/format-md.md +72 -0
- package/all/copy-overwrite/.claude/commands/sonarqube/check.md +6 -0
- package/all/copy-overwrite/.claude/commands/sonarqube/fix.md +3 -0
- package/all/copy-overwrite/.claude/hooks/README.md +301 -0
- package/all/copy-overwrite/.claude/hooks/notify-ntfy.sh +181 -0
- package/all/copy-overwrite/.claude/settings.json +41 -0
- package/all/copy-overwrite/.claude/settings.local.json.example +14 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/SKILL.md +405 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/references/function-structure.md +416 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/references/immutable-patterns.md +316 -0
- package/all/copy-overwrite/.claude/skills/prompt-complexity-scorer/SKILL.md +118 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/LICENSE.txt +202 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/SKILL.md +210 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/__pycache__/quick_validate.cpython-312.pyc +0 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/all/copy-overwrite/CLAUDE.md +77 -0
- package/all/copy-overwrite/HUMAN.md +17 -0
- package/all/copy-overwrite/specs/.keep +0 -0
- package/all/create-only/PROJECT_RULES.md +0 -0
- package/cdk/merge/package.json +20 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +107 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/prompts.d.ts +45 -0
- package/dist/cli/prompts.d.ts.map +1 -0
- package/dist/cli/prompts.js +58 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/core/config.d.ts +73 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +36 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lisa.d.ts +81 -0
- package/dist/core/lisa.d.ts.map +1 -0
- package/dist/core/lisa.js +459 -0
- package/dist/core/lisa.js.map +1 -0
- package/dist/core/manifest.d.ts +58 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +104 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/detection/detector.interface.d.ts +15 -0
- package/dist/detection/detector.interface.d.ts.map +1 -0
- package/dist/detection/detector.interface.js +2 -0
- package/dist/detection/detector.interface.js.map +1 -0
- package/dist/detection/detectors/cdk.d.ts +10 -0
- package/dist/detection/detectors/cdk.d.ts.map +1 -0
- package/dist/detection/detectors/cdk.js +34 -0
- package/dist/detection/detectors/cdk.js.map +1 -0
- package/dist/detection/detectors/expo.d.ts +10 -0
- package/dist/detection/detectors/expo.d.ts.map +1 -0
- package/dist/detection/detectors/expo.js +30 -0
- package/dist/detection/detectors/expo.js.map +1 -0
- package/dist/detection/detectors/nestjs.d.ts +10 -0
- package/dist/detection/detectors/nestjs.d.ts.map +1 -0
- package/dist/detection/detectors/nestjs.js +34 -0
- package/dist/detection/detectors/nestjs.js.map +1 -0
- package/dist/detection/detectors/npm-package.d.ts +13 -0
- package/dist/detection/detectors/npm-package.d.ts.map +1 -0
- package/dist/detection/detectors/npm-package.js +30 -0
- package/dist/detection/detectors/npm-package.js.map +1 -0
- package/dist/detection/detectors/typescript.d.ts +10 -0
- package/dist/detection/detectors/typescript.d.ts.map +1 -0
- package/dist/detection/detectors/typescript.js +25 -0
- package/dist/detection/detectors/typescript.js.map +1 -0
- package/dist/detection/index.d.ts +24 -0
- package/dist/detection/index.d.ts.map +1 -0
- package/dist/detection/index.js +57 -0
- package/dist/detection/index.js.map +1 -0
- package/dist/errors/index.d.ts +69 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +110 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/console-logger.d.ts +12 -0
- package/dist/logging/console-logger.d.ts.map +1 -0
- package/dist/logging/console-logger.js +22 -0
- package/dist/logging/console-logger.js.map +1 -0
- package/dist/logging/index.d.ts +4 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +3 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.interface.d.ts +20 -0
- package/dist/logging/logger.interface.d.ts.map +1 -0
- package/dist/logging/logger.interface.js +2 -0
- package/dist/logging/logger.interface.js.map +1 -0
- package/dist/logging/silent-logger.d.ts +12 -0
- package/dist/logging/silent-logger.d.ts.map +1 -0
- package/dist/logging/silent-logger.js +21 -0
- package/dist/logging/silent-logger.js.map +1 -0
- package/dist/strategies/copy-contents.d.ts +14 -0
- package/dist/strategies/copy-contents.d.ts.map +1 -0
- package/dist/strategies/copy-contents.js +69 -0
- package/dist/strategies/copy-contents.js.map +1 -0
- package/dist/strategies/copy-overwrite.d.ts +14 -0
- package/dist/strategies/copy-overwrite.d.ts.map +1 -0
- package/dist/strategies/copy-overwrite.js +47 -0
- package/dist/strategies/copy-overwrite.js.map +1 -0
- package/dist/strategies/create-only.d.ts +13 -0
- package/dist/strategies/create-only.d.ts.map +1 -0
- package/dist/strategies/create-only.js +30 -0
- package/dist/strategies/create-only.js.map +1 -0
- package/dist/strategies/index.d.ts +31 -0
- package/dist/strategies/index.d.ts.map +1 -0
- package/dist/strategies/index.js +52 -0
- package/dist/strategies/index.js.map +1 -0
- package/dist/strategies/merge.d.ts +13 -0
- package/dist/strategies/merge.d.ts.map +1 -0
- package/dist/strategies/merge.js +60 -0
- package/dist/strategies/merge.js.map +1 -0
- package/dist/strategies/strategy.interface.d.ts +31 -0
- package/dist/strategies/strategy.interface.d.ts.map +1 -0
- package/dist/strategies/strategy.interface.js +2 -0
- package/dist/strategies/strategy.interface.js.map +1 -0
- package/dist/transaction/backup.d.ts +38 -0
- package/dist/transaction/backup.d.ts.map +1 -0
- package/dist/transaction/backup.js +97 -0
- package/dist/transaction/backup.js.map +1 -0
- package/dist/transaction/index.d.ts +4 -0
- package/dist/transaction/index.d.ts.map +1 -0
- package/dist/transaction/index.js +3 -0
- package/dist/transaction/index.js.map +1 -0
- package/dist/transaction/transaction.d.ts +34 -0
- package/dist/transaction/transaction.d.ts.map +1 -0
- package/dist/transaction/transaction.js +68 -0
- package/dist/transaction/transaction.js.map +1 -0
- package/dist/utils/file-operations.d.ts +29 -0
- package/dist/utils/file-operations.d.ts.map +1 -0
- package/dist/utils/file-operations.js +84 -0
- package/dist/utils/file-operations.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/json-utils.d.ts +22 -0
- package/dist/utils/json-utils.d.ts.map +1 -0
- package/dist/utils/json-utils.js +57 -0
- package/dist/utils/json-utils.js.map +1 -0
- package/dist/utils/path-utils.d.ts +21 -0
- package/dist/utils/path-utils.d.ts.map +1 -0
- package/dist/utils/path-utils.js +35 -0
- package/dist/utils/path-utils.js.map +1 -0
- package/eslint-plugin-code-organization/README.md +149 -0
- package/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +468 -0
- package/eslint-plugin-code-organization/index.js +23 -0
- package/eslint-plugin-code-organization/package.json +10 -0
- package/eslint-plugin-code-organization/rules/enforce-statement-order.js +157 -0
- package/expo/copy-overwrite/.claude/skills/apollo-client/SKILL.md +238 -0
- package/expo/copy-overwrite/.claude/skills/apollo-client/references/mutation-patterns.md +360 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/SKILL.md +360 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/atomic-levels.md +417 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/folder-structure.md +257 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/gluestack-mapping.md +233 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/scripts/validate_atomic_structure.py +327 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/SKILL.md +299 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/examples.md +749 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/patterns.md +318 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/create_component.py +198 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/validate_component.py +207 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/SKILL.md +268 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/common-issues.md +619 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/file-extensions.md +340 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/platform-api.md +276 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/scripts/validate_cross_platform.py +414 -0
- package/expo/copy-overwrite/.claude/skills/directory-structure/SKILL.md +202 -0
- package/expo/copy-overwrite/.claude/skills/directory-structure/scripts/validate_structure.py +443 -0
- package/expo/copy-overwrite/.claude/skills/expo-env-config/SKILL.md +309 -0
- package/expo/copy-overwrite/.claude/skills/expo-env-config/references/validation-patterns.md +417 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/SKILL.md +431 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/references/official-docs.md +290 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/scripts/generate-route.py +169 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/SKILL.md +411 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/color-tokens.md +343 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/component-mapping.md +307 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/spacing-scale.md +300 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/scripts/validate_styling.py +354 -0
- package/expo/copy-overwrite/.claude/skills/local-state/SKILL.md +362 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/async-storage.md +505 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/persistence-patterns.md +711 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/reactive-variables.md +446 -0
- package/expo/copy-overwrite/.claude/skills/playwright-selectors/SKILL.md +223 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/SKILL.md +319 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/async-patterns.md +420 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/expo-router-testing.md +556 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/mocking-patterns.md +590 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/query-priority.md +291 -0
- package/expo/copy-overwrite/.easignore.extra +2 -0
- package/expo/copy-overwrite/.mcp.json +33 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/README.md +234 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/plugin-index.test.js +84 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/require-memo-in-view.test.js +196 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/single-component-per-file.test.js +289 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/index.js +32 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/package.json +10 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/enforce-component-structure.js +230 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/no-return-in-view.js +91 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/require-memo-in-view.js +178 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/single-component-per-file.js +238 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/README.md +260 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/index.js +29 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/package.json +10 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-classname-outside-ui.js +51 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-direct-rn-imports.js +55 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-inline-styles.js +73 -0
- package/expo/copy-overwrite/eslint.config.mjs +560 -0
- package/expo/copy-overwrite/lighthouserc.js +194 -0
- package/expo/create-only/lighthouserc-config.json +28 -0
- package/expo/merge/package.json +132 -0
- package/lisa.sh +35 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/SKILL.md +176 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/advanced-features.md +527 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/project-patterns.md +483 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/quick-start.md +257 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/resolvers-mutations.md +413 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/types-scalars.md +513 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-rules/SKILL.md +536 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/SKILL.md +275 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/configuration-patterns.md +487 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/entity-patterns.md +450 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/observability-patterns.md +536 -0
- package/nestjs/merge/package.json +75 -0
- package/package.json +124 -0
- package/typescript/copy-contents/.husky/commit-msg +91 -0
- package/typescript/copy-contents/.husky/pre-commit +96 -0
- package/typescript/copy-contents/.husky/pre-push +211 -0
- package/typescript/copy-overwrite/.claude/hooks/format-on-edit.sh +74 -0
- package/typescript/copy-overwrite/.claude/hooks/install_pkgs.sh +59 -0
- package/typescript/copy-overwrite/.claude/hooks/lint-on-edit.sh +103 -0
- package/typescript/copy-overwrite/.claude/skills/jsdoc-best-practices/SKILL.md +388 -0
- package/typescript/copy-overwrite/.github/README.md +455 -0
- package/typescript/copy-overwrite/.github/dependabot.yml +40 -0
- package/typescript/copy-overwrite/.github/k6/BROWSER_TESTING_NOTE.md +129 -0
- package/typescript/copy-overwrite/.github/k6/INTEGRATION_GUIDE.md +354 -0
- package/typescript/copy-overwrite/.github/k6/README.md +386 -0
- package/typescript/copy-overwrite/.github/k6/SCENARIO_SELECTION_GUIDE.md +264 -0
- package/typescript/copy-overwrite/.github/k6/examples/customer-deploy-integration.yml +115 -0
- package/typescript/copy-overwrite/.github/k6/examples/data-driven-test.js +268 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/load.js +142 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/load.json +27 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/smoke.js +26 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/smoke.json +20 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/soak.js +244 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/soak.json +29 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/spike.js +180 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/spike.json +32 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/stress.js +206 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/stress.json +38 -0
- package/typescript/copy-overwrite/.github/k6/scripts/api-test.js +452 -0
- package/typescript/copy-overwrite/.github/k6/scripts/default-test.js +185 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/normal.json +30 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/relaxed.json +21 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/strict.json +29 -0
- package/typescript/copy-overwrite/.github/workflows/build.yml +72 -0
- package/typescript/copy-overwrite/.github/workflows/ci.yml +49 -0
- package/typescript/copy-overwrite/.github/workflows/claude.yml +51 -0
- package/typescript/copy-overwrite/.github/workflows/create-github-issue-on-failure.yml +113 -0
- package/typescript/copy-overwrite/.github/workflows/create-jira-issue-on-failure.yml +195 -0
- package/typescript/copy-overwrite/.github/workflows/create-sentry-issue-on-failure.yml +267 -0
- package/typescript/copy-overwrite/.github/workflows/deploy.yml +228 -0
- package/typescript/copy-overwrite/.github/workflows/k6-load-test-README.md +230 -0
- package/typescript/copy-overwrite/.github/workflows/lighthouse.yml +68 -0
- package/typescript/copy-overwrite/.github/workflows/load-test.yml +282 -0
- package/typescript/copy-overwrite/.github/workflows/quality.yml +1737 -0
- package/typescript/copy-overwrite/.github/workflows/release.yml +1599 -0
- package/typescript/copy-overwrite/.gitleaksignore +28 -0
- package/typescript/copy-overwrite/.nvmrc +1 -0
- package/typescript/copy-overwrite/.prettierignore +23 -0
- package/typescript/copy-overwrite/.prettierrc.json +22 -0
- package/typescript/copy-overwrite/.versionrc +42 -0
- package/typescript/copy-overwrite/.yamllint +20 -0
- package/typescript/copy-overwrite/commitlint.config.js +11 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/README.md +149 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +468 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/index.js +23 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/package.json +10 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/rules/enforce-statement-order.js +157 -0
- package/typescript/copy-overwrite/eslint.config.mjs +390 -0
- package/typescript/copy-overwrite/eslint.ignore.config.json +57 -0
- package/typescript/copy-overwrite/eslint.thresholds.config.json +5 -0
- package/typescript/github-rulesets/base.json +106 -0
- package/typescript/merge/.claude/settings.json +28 -0
- package/typescript/merge/package.json +71 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
# Entity Patterns
|
|
2
|
+
|
|
3
|
+
Detailed patterns for TypeORM entity design including base entity, relationships, indexes, enums, and database views.
|
|
4
|
+
|
|
5
|
+
## Abstract Base Entity
|
|
6
|
+
|
|
7
|
+
All entities must extend the abstract `TimestampedEntity` class.
|
|
8
|
+
|
|
9
|
+
**Important naming**: We use `TimestampedEntity` instead of `BaseEntity` to avoid confusion with [TypeORM's built-in BaseEntity](https://typeorm.io/active-record-data-mapper#what-is-the-active-record-pattern) which provides Active Record pattern methods (`save()`, `remove()`, etc.). Our class only provides column inheritance.
|
|
10
|
+
|
|
11
|
+
### timestamped.entity.ts
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import {
|
|
15
|
+
CreateDateColumn,
|
|
16
|
+
PrimaryGeneratedColumn,
|
|
17
|
+
UpdateDateColumn,
|
|
18
|
+
} from "typeorm";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Abstract base entity providing common columns for all entities.
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
* All entities must extend this class to ensure consistent:
|
|
25
|
+
* - UUID primary keys
|
|
26
|
+
* - Automatic timestamp management
|
|
27
|
+
* - Standardized column naming via SnakeNamingStrategy
|
|
28
|
+
*
|
|
29
|
+
* IMPORTANT: This class does NOT have an @Entity() decorator.
|
|
30
|
+
* Only concrete child entities should have @Entity().
|
|
31
|
+
*/
|
|
32
|
+
export abstract class TimestampedEntity {
|
|
33
|
+
/**
|
|
34
|
+
* Unique identifier for the entity.
|
|
35
|
+
*/
|
|
36
|
+
@PrimaryGeneratedColumn("uuid", { comment: "Unique identifier (UUID v4)" })
|
|
37
|
+
id: string;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Timestamp when the entity was created.
|
|
41
|
+
*/
|
|
42
|
+
@CreateDateColumn({ comment: "Timestamp when record was created" })
|
|
43
|
+
createdAt: Date;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Timestamp when the entity was last updated.
|
|
47
|
+
*/
|
|
48
|
+
@UpdateDateColumn({ comment: "Timestamp when record was last updated" })
|
|
49
|
+
updatedAt: Date;
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### When NOT to Use TimestampedEntity
|
|
54
|
+
|
|
55
|
+
Per [The Hidden Costs of Using BaseEntity with TypeORM](https://medium.com/@dmitriykhirniy/the-hidden-costs-of-using-baseentity-with-typeorm-108a9cf40a7f), consider whether all entities need these columns:
|
|
56
|
+
|
|
57
|
+
| Entity Type | Recommendation |
|
|
58
|
+
|-------------|----------------|
|
|
59
|
+
| **Domain entities** (User, Organization) | Extend `TimestampedEntity` |
|
|
60
|
+
| **High-volume metrics/logs** | Consider minimal columns to reduce storage |
|
|
61
|
+
| **Junction tables** | May only need foreign keys, no timestamps |
|
|
62
|
+
|
|
63
|
+
For high-volume tables, create a minimal entity without inheritance:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
@Entity({ comment: "High-volume sensor readings - minimal columns for performance" })
|
|
67
|
+
export class SensorReading {
|
|
68
|
+
@PrimaryGeneratedColumn("uuid", { comment: "Unique identifier" })
|
|
69
|
+
id: string;
|
|
70
|
+
|
|
71
|
+
@Column({ comment: "Sensor value", type: "decimal" })
|
|
72
|
+
value: number;
|
|
73
|
+
|
|
74
|
+
@Column({ comment: "Reading timestamp", type: "timestamptz" })
|
|
75
|
+
timestamp: Date;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Column Comments
|
|
80
|
+
|
|
81
|
+
All columns must have comments for database documentation.
|
|
82
|
+
|
|
83
|
+
### Required Comment Pattern
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
@Entity({ comment: "Description of what this entity represents" })
|
|
87
|
+
export class User extends TimestampedEntity {
|
|
88
|
+
// Simple column with comment
|
|
89
|
+
@Column({ comment: "User's email address for authentication" })
|
|
90
|
+
email: string;
|
|
91
|
+
|
|
92
|
+
// Nullable column with comment
|
|
93
|
+
@Column({ comment: "User's display name", nullable: true })
|
|
94
|
+
displayName: string | null;
|
|
95
|
+
|
|
96
|
+
// Typed column with comment
|
|
97
|
+
@Column({ type: "uuid", comment: "Foreign key to organization" })
|
|
98
|
+
@Index()
|
|
99
|
+
organizationId: string;
|
|
100
|
+
|
|
101
|
+
// Enum column with comment
|
|
102
|
+
@Column({
|
|
103
|
+
type: "enum",
|
|
104
|
+
enum: UserRole,
|
|
105
|
+
default: UserRole.MEMBER,
|
|
106
|
+
comment: "User's role within the system",
|
|
107
|
+
})
|
|
108
|
+
role: UserRole;
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Comment Guidelines
|
|
113
|
+
|
|
114
|
+
| Guideline | Example |
|
|
115
|
+
|-----------|---------|
|
|
116
|
+
| Describe purpose, not type | "User's email for authentication" not "String email" |
|
|
117
|
+
| Include constraints | "Must be unique across all organizations" |
|
|
118
|
+
| Document relationships | "Foreign key to organization table" |
|
|
119
|
+
| Note special behavior | "Set to null when organization is deleted" |
|
|
120
|
+
|
|
121
|
+
## Foreign Key Indexing
|
|
122
|
+
|
|
123
|
+
All foreign keys must be indexed for query performance.
|
|
124
|
+
|
|
125
|
+
### Correct Pattern
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
@Entity({ comment: "User entity with organization membership" })
|
|
129
|
+
export class User extends TimestampedEntity {
|
|
130
|
+
// Foreign key column - MUST be indexed
|
|
131
|
+
@Column({ type: "uuid", comment: "Foreign key to organization" })
|
|
132
|
+
@Index()
|
|
133
|
+
organizationId: string;
|
|
134
|
+
|
|
135
|
+
// Relationship definition
|
|
136
|
+
@ManyToOne(() => Organization, { onDelete: "SET NULL", nullable: true })
|
|
137
|
+
@JoinColumn()
|
|
138
|
+
organization: Organization;
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Composite Indexes
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
@Entity({ comment: "Player statistics by season" })
|
|
146
|
+
@Index(["playerId", "seasonId"], { unique: true })
|
|
147
|
+
export class PlayerSeasonStat extends TimestampedEntity {
|
|
148
|
+
@Column({ type: "uuid", comment: "Foreign key to player" })
|
|
149
|
+
@Index()
|
|
150
|
+
playerId: string;
|
|
151
|
+
|
|
152
|
+
@Column({ type: "uuid", comment: "Foreign key to season" })
|
|
153
|
+
@Index()
|
|
154
|
+
seasonId: string;
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Relationship Patterns
|
|
159
|
+
|
|
160
|
+
### OneToMany with Cascade Delete
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
@Entity({ comment: "Organization containing multiple users" })
|
|
164
|
+
export class Organization extends TimestampedEntity {
|
|
165
|
+
@Column({ comment: "Organization name" })
|
|
166
|
+
name: string;
|
|
167
|
+
|
|
168
|
+
// Cascade delete orphaned rows when relationship is broken
|
|
169
|
+
@OneToMany(() => User, user => user.organization, {
|
|
170
|
+
orphanedRowAction: "delete",
|
|
171
|
+
})
|
|
172
|
+
users: User[];
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### ManyToOne with Delete Strategy
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
@Entity({ comment: "User with organization membership" })
|
|
180
|
+
export class User extends TimestampedEntity {
|
|
181
|
+
@Column({ type: "uuid", comment: "Foreign key to organization", nullable: true })
|
|
182
|
+
@Index()
|
|
183
|
+
organizationId: string | null;
|
|
184
|
+
|
|
185
|
+
// SET NULL: User survives when organization deleted
|
|
186
|
+
@ManyToOne(() => Organization, { onDelete: "SET NULL", nullable: true })
|
|
187
|
+
@JoinColumn()
|
|
188
|
+
organization: Organization | null;
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Delete Strategy Reference
|
|
193
|
+
|
|
194
|
+
| Strategy | Use When |
|
|
195
|
+
|----------|----------|
|
|
196
|
+
| `CASCADE` | Child cannot exist without parent |
|
|
197
|
+
| `SET NULL` | Child should survive parent deletion |
|
|
198
|
+
| `NO ACTION` | Prevent deletion if children exist |
|
|
199
|
+
| `RESTRICT` | Same as NO ACTION (checked immediately) |
|
|
200
|
+
|
|
201
|
+
### ManyToMany Relationship
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
@Entity({ comment: "User entity" })
|
|
205
|
+
export class User extends TimestampedEntity {
|
|
206
|
+
@ManyToMany(() => Role)
|
|
207
|
+
@JoinTable({
|
|
208
|
+
name: "user_roles",
|
|
209
|
+
joinColumn: { name: "user_id" },
|
|
210
|
+
inverseJoinColumn: { name: "role_id" },
|
|
211
|
+
})
|
|
212
|
+
roles: Role[];
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Enum Columns
|
|
217
|
+
|
|
218
|
+
### Define Enum Type
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
/**
|
|
222
|
+
* Supported user roles in the system.
|
|
223
|
+
*/
|
|
224
|
+
export enum UserRole {
|
|
225
|
+
ADMIN = "admin",
|
|
226
|
+
MEMBER = "member",
|
|
227
|
+
VIEWER = "viewer",
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Use in Entity
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
@Entity({ comment: "User with role-based access" })
|
|
235
|
+
export class User extends TimestampedEntity {
|
|
236
|
+
@Column({
|
|
237
|
+
type: "enum",
|
|
238
|
+
enum: UserRole,
|
|
239
|
+
default: UserRole.MEMBER,
|
|
240
|
+
comment: "User's role determining permissions",
|
|
241
|
+
})
|
|
242
|
+
role: UserRole;
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## JSONB Columns
|
|
247
|
+
|
|
248
|
+
For flexible schema storage:
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
/**
|
|
252
|
+
* Custom settings interface.
|
|
253
|
+
*/
|
|
254
|
+
interface UserSettings {
|
|
255
|
+
readonly theme: "light" | "dark";
|
|
256
|
+
readonly notifications: boolean;
|
|
257
|
+
readonly timezone: string;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
@Entity({ comment: "User with customizable settings" })
|
|
261
|
+
export class User extends TimestampedEntity {
|
|
262
|
+
@Column({
|
|
263
|
+
type: "jsonb",
|
|
264
|
+
default: {},
|
|
265
|
+
comment: "User preferences stored as JSON",
|
|
266
|
+
})
|
|
267
|
+
settings: UserSettings;
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Database Views
|
|
272
|
+
|
|
273
|
+
For complex analytics queries, use ViewEntity:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
import { ViewColumn, ViewEntity } from "typeorm";
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Aggregated user statistics view.
|
|
280
|
+
*
|
|
281
|
+
* @remarks
|
|
282
|
+
* This is a read-only view - synchronize: false ensures
|
|
283
|
+
* TypeORM won't try to create/modify the view automatically.
|
|
284
|
+
* The view must be created via migration.
|
|
285
|
+
*/
|
|
286
|
+
@ViewEntity({
|
|
287
|
+
name: "user_stats_view",
|
|
288
|
+
synchronize: false,
|
|
289
|
+
expression: `
|
|
290
|
+
SELECT
|
|
291
|
+
u.id as user_id,
|
|
292
|
+
u.organization_id,
|
|
293
|
+
COUNT(DISTINCT w.id) as watchlist_count,
|
|
294
|
+
MAX(u.updated_at) as last_activity
|
|
295
|
+
FROM users u
|
|
296
|
+
LEFT JOIN watchlists w ON w.user_id = u.id
|
|
297
|
+
GROUP BY u.id, u.organization_id
|
|
298
|
+
`,
|
|
299
|
+
})
|
|
300
|
+
export class UserStatsView {
|
|
301
|
+
@ViewColumn({ name: "user_id" })
|
|
302
|
+
userId: string;
|
|
303
|
+
|
|
304
|
+
@ViewColumn({ name: "organization_id" })
|
|
305
|
+
organizationId: string;
|
|
306
|
+
|
|
307
|
+
@ViewColumn({ name: "watchlist_count" })
|
|
308
|
+
watchlistCount: number;
|
|
309
|
+
|
|
310
|
+
@ViewColumn({ name: "last_activity" })
|
|
311
|
+
lastActivity: Date;
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## Multi-Schema Support
|
|
316
|
+
|
|
317
|
+
For organizing entities into separate schemas:
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
@Entity({
|
|
321
|
+
schema: "analytics",
|
|
322
|
+
comment: "Event tracking for user analytics",
|
|
323
|
+
})
|
|
324
|
+
export class AnalyticsEvent extends TimestampedEntity {
|
|
325
|
+
@Column({ comment: "Event type identifier" })
|
|
326
|
+
eventType: string;
|
|
327
|
+
|
|
328
|
+
@Column({ type: "jsonb", comment: "Event payload data" })
|
|
329
|
+
payload: Record<string, unknown>;
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## Entity Export Pattern
|
|
334
|
+
|
|
335
|
+
All entities must be explicitly exported from `src/database/entities/index.ts`:
|
|
336
|
+
|
|
337
|
+
### entities/index.ts
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
/**
|
|
341
|
+
* Centralized entity exports for TypeORM configuration.
|
|
342
|
+
*
|
|
343
|
+
* @remarks
|
|
344
|
+
* All entities must be exported here for esbuild compatibility.
|
|
345
|
+
* Glob patterns don't work with esbuild bundling.
|
|
346
|
+
*/
|
|
347
|
+
|
|
348
|
+
// Abstract base entity (not exported to TypeORM, but available for extension)
|
|
349
|
+
export { TimestampedEntity } from "./timestamped.entity";
|
|
350
|
+
|
|
351
|
+
// Domain entities
|
|
352
|
+
export { User } from "./user.entity";
|
|
353
|
+
export { Organization } from "./organization.entity";
|
|
354
|
+
export { Watchlist } from "./watchlist.entity";
|
|
355
|
+
|
|
356
|
+
// View entities
|
|
357
|
+
export { UserStatsView } from "./user-stats.view";
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Adding New Entities Checklist
|
|
361
|
+
|
|
362
|
+
1. Create entity file: `src/database/entities/{name}.entity.ts`
|
|
363
|
+
2. Extend `TimestampedEntity` (or create minimal entity for high-volume tables)
|
|
364
|
+
3. Add `@Entity({ comment: "..." })` decorator (NOT on abstract base class)
|
|
365
|
+
4. Add column comments to all columns
|
|
366
|
+
5. Index all foreign key columns
|
|
367
|
+
6. Export from `src/database/entities/index.ts`
|
|
368
|
+
7. Generate migration: `bun migration:generate --name=Add{Name}Entity`
|
|
369
|
+
|
|
370
|
+
## Complete Entity Example
|
|
371
|
+
|
|
372
|
+
```typescript
|
|
373
|
+
import {
|
|
374
|
+
Column,
|
|
375
|
+
Entity,
|
|
376
|
+
Index,
|
|
377
|
+
JoinColumn,
|
|
378
|
+
ManyToOne,
|
|
379
|
+
OneToMany,
|
|
380
|
+
} from "typeorm";
|
|
381
|
+
import { TimestampedEntity } from "./timestamped.entity";
|
|
382
|
+
import { Organization } from "./organization.entity";
|
|
383
|
+
import { Watchlist } from "./watchlist.entity";
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Supported user roles in the system.
|
|
387
|
+
*/
|
|
388
|
+
export enum UserRole {
|
|
389
|
+
ADMIN = "admin",
|
|
390
|
+
MEMBER = "member",
|
|
391
|
+
VIEWER = "viewer",
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* User settings interface for JSONB column.
|
|
396
|
+
*/
|
|
397
|
+
interface UserSettings {
|
|
398
|
+
readonly theme?: "light" | "dark";
|
|
399
|
+
readonly notifications?: boolean;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Represents a user in the system.
|
|
404
|
+
*
|
|
405
|
+
* @remarks
|
|
406
|
+
* Users belong to organizations and can create watchlists.
|
|
407
|
+
* When an organization is deleted, the user's organizationId is set to null.
|
|
408
|
+
*/
|
|
409
|
+
@Entity({ comment: "Application users with organization membership" })
|
|
410
|
+
export class User extends TimestampedEntity {
|
|
411
|
+
@Column({ comment: "User email address for authentication" })
|
|
412
|
+
@Index({ unique: true })
|
|
413
|
+
email: string;
|
|
414
|
+
|
|
415
|
+
@Column({ comment: "User display name", nullable: true })
|
|
416
|
+
displayName: string | null;
|
|
417
|
+
|
|
418
|
+
@Column({
|
|
419
|
+
type: "uuid",
|
|
420
|
+
comment: "Foreign key to organization",
|
|
421
|
+
nullable: true,
|
|
422
|
+
})
|
|
423
|
+
@Index()
|
|
424
|
+
organizationId: string | null;
|
|
425
|
+
|
|
426
|
+
@Column({
|
|
427
|
+
type: "enum",
|
|
428
|
+
enum: UserRole,
|
|
429
|
+
default: UserRole.MEMBER,
|
|
430
|
+
comment: "User role determining permissions",
|
|
431
|
+
})
|
|
432
|
+
role: UserRole;
|
|
433
|
+
|
|
434
|
+
@Column({
|
|
435
|
+
type: "jsonb",
|
|
436
|
+
default: {},
|
|
437
|
+
comment: "User preferences and settings",
|
|
438
|
+
})
|
|
439
|
+
settings: UserSettings;
|
|
440
|
+
|
|
441
|
+
@ManyToOne(() => Organization, { onDelete: "SET NULL", nullable: true })
|
|
442
|
+
@JoinColumn()
|
|
443
|
+
organization: Organization | null;
|
|
444
|
+
|
|
445
|
+
@OneToMany(() => Watchlist, watchlist => watchlist.user, {
|
|
446
|
+
orphanedRowAction: "delete",
|
|
447
|
+
})
|
|
448
|
+
watchlists: Watchlist[];
|
|
449
|
+
}
|
|
450
|
+
```
|