@rosetears/aili-pi 0.1.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 +109 -0
- package/THIRD_PARTY_NOTICES.md +64 -0
- package/extensions/index.ts +6 -0
- package/install.sh +5 -0
- package/manifests/adapter-evidence.json +45 -0
- package/manifests/capabilities.json +124 -0
- package/manifests/live-verification.json +26 -0
- package/manifests/provenance.json +71 -0
- package/manifests/roles.json +474 -0
- package/manifests/sbom.json +7797 -0
- package/manifests/skill-compatibility.json +8100 -0
- package/manifests/subagent-provenance.json +37 -0
- package/package.json +91 -0
- package/prompts/build.md +8 -0
- package/prompts/define.md +8 -0
- package/prompts/ideate.md +8 -0
- package/prompts/local-review.md +8 -0
- package/prompts/ship.md +8 -0
- package/roles/agent-evaluator.md +47 -0
- package/roles/ai-regression-scout.md +47 -0
- package/roles/browser-qa-runner.md +47 -0
- package/roles/code-reviewer.md +47 -0
- package/roles/code-scout.md +47 -0
- package/roles/convergence-reviewer.md +55 -0
- package/roles/doc-researcher.md +47 -0
- package/roles/e2e-artifact-runner.md +47 -0
- package/roles/implementer.md +47 -0
- package/roles/opensource-sanitizer.md +47 -0
- package/roles/plan-auditor.md +47 -0
- package/roles/pr-test-analyzer.md +47 -0
- package/roles/security-auditor.md +47 -0
- package/roles/silent-failure-reviewer.md +47 -0
- package/roles/spec-miner.md +47 -0
- package/roles/test-coverage-reviewer.md +47 -0
- package/roles/test-engineer.md +48 -0
- package/roles/web-performance-auditor.md +47 -0
- package/roles/web-researcher.md +47 -0
- package/scripts/apply-adapter-evidence.ts +73 -0
- package/scripts/bootstrap.sh +180 -0
- package/scripts/generate-provenance.ts +143 -0
- package/scripts/local-package-e2e.ts +51 -0
- package/scripts/sync-roles.ts +213 -0
- package/scripts/sync-skills.ts +356 -0
- package/scripts/validate-runtime.ts +11 -0
- package/skills/academic-paper-review/SKILL.md +81 -0
- package/skills/agents-md-initialization/SKILL.md +121 -0
- package/skills/agents-md-initialization/references/agents-template.md +83 -0
- package/skills/agents-md-initialization/references/agents_md.py +215 -0
- package/skills/ai-regression-scout/SKILL.md +24 -0
- package/skills/aili-delivery-flow/SKILL.md +125 -0
- package/skills/aili-delivery-flow/references/artifact-contracts.md +138 -0
- package/skills/aili-delivery-flow/references/backend-routing.md +40 -0
- package/skills/aili-delivery-flow/references/build-execution-loop.md +113 -0
- package/skills/aili-delivery-flow/references/build-goal-mode.md +3 -0
- package/skills/aili-delivery-flow/references/direct-vs-delegated-work.md +38 -0
- package/skills/aili-delivery-flow/references/implementation-packages.md +54 -0
- package/skills/aili-delivery-flow/references/lifecycle.md +127 -0
- package/skills/aili-delivery-flow/references/protocols/acceptance-test-plan.md +18 -0
- package/skills/aili-delivery-flow/references/protocols/alignment-questionnaire.md +10 -0
- package/skills/aili-delivery-flow/references/protocols/closeout-report.md +101 -0
- package/skills/aili-delivery-flow/references/protocols/compact-evidence-pack.md +46 -0
- package/skills/aili-delivery-flow/references/protocols/idea-brief.md +10 -0
- package/skills/aili-delivery-flow/references/protocols/implementation-package.md +53 -0
- package/skills/aili-delivery-flow/references/protocols/research-evidence-pack.md +19 -0
- package/skills/aili-delivery-flow/references/protocols/review-report.md +7 -0
- package/skills/aili-delivery-flow/references/protocols/spec-draft.md +12 -0
- package/skills/aili-delivery-flow/references/protocols/subagent-result.md +60 -0
- package/skills/aili-delivery-flow/references/protocols/subagent-task-packet.md +29 -0
- package/skills/aili-delivery-flow/references/protocols/worktree-context.md +109 -0
- package/skills/aili-delivery-flow/references/questionnaire-policy.md +62 -0
- package/skills/aili-delivery-flow/references/review-repair-loop.md +16 -0
- package/skills/aili-delivery-flow/references/test-document-policy.md +35 -0
- package/skills/android-native-dev/SKILL.md +722 -0
- package/skills/android-native-dev/references/accessibility.md +209 -0
- package/skills/android-native-dev/references/adaptive-screens.md +231 -0
- package/skills/android-native-dev/references/design-style-guide.md +365 -0
- package/skills/android-native-dev/references/functional-requirements.md +229 -0
- package/skills/android-native-dev/references/motion-system.md +203 -0
- package/skills/android-native-dev/references/performance-stability.md +223 -0
- package/skills/android-native-dev/references/privacy-security.md +244 -0
- package/skills/android-native-dev/references/testing.md +554 -0
- package/skills/android-native-dev/references/visual-design.md +246 -0
- package/skills/api-and-interface-design/SKILL.md +318 -0
- package/skills/browser-qa/SKILL.md +32 -0
- package/skills/browser-testing-with-devtools/SKILL.md +323 -0
- package/skills/build-failure-repair/SKILL.md +49 -0
- package/skills/chart-visualization/SKILL.md +73 -0
- package/skills/ci-cd-and-automation/SKILL.md +353 -0
- package/skills/code-review-and-quality/SKILL.md +375 -0
- package/skills/code-review-quality-gates/SKILL.md +132 -0
- package/skills/code-simplification/SKILL.md +371 -0
- package/skills/comment-accuracy-review/SKILL.md +37 -0
- package/skills/consulting-analysis/SKILL.md +69 -0
- package/skills/context-engineering/SKILL.md +375 -0
- package/skills/coverage-review/SKILL.md +24 -0
- package/skills/data-analysis/SKILL.md +74 -0
- package/skills/deprecation-and-migration/SKILL.md +222 -0
- package/skills/documentation-and-adrs/SKILL.md +330 -0
- package/skills/e2e-artifact-handling/SKILL.md +30 -0
- package/skills/evidence-scoped-retrospective/SKILL.md +156 -0
- package/skills/explain-by-allegory/SKILL.md +99 -0
- package/skills/flutter-dev/SKILL.md +162 -0
- package/skills/flutter-dev/references/animations.md +497 -0
- package/skills/flutter-dev/references/bloc-state.md +281 -0
- package/skills/flutter-dev/references/forms.md +656 -0
- package/skills/flutter-dev/references/gorouter-navigation.md +257 -0
- package/skills/flutter-dev/references/localization.md +510 -0
- package/skills/flutter-dev/references/networking.md +566 -0
- package/skills/flutter-dev/references/performance.md +305 -0
- package/skills/flutter-dev/references/platform-specific.md +417 -0
- package/skills/flutter-dev/references/project-structure.md +273 -0
- package/skills/flutter-dev/references/riverpod-state.md +232 -0
- package/skills/flutter-dev/references/testing.md +364 -0
- package/skills/flutter-dev/references/widget-patterns.md +233 -0
- package/skills/frontend-dev/SKILL.md +468 -0
- package/skills/frontend-dev/canvas-fonts/ArsenalSC-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/BigShoulders-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Boldonse-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/CrimsonPro-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/DMMono-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/EricaOne-OFL.txt +94 -0
- package/skills/frontend-dev/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/GeistMono-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Gloock-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/InstrumentSans-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Italiana-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Jura-Light.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Jura-Medium.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Jura-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Lora-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Lora-Italic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Lora-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Lora-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/NationalPark-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Outfit-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/PixelifySans-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/PoiretOne-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/RedHatMono-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Silkscreen-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/SmoochSans-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Tektur-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/WorkSans-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/YoungSerif-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- package/skills/frontend-dev/references/asset-prompt-guide.md +43 -0
- package/skills/frontend-dev/references/env-setup.md +33 -0
- package/skills/frontend-dev/references/minimax-cli-reference.md +133 -0
- package/skills/frontend-dev/references/minimax-image-guide.md +65 -0
- package/skills/frontend-dev/references/minimax-music-guide.md +216 -0
- package/skills/frontend-dev/references/minimax-tts-guide.md +78 -0
- package/skills/frontend-dev/references/minimax-video-guide.md +82 -0
- package/skills/frontend-dev/references/minimax-voice-catalog.md +685 -0
- package/skills/frontend-dev/references/motion-recipes.md +407 -0
- package/skills/frontend-dev/references/troubleshooting.md +85 -0
- package/skills/frontend-dev/scripts/minimax_image.py +137 -0
- package/skills/frontend-dev/scripts/minimax_music.py +157 -0
- package/skills/frontend-dev/scripts/minimax_tts.py +127 -0
- package/skills/frontend-dev/scripts/minimax_video.py +187 -0
- package/skills/frontend-dev/templates/generator_template.js +223 -0
- package/skills/frontend-dev/templates/viewer.html +599 -0
- package/skills/frontend-ui-engineering/SKILL.md +367 -0
- package/skills/fullstack-dev/SKILL.md +819 -0
- package/skills/fullstack-dev/references/api-design.md +444 -0
- package/skills/fullstack-dev/references/auth-flow.md +165 -0
- package/skills/fullstack-dev/references/db-schema.md +706 -0
- package/skills/fullstack-dev/references/django-best-practices.md +466 -0
- package/skills/fullstack-dev/references/environment-management.md +78 -0
- package/skills/fullstack-dev/references/release-checklist.md +278 -0
- package/skills/fullstack-dev/references/technology-selection.md +254 -0
- package/skills/fullstack-dev/references/testing-strategy.md +404 -0
- package/skills/git-workflow-and-versioning/SKILL.md +446 -0
- package/skills/github-evidence-triage/SKILL.md +115 -0
- package/skills/harness-evolution/SKILL.md +59 -0
- package/skills/harness-evolution/references/activation-matrix.md +13 -0
- package/skills/harness-evolution/references/approval-policy.md +20 -0
- package/skills/harness-evolution/references/change-report-template.md +33 -0
- package/skills/harness-evolution/references/component-taxonomy.md +19 -0
- package/skills/harness-evolution/references/verdict-policy.md +13 -0
- package/skills/harness-issue-triage/SKILL.md +72 -0
- package/skills/harness-issue-triage/references/component-diagnosis.md +25 -0
- package/skills/harness-issue-triage/references/triage-report-template.md +34 -0
- package/skills/harness-optimization-audit/SKILL.md +125 -0
- package/skills/idea-refine/SKILL.md +191 -0
- package/skills/idea-refine/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/LICENSE +21 -0
- package/skills/idea-refine/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/NOTICE.md +9 -0
- package/skills/idea-refine/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/idea-refine/SKILL.upstream.md +178 -0
- package/skills/idea-refine/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/idea-refine/examples.md +238 -0
- package/skills/idea-refine/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/idea-refine/frameworks.md +99 -0
- package/skills/idea-refine/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/idea-refine/refinement-criteria.md +113 -0
- package/skills/idea-refine/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/idea-refine/scripts/idea-refine.upstream.sh +15 -0
- package/skills/incremental-implementation/SKILL.md +252 -0
- package/skills/ios-application-dev/SKILL.md +212 -0
- package/skills/ios-application-dev/references/accessibility.md +259 -0
- package/skills/ios-application-dev/references/graphics-animation.md +350 -0
- package/skills/ios-application-dev/references/layout-system.md +199 -0
- package/skills/ios-application-dev/references/metal-shader.md +178 -0
- package/skills/ios-application-dev/references/navigation-patterns.md +175 -0
- package/skills/ios-application-dev/references/swift-coding-standards.md +757 -0
- package/skills/ios-application-dev/references/swiftui-design-guidelines.md +1167 -0
- package/skills/ios-application-dev/references/system-integration.md +401 -0
- package/skills/ios-application-dev/references/uikit-components.md +297 -0
- package/skills/local-review-gate/SKILL.md +207 -0
- package/skills/local-review-gate/references/addyosmani-code-review-rubric.md +33 -0
- package/skills/local-review-gate/references/codex-github-compatibility.md +26 -0
- package/skills/local-review-gate/references/ecc-code-review-adaptation.md +40 -0
- package/skills/local-review-gate/references/graphify-local-review.md +33 -0
- package/skills/local-review-gate/references/orchestration-adaptation.md +51 -0
- package/skills/local-review-gate/references/review-repair-lane-adaptation.md +46 -0
- package/skills/local-review-gate/references/upstream-provenance.md +61 -0
- package/skills/mature-project-pattern-research/SKILL.md +155 -0
- package/skills/mature-project-pattern-research/references/research-rubric.md +45 -0
- package/skills/minimax-docx/LICENSE +21 -0
- package/skills/minimax-docx/SKILL.md +273 -0
- package/skills/minimax-docx/assets/styles/academic_styles.xml +250 -0
- package/skills/minimax-docx/assets/styles/corporate_styles.xml +284 -0
- package/skills/minimax-docx/assets/styles/default_styles.xml +449 -0
- package/skills/minimax-docx/assets/xsd/aesthetic-rules.xsd +470 -0
- package/skills/minimax-docx/assets/xsd/business-rules.xsd +130 -0
- package/skills/minimax-docx/assets/xsd/common-types.xsd +159 -0
- package/skills/minimax-docx/assets/xsd/wml-subset.xsd +589 -0
- package/skills/minimax-docx/references/cjk_typography.md +357 -0
- package/skills/minimax-docx/references/cjk_university_template_guide.md +184 -0
- package/skills/minimax-docx/references/comments_guide.md +191 -0
- package/skills/minimax-docx/references/design_good_bad_examples.md +829 -0
- package/skills/minimax-docx/references/design_principles.md +819 -0
- package/skills/minimax-docx/references/openxml_element_order.md +308 -0
- package/skills/minimax-docx/references/openxml_encyclopedia_part1.md +4061 -0
- package/skills/minimax-docx/references/openxml_encyclopedia_part2.md +2820 -0
- package/skills/minimax-docx/references/openxml_encyclopedia_part3.md +3381 -0
- package/skills/minimax-docx/references/openxml_namespaces.md +82 -0
- package/skills/minimax-docx/references/openxml_units.md +72 -0
- package/skills/minimax-docx/references/scenario_a_create.md +284 -0
- package/skills/minimax-docx/references/scenario_b_edit_content.md +295 -0
- package/skills/minimax-docx/references/scenario_c_apply_template.md +456 -0
- package/skills/minimax-docx/references/track_changes_guide.md +200 -0
- package/skills/minimax-docx/references/troubleshooting.md +506 -0
- package/skills/minimax-docx/references/typography_guide.md +294 -0
- package/skills/minimax-docx/references/xsd_validation_guide.md +158 -0
- package/skills/minimax-docx/scripts/doc_to_docx.sh +40 -0
- package/skills/minimax-docx/scripts/docx_preview.sh +37 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Cli/MiniMaxAIDocx.Cli.csproj +19 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Cli/Program.cs +18 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/AnalyzeCommand.cs +147 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/ApplyTemplateCommand.cs +322 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/CreateCommand.cs +324 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/DiffCommand.cs +155 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/EditContentCommand.cs +487 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/FixOrderCommand.cs +108 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/MergeRunsCommand.cs +122 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/ValidateCommand.cs +107 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/MiniMaxAIDocx.Core.csproj +15 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/CommentSynchronizer.cs +169 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/ElementOrder.cs +80 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/NamespaceConstants.cs +42 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/RunMerger.cs +81 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/StyleAnalyzer.cs +81 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/TrackChangesHelper.cs +99 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/UnitConverter.cs +23 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples.cs +1832 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch1.cs +910 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch2.cs +999 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch3.cs +1048 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch4.cs +1038 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/CharacterFormattingSamples.cs +1020 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/DocumentCreationSamples.cs +1121 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/FieldAndTocSamples.cs +624 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/FootnoteAndCommentSamples.cs +675 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/HeaderFooterSamples.cs +838 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ImageSamples.cs +917 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ListAndNumberingSamples.cs +826 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ParagraphFormattingSamples.cs +1199 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/StyleSystemSamples.cs +1487 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/TableSamples.cs +1163 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/TrackChangesSamples.cs +595 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/CjkHelper.cs +39 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/FontDefaults.cs +24 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/PageSizes.cs +20 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/BusinessRuleValidator.cs +224 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/GateCheckValidator.cs +148 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/ValidationResult.cs +23 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/XsdValidator.cs +69 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.slnx +4 -0
- package/skills/minimax-docx/scripts/env_check.sh +196 -0
- package/skills/minimax-docx/scripts/setup.ps1 +274 -0
- package/skills/minimax-docx/scripts/setup.sh +504 -0
- package/skills/minimax-pdf/README.md +222 -0
- package/skills/minimax-pdf/SKILL.md +218 -0
- package/skills/minimax-pdf/design/design.md +381 -0
- package/skills/minimax-pdf/scripts/cover.py +1579 -0
- package/skills/minimax-pdf/scripts/fill_inspect.py +200 -0
- package/skills/minimax-pdf/scripts/fill_write.py +242 -0
- package/skills/minimax-pdf/scripts/make.sh +491 -0
- package/skills/minimax-pdf/scripts/merge.py +112 -0
- package/skills/minimax-pdf/scripts/palette.py +521 -0
- package/skills/minimax-pdf/scripts/reformat_parse.py +374 -0
- package/skills/minimax-pdf/scripts/render_body.py +1052 -0
- package/skills/minimax-pdf/scripts/render_cover.js +111 -0
- package/skills/minimax-xlsx/SKILL.md +156 -0
- package/skills/minimax-xlsx/references/create.md +691 -0
- package/skills/minimax-xlsx/references/edit.md +684 -0
- package/skills/minimax-xlsx/references/fix.md +37 -0
- package/skills/minimax-xlsx/references/format.md +768 -0
- package/skills/minimax-xlsx/references/ooxml-cheatsheet.md +231 -0
- package/skills/minimax-xlsx/references/read-analyze.md +97 -0
- package/skills/minimax-xlsx/references/validate.md +772 -0
- package/skills/minimax-xlsx/scripts/formula_check.py +422 -0
- package/skills/minimax-xlsx/scripts/libreoffice_recalc.py +248 -0
- package/skills/minimax-xlsx/scripts/shared_strings_builder.py +163 -0
- package/skills/minimax-xlsx/scripts/style_audit.py +575 -0
- package/skills/minimax-xlsx/scripts/xlsx_add_column.py +395 -0
- package/skills/minimax-xlsx/scripts/xlsx_insert_row.py +274 -0
- package/skills/minimax-xlsx/scripts/xlsx_pack.py +87 -0
- package/skills/minimax-xlsx/scripts/xlsx_reader.py +362 -0
- package/skills/minimax-xlsx/scripts/xlsx_shift_rows.py +396 -0
- package/skills/minimax-xlsx/scripts/xlsx_unpack.py +130 -0
- package/skills/minimax-xlsx/templates/minimal_xlsx/[Content_Types].xml +9 -0
- package/skills/minimax-xlsx/templates/minimal_xlsx/_rels/.rels +6 -0
- package/skills/minimax-xlsx/templates/minimal_xlsx/xl/_rels/workbook.xml.rels +19 -0
- package/skills/minimax-xlsx/templates/minimal_xlsx/xl/sharedStrings.xml +33 -0
- package/skills/minimax-xlsx/templates/minimal_xlsx/xl/styles.xml +160 -0
- package/skills/minimax-xlsx/templates/minimal_xlsx/xl/workbook.xml +30 -0
- package/skills/minimax-xlsx/templates/minimal_xlsx/xl/worksheets/sheet1.xml +70 -0
- package/skills/newsletter-generation/SKILL.md +71 -0
- package/skills/oss-release-readiness/SKILL.md +47 -0
- package/skills/parallel-subagent-dispatch/SKILL.md +58 -0
- package/skills/performance-optimization/SKILL.md +364 -0
- package/skills/planning-and-task-breakdown/SKILL.md +290 -0
- package/skills/pptx-generator/SKILL.md +275 -0
- package/skills/pptx-generator/references/design-system.md +392 -0
- package/skills/pptx-generator/references/editing.md +162 -0
- package/skills/pptx-generator/references/pitfalls.md +112 -0
- package/skills/pptx-generator/references/pptxgenjs.md +420 -0
- package/skills/pptx-generator/references/slide-types.md +413 -0
- package/skills/pr-test-analysis/SKILL.md +24 -0
- package/skills/react-native-dev/SKILL.md +180 -0
- package/skills/react-native-dev/references/animations.md +254 -0
- package/skills/react-native-dev/references/components.md +124 -0
- package/skills/react-native-dev/references/engineering.md +527 -0
- package/skills/react-native-dev/references/forms.md +300 -0
- package/skills/react-native-dev/references/native-capabilities.md +163 -0
- package/skills/react-native-dev/references/navigation.md +271 -0
- package/skills/react-native-dev/references/networking.md +346 -0
- package/skills/react-native-dev/references/performance.md +215 -0
- package/skills/react-native-dev/references/state-management.md +230 -0
- package/skills/react-native-dev/references/styling.md +117 -0
- package/skills/react-native-dev/references/testing.md +341 -0
- package/skills/requirements-grilling/SKILL.md +447 -0
- package/skills/requirements-grilling/references/ADR-FORMAT.md +46 -0
- package/skills/requirements-grilling/references/CONTEXT-FORMAT.md +41 -0
- package/skills/requirements-grilling/references/INTERVIEW-PACKET-FORMAT.md +62 -0
- package/skills/requirements-grilling/references/MIT-LICENSE-MATT-POCOCK.md +25 -0
- package/skills/requirements-grilling/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/LICENSE +21 -0
- package/skills/requirements-grilling/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/NOTICE.md +9 -0
- package/skills/requirements-grilling/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/interview-me/SKILL.upstream.md +225 -0
- package/skills/requirements-grilling/references/upstream/mattpocock-skills/9603c1cc8118d08bc1b3bf34cf714f62178dea3b/LICENSE +21 -0
- package/skills/requirements-grilling/references/upstream/mattpocock-skills/9603c1cc8118d08bc1b3bf34cf714f62178dea3b/NOTICE.md +12 -0
- package/skills/requirements-grilling/references/upstream/mattpocock-skills/9603c1cc8118d08bc1b3bf34cf714f62178dea3b/batch-grill-me/SKILL.upstream.md +15 -0
- package/skills/requirements-grilling/references/upstream/mattpocock-skills/9603c1cc8118d08bc1b3bf34cf714f62178dea3b/grill-me/SKILL.upstream.md +7 -0
- package/skills/requirements-grilling/references/upstream/mattpocock-skills/9603c1cc8118d08bc1b3bf34cf714f62178dea3b/grilling/SKILL.upstream.md +12 -0
- package/skills/review-pipeline/SKILL.md +38 -0
- package/skills/rose-memory/SKILL.md +210 -0
- package/skills/rose-memory/references/README.md +48 -0
- package/skills/rose-memory/references/memory_cli.py +2384 -0
- package/skills/rose-memory/references/schema.sql +315 -0
- package/skills/security-and-hardening/SKILL.md +369 -0
- package/skills/session-handoff/SKILL.md +88 -0
- package/skills/session-handoff/references/upstream/mattpocock-skills/391a2701dd948f94f56a39f7533f8eea9a859c87/LICENSE +21 -0
- package/skills/session-handoff/references/upstream/mattpocock-skills/391a2701dd948f94f56a39f7533f8eea9a859c87/NOTICE.md +9 -0
- package/skills/session-handoff/references/upstream/mattpocock-skills/391a2701dd948f94f56a39f7533f8eea9a859c87/productivity/handoff/SKILL.upstream.md +16 -0
- package/skills/session-handoff/scripts/session_handoff.py +764 -0
- package/skills/shader-dev/SKILL.md +316 -0
- package/skills/shader-dev/reference/ambient-occlusion.md +382 -0
- package/skills/shader-dev/reference/analytic-ray-tracing.md +651 -0
- package/skills/shader-dev/reference/anti-aliasing.md +71 -0
- package/skills/shader-dev/reference/atmospheric-scattering.md +571 -0
- package/skills/shader-dev/reference/camera-effects.md +80 -0
- package/skills/shader-dev/reference/cellular-automata.md +635 -0
- package/skills/shader-dev/reference/color-palette.md +481 -0
- package/skills/shader-dev/reference/csg-boolean-operations.md +466 -0
- package/skills/shader-dev/reference/domain-repetition.md +436 -0
- package/skills/shader-dev/reference/domain-warping.md +419 -0
- package/skills/shader-dev/reference/fluid-simulation.md +425 -0
- package/skills/shader-dev/reference/fractal-rendering.md +525 -0
- package/skills/shader-dev/reference/lighting-model.md +639 -0
- package/skills/shader-dev/reference/matrix-transform.md +535 -0
- package/skills/shader-dev/reference/multipass-buffer.md +571 -0
- package/skills/shader-dev/reference/normal-estimation.md +418 -0
- package/skills/shader-dev/reference/particle-system.md +589 -0
- package/skills/shader-dev/reference/path-tracing-gi.md +602 -0
- package/skills/shader-dev/reference/polar-uv-manipulation.md +521 -0
- package/skills/shader-dev/reference/post-processing.md +375 -0
- package/skills/shader-dev/reference/procedural-2d-pattern.md +439 -0
- package/skills/shader-dev/reference/procedural-noise.md +551 -0
- package/skills/shader-dev/reference/ray-marching.md +396 -0
- package/skills/shader-dev/reference/sdf-2d.md +724 -0
- package/skills/shader-dev/reference/sdf-3d.md +805 -0
- package/skills/shader-dev/reference/sdf-tricks.md +63 -0
- package/skills/shader-dev/reference/shadow-techniques.md +476 -0
- package/skills/shader-dev/reference/simulation-physics.md +644 -0
- package/skills/shader-dev/reference/sound-synthesis.md +578 -0
- package/skills/shader-dev/reference/terrain-rendering.md +839 -0
- package/skills/shader-dev/reference/texture-mapping-advanced.md +87 -0
- package/skills/shader-dev/reference/texture-sampling.md +553 -0
- package/skills/shader-dev/reference/volumetric-rendering.md +608 -0
- package/skills/shader-dev/reference/voronoi-cellular-noise.md +486 -0
- package/skills/shader-dev/reference/voxel-rendering.md +701 -0
- package/skills/shader-dev/reference/water-ocean.md +445 -0
- package/skills/shader-dev/reference/webgl-pitfalls.md +41 -0
- package/skills/shader-dev/techniques/ambient-occlusion.md +364 -0
- package/skills/shader-dev/techniques/analytic-ray-tracing.md +542 -0
- package/skills/shader-dev/techniques/anti-aliasing.md +124 -0
- package/skills/shader-dev/techniques/atmospheric-scattering.md +522 -0
- package/skills/shader-dev/techniques/camera-effects.md +115 -0
- package/skills/shader-dev/techniques/cellular-automata.md +531 -0
- package/skills/shader-dev/techniques/color-palette.md +380 -0
- package/skills/shader-dev/techniques/csg-boolean-operations.md +491 -0
- package/skills/shader-dev/techniques/domain-repetition.md +333 -0
- package/skills/shader-dev/techniques/domain-warping.md +414 -0
- package/skills/shader-dev/techniques/fluid-simulation.md +1175 -0
- package/skills/shader-dev/techniques/fractal-rendering.md +436 -0
- package/skills/shader-dev/techniques/lighting-model.md +527 -0
- package/skills/shader-dev/techniques/matrix-transform.md +455 -0
- package/skills/shader-dev/techniques/multipass-buffer.md +922 -0
- package/skills/shader-dev/techniques/normal-estimation.md +318 -0
- package/skills/shader-dev/techniques/particle-system.md +1203 -0
- package/skills/shader-dev/techniques/path-tracing-gi.md +623 -0
- package/skills/shader-dev/techniques/polar-uv-manipulation.md +373 -0
- package/skills/shader-dev/techniques/post-processing.md +788 -0
- package/skills/shader-dev/techniques/procedural-2d-pattern.md +346 -0
- package/skills/shader-dev/techniques/procedural-noise.md +554 -0
- package/skills/shader-dev/techniques/ray-marching.md +467 -0
- package/skills/shader-dev/techniques/sdf-2d.md +631 -0
- package/skills/shader-dev/techniques/sdf-3d.md +589 -0
- package/skills/shader-dev/techniques/sdf-tricks.md +100 -0
- package/skills/shader-dev/techniques/shadow-techniques.md +776 -0
- package/skills/shader-dev/techniques/simulation-physics.md +1542 -0
- package/skills/shader-dev/techniques/sound-synthesis.md +490 -0
- package/skills/shader-dev/techniques/terrain-rendering.md +408 -0
- package/skills/shader-dev/techniques/texture-mapping-advanced.md +121 -0
- package/skills/shader-dev/techniques/texture-sampling.md +382 -0
- package/skills/shader-dev/techniques/volumetric-rendering.md +375 -0
- package/skills/shader-dev/techniques/voronoi-cellular-noise.md +458 -0
- package/skills/shader-dev/techniques/voxel-rendering.md +985 -0
- package/skills/shader-dev/techniques/water-ocean.md +490 -0
- package/skills/shader-dev/techniques/webgl-pitfalls.md +170 -0
- package/skills/shipping-and-launch/SKILL.md +334 -0
- package/skills/silent-failure-hunting/SKILL.md +24 -0
- package/skills/source-driven-development/SKILL.md +223 -0
- package/skills/spec-driven-development/SKILL.md +235 -0
- package/skills/spec-driven-development/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/LICENSE +21 -0
- package/skills/spec-driven-development/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/NOTICE.md +9 -0
- package/skills/spec-driven-development/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/spec-driven-development/SKILL.upstream.md +206 -0
- package/skills/strategy-stress-test/SKILL.md +185 -0
- package/skills/systematic-literature-review/SKILL.md +77 -0
- package/skills/test-document-generator/SKILL.md +152 -0
- package/skills/test-document-generator/references/test-document-template.md +45 -0
- package/skills/test-driven-development/SKILL.md +399 -0
- package/skills/write-skills/GLOSSARY.md +113 -0
- package/skills/write-skills/SKILL.md +133 -0
- package/skills/write-skills/references/upstream/mattpocock-skills/391a2701dd948f94f56a39f7533f8eea9a859c87/LICENSE +21 -0
- package/skills/write-skills/references/upstream/mattpocock-skills/391a2701dd948f94f56a39f7533f8eea9a859c87/NOTICE.md +9 -0
- package/skills/write-skills/references/upstream/mattpocock-skills/391a2701dd948f94f56a39f7533f8eea9a859c87/productivity/writing-great-skills/GLOSSARY.md +201 -0
- package/skills/write-skills/references/upstream/mattpocock-skills/391a2701dd948f94f56a39f7533f8eea9a859c87/productivity/writing-great-skills/SKILL.upstream.md +83 -0
- package/src/runtime/child-guard.ts +70 -0
- package/src/runtime/conflicts.ts +25 -0
- package/src/runtime/contracts.ts +9 -0
- package/src/runtime/doctor.ts +134 -0
- package/src/runtime/global-resources.ts +152 -0
- package/src/runtime/index.ts +23 -0
- package/src/runtime/lifecycle.ts +19 -0
- package/src/runtime/native-integrations.ts +44 -0
- package/src/runtime/path-boundaries.ts +69 -0
- package/src/runtime/registry.ts +213 -0
- package/src/runtime/roles.ts +64 -0
- package/src/runtime/rose-context.ts +24 -0
- package/src/runtime/subagents.ts +426 -0
- package/templates/APPEND_SYSTEM.md +12 -0
- package/upstream/aili-workflows.lock.json +3226 -0
|
@@ -0,0 +1,706 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fullstack-dev-db-schema
|
|
3
|
+
description: "Database schema design and migrations. Use when creating tables, defining ORM models, adding indexes, or designing relationships. Covers zero-downtime migrations and multi-tenancy."
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
version: "1.0.0"
|
|
7
|
+
sources:
|
|
8
|
+
- PostgreSQL official documentation
|
|
9
|
+
- Use The Index, Luke (use-the-index-luke.com)
|
|
10
|
+
- Designing Data-Intensive Applications (Martin Kleppmann)
|
|
11
|
+
- Database Reliability Engineering (Laine Campbell & Charity Majors)
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Database Schema Design
|
|
15
|
+
|
|
16
|
+
ORM-agnostic guide for relational database schema design. Covers data modeling, normalization, indexing, migrations, multi-tenancy, and common application patterns. Primarily PostgreSQL-focused but principles apply to MySQL/MariaDB.
|
|
17
|
+
|
|
18
|
+
## Scope
|
|
19
|
+
|
|
20
|
+
**USE this skill when:**
|
|
21
|
+
- Designing a schema for a new project or feature
|
|
22
|
+
- Deciding between normalization and denormalization
|
|
23
|
+
- Choosing which indexes to create
|
|
24
|
+
- Planning a zero-downtime migration on a live database
|
|
25
|
+
- Implementing multi-tenant data isolation
|
|
26
|
+
- Adding audit trails, soft delete, or versioning
|
|
27
|
+
- Diagnosing slow queries caused by schema problems
|
|
28
|
+
|
|
29
|
+
**NOT for:**
|
|
30
|
+
- Choosing which database technology to use (→ `technology-selection`)
|
|
31
|
+
- PostgreSQL-specific query tuning (use PostgreSQL performance docs)
|
|
32
|
+
- ORM-specific configuration (→ `django-best-practices` or your ORM's docs)
|
|
33
|
+
- Application-layer caching (→ `fullstack-dev-practices`)
|
|
34
|
+
|
|
35
|
+
## Context Required
|
|
36
|
+
|
|
37
|
+
| Required | Optional |
|
|
38
|
+
|----------|----------|
|
|
39
|
+
| Database engine (PostgreSQL / MySQL) | Expected data volume (rows, growth rate) |
|
|
40
|
+
| Domain entities and relationships | Read/write ratio |
|
|
41
|
+
| Key access patterns (queries) | Multi-tenant requirements |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Quick Start Checklist
|
|
46
|
+
|
|
47
|
+
Designing a new schema:
|
|
48
|
+
|
|
49
|
+
- [ ] **Domain entities identified** — map 1 entity = 1 table (not 1 class = 1 table)
|
|
50
|
+
- [ ] **Primary keys**: UUID for public IDs, serial/bigserial for internal-only
|
|
51
|
+
- [ ] **Foreign keys** with explicit `ON DELETE` behavior
|
|
52
|
+
- [ ] **NOT NULL** by default — nullable only when business logic requires it
|
|
53
|
+
- [ ] **Timestamps**: `created_at` + `updated_at` on every table
|
|
54
|
+
- [ ] **Indexes** created for every WHERE, JOIN, ORDER BY column
|
|
55
|
+
- [ ] **No premature denormalization** — start normalized, denormalize when measured
|
|
56
|
+
- [ ] **Naming convention** consistent: `snake_case`, plural table names
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Quick Navigation
|
|
61
|
+
|
|
62
|
+
| Need to… | Jump to |
|
|
63
|
+
|----------|---------|
|
|
64
|
+
| Model entities and relationships | [1. Data Modeling](#1-data-modeling-critical) |
|
|
65
|
+
| Decide normalize vs denormalize | [2. Normalization](#2-normalization-vs-denormalization-critical) |
|
|
66
|
+
| Choose the right index | [3. Indexing](#3-indexing-strategy-critical) |
|
|
67
|
+
| Run migrations safely on live DB | [4. Migrations](#4-zero-downtime-migrations-high) |
|
|
68
|
+
| Design multi-tenant schema | [5. Multi-Tenancy](#5-multi-tenant-design-high) |
|
|
69
|
+
| Add soft delete / audit trails | [6. Common Patterns](#6-common-schema-patterns-medium) |
|
|
70
|
+
| Partition large tables | [7. Partitioning](#7-table-partitioning-medium) |
|
|
71
|
+
| See anti-patterns | [Anti-Patterns](#anti-patterns) |
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Core Principles (7 Rules)
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
1. ✅ Start normalized (3NF) — denormalize only when you have measured evidence
|
|
79
|
+
2. ✅ Every table has a primary key, created_at, updated_at
|
|
80
|
+
3. ✅ UUID for public-facing IDs, serial for internal join keys
|
|
81
|
+
4. ✅ NOT NULL by default — null is a business decision, not a lazy default
|
|
82
|
+
5. ✅ Index every column used in WHERE, JOIN, ORDER BY
|
|
83
|
+
6. ✅ Foreign keys enforced in database (not just application code)
|
|
84
|
+
7. ✅ Migrations are additive — never drop/rename in production without a multi-step plan
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 1. Data Modeling (CRITICAL)
|
|
90
|
+
|
|
91
|
+
### Table Naming
|
|
92
|
+
|
|
93
|
+
```sql
|
|
94
|
+
-- ✅ Plural, snake_case
|
|
95
|
+
CREATE TABLE orders (...);
|
|
96
|
+
CREATE TABLE order_items (...);
|
|
97
|
+
CREATE TABLE user_profiles (...);
|
|
98
|
+
|
|
99
|
+
-- ❌ Singular, mixed case
|
|
100
|
+
CREATE TABLE Order (...);
|
|
101
|
+
CREATE TABLE OrderItem (...);
|
|
102
|
+
CREATE TABLE tbl_usr_prof (...); -- cryptic abbreviation
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Primary Keys
|
|
106
|
+
|
|
107
|
+
| Strategy | When | Pros | Cons |
|
|
108
|
+
|----------|------|------|------|
|
|
109
|
+
| `bigserial` (auto-increment) | Internal tables, FK joins | Compact, fast joins | Enumerable, not safe for public IDs |
|
|
110
|
+
| `uuid` (v4 random) | Public-facing resources | Non-guessable, globally unique | Larger (16 bytes), random I/O on B-Tree |
|
|
111
|
+
| `uuid` v7 (time-sorted) | Public + needs ordering | Non-guessable + insert-friendly | Newer, less ecosystem support |
|
|
112
|
+
| `text` slug | URL-friendly resources | Human-readable | Must enforce uniqueness, updates expensive |
|
|
113
|
+
|
|
114
|
+
**Recommended default:**
|
|
115
|
+
|
|
116
|
+
```sql
|
|
117
|
+
CREATE TABLE orders (
|
|
118
|
+
id bigserial PRIMARY KEY, -- internal FK target
|
|
119
|
+
public_id uuid NOT NULL DEFAULT gen_random_uuid() UNIQUE, -- API-facing
|
|
120
|
+
-- ...
|
|
121
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
122
|
+
updated_at timestamptz NOT NULL DEFAULT now()
|
|
123
|
+
);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Relationships
|
|
127
|
+
|
|
128
|
+
```sql
|
|
129
|
+
-- One-to-Many: user → orders
|
|
130
|
+
CREATE TABLE orders (
|
|
131
|
+
id bigserial PRIMARY KEY,
|
|
132
|
+
user_id bigint NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
133
|
+
-- ...
|
|
134
|
+
);
|
|
135
|
+
CREATE INDEX idx_orders_user_id ON orders(user_id);
|
|
136
|
+
|
|
137
|
+
-- Many-to-Many: orders ↔ products (via junction table)
|
|
138
|
+
CREATE TABLE order_items (
|
|
139
|
+
id bigserial PRIMARY KEY,
|
|
140
|
+
order_id bigint NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
|
|
141
|
+
product_id bigint NOT NULL REFERENCES products(id) ON DELETE RESTRICT,
|
|
142
|
+
quantity int NOT NULL CHECK (quantity > 0),
|
|
143
|
+
unit_price numeric(10,2) NOT NULL,
|
|
144
|
+
UNIQUE (order_id, product_id) -- prevent duplicate line items
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
-- One-to-One: user → profile
|
|
148
|
+
CREATE TABLE user_profiles (
|
|
149
|
+
user_id bigint PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
|
|
150
|
+
bio text,
|
|
151
|
+
avatar_url text,
|
|
152
|
+
-- ...
|
|
153
|
+
);
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### ON DELETE Behavior
|
|
157
|
+
|
|
158
|
+
| Behavior | When | Example |
|
|
159
|
+
|----------|------|---------|
|
|
160
|
+
| `CASCADE` | Child meaningless without parent | order_items when order deleted |
|
|
161
|
+
| `RESTRICT` | Prevent accidental deletion | products referenced by order_items |
|
|
162
|
+
| `SET NULL` | Preserve child, clear reference | orders.assigned_to when employee leaves |
|
|
163
|
+
| `SET DEFAULT` | Fallback to default value | Rare, for status columns |
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 2. Normalization vs Denormalization (CRITICAL)
|
|
168
|
+
|
|
169
|
+
### Start Normalized (3NF)
|
|
170
|
+
|
|
171
|
+
**Normal forms in practice:**
|
|
172
|
+
|
|
173
|
+
| Form | Rule | Example Violation |
|
|
174
|
+
|------|------|-------------------|
|
|
175
|
+
| 1NF | No repeating groups, atomic values | `tags = "go,python,rust"` in one column |
|
|
176
|
+
| 2NF | No partial dependencies (composite keys) | `order_items.product_name` depends on `product_id` alone |
|
|
177
|
+
| 3NF | No transitive dependencies | `orders.customer_city` depends on `customer_id`, not `order_id` |
|
|
178
|
+
|
|
179
|
+
**1NF violation fix:**
|
|
180
|
+
```sql
|
|
181
|
+
-- ❌ Tags as comma-separated string
|
|
182
|
+
CREATE TABLE posts (id serial, tags text); -- tags = "go,python"
|
|
183
|
+
|
|
184
|
+
-- ✅ Separate table (or array/JSONB if simple)
|
|
185
|
+
CREATE TABLE post_tags (
|
|
186
|
+
post_id bigint REFERENCES posts(id) ON DELETE CASCADE,
|
|
187
|
+
tag_id bigint REFERENCES tags(id) ON DELETE CASCADE,
|
|
188
|
+
PRIMARY KEY (post_id, tag_id)
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
-- ✅ Alternative: PostgreSQL array (if tags are just strings, no metadata)
|
|
192
|
+
CREATE TABLE posts (id serial, tags text[] NOT NULL DEFAULT '{}');
|
|
193
|
+
CREATE INDEX idx_posts_tags ON posts USING GIN(tags);
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### When to Denormalize
|
|
197
|
+
|
|
198
|
+
**Denormalize ONLY when:**
|
|
199
|
+
1. You have **measured** a performance problem (EXPLAIN ANALYZE, not "I think it's slow")
|
|
200
|
+
2. The denormalized data is **read-heavy** (read:write ratio > 100:1)
|
|
201
|
+
3. You accept the **consistency maintenance cost** (triggers, application logic, or materialized views)
|
|
202
|
+
|
|
203
|
+
**Safe denormalization patterns:**
|
|
204
|
+
|
|
205
|
+
```sql
|
|
206
|
+
-- Pattern 1: Materialized view (computed, refreshable)
|
|
207
|
+
CREATE MATERIALIZED VIEW order_summary AS
|
|
208
|
+
SELECT o.id, o.user_id, o.total,
|
|
209
|
+
COUNT(oi.id) AS item_count,
|
|
210
|
+
u.email AS user_email
|
|
211
|
+
FROM orders o
|
|
212
|
+
JOIN order_items oi ON oi.order_id = o.id
|
|
213
|
+
JOIN users u ON u.id = o.user_id
|
|
214
|
+
GROUP BY o.id, u.email;
|
|
215
|
+
|
|
216
|
+
REFRESH MATERIALIZED VIEW CONCURRENTLY order_summary; -- non-blocking
|
|
217
|
+
|
|
218
|
+
-- Pattern 2: Cached aggregate column (application-maintained)
|
|
219
|
+
ALTER TABLE orders ADD COLUMN item_count int NOT NULL DEFAULT 0;
|
|
220
|
+
-- Update via trigger or application code on order_item insert/delete
|
|
221
|
+
|
|
222
|
+
-- Pattern 3: JSONB snapshot (freeze-at-write-time)
|
|
223
|
+
-- Store a copy of the product details at the time of purchase
|
|
224
|
+
CREATE TABLE order_items (
|
|
225
|
+
id bigserial PRIMARY KEY,
|
|
226
|
+
order_id bigint NOT NULL REFERENCES orders(id),
|
|
227
|
+
product_id bigint REFERENCES products(id),
|
|
228
|
+
quantity int NOT NULL,
|
|
229
|
+
unit_price numeric(10,2) NOT NULL, -- frozen price
|
|
230
|
+
product_snapshot jsonb NOT NULL -- frozen name, description, image
|
|
231
|
+
);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## 3. Indexing Strategy (CRITICAL)
|
|
237
|
+
|
|
238
|
+
### Index Types (PostgreSQL)
|
|
239
|
+
|
|
240
|
+
| Type | When | Example |
|
|
241
|
+
|------|------|---------|
|
|
242
|
+
| **B-Tree** (default) | Equality, range, ORDER BY | `WHERE status = 'active'`, `WHERE created_at > '2025-01-01'` |
|
|
243
|
+
| **Hash** | Equality only (rare, B-Tree usually better) | `WHERE id = 123` (large tables, Postgres 10+) |
|
|
244
|
+
| **GIN** | Arrays, JSONB, full-text search | `WHERE tags @> '{go}'`, `WHERE data->>'key' = 'val'` |
|
|
245
|
+
| **GiST** | Geometry, ranges, nearest-neighbor | PostGIS, tsrange, ltree |
|
|
246
|
+
| **BRIN** | Very large tables with natural ordering | Time-series data sorted by timestamp |
|
|
247
|
+
|
|
248
|
+
### Index Decision Rules
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
Rule 1: Index every column in WHERE clauses
|
|
252
|
+
Rule 2: Index every column used in JOIN ON conditions
|
|
253
|
+
Rule 3: Index every column in ORDER BY (if queried with LIMIT)
|
|
254
|
+
Rule 4: Composite index for multi-column WHERE (leftmost prefix rule)
|
|
255
|
+
Rule 5: Partial index when filtering a subset (e.g., only active records)
|
|
256
|
+
Rule 6: Covering index (INCLUDE) to avoid table lookup
|
|
257
|
+
Rule 7: DON'T index low-cardinality columns alone (e.g., boolean)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Composite Index: Column Order Matters
|
|
261
|
+
|
|
262
|
+
```sql
|
|
263
|
+
-- Query: WHERE user_id = ? AND status = ? ORDER BY created_at DESC
|
|
264
|
+
-- ✅ Optimal: matches query pattern left-to-right
|
|
265
|
+
CREATE INDEX idx_orders_user_status_created
|
|
266
|
+
ON orders(user_id, status, created_at DESC);
|
|
267
|
+
|
|
268
|
+
-- ❌ Wrong order: can't use for this query efficiently
|
|
269
|
+
CREATE INDEX idx_orders_created_user_status
|
|
270
|
+
ON orders(created_at DESC, user_id, status);
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**Leftmost prefix rule:** Index on `(A, B, C)` supports queries on `(A)`, `(A, B)`, `(A, B, C)` but NOT `(B)`, `(C)`, or `(B, C)`.
|
|
274
|
+
|
|
275
|
+
### Partial Index (Index Only What Matters)
|
|
276
|
+
|
|
277
|
+
```sql
|
|
278
|
+
-- Only 5% of orders are 'pending', but queried frequently
|
|
279
|
+
CREATE INDEX idx_orders_pending
|
|
280
|
+
ON orders(created_at DESC)
|
|
281
|
+
WHERE status = 'pending';
|
|
282
|
+
|
|
283
|
+
-- Only active users matter for login
|
|
284
|
+
CREATE INDEX idx_users_active_email
|
|
285
|
+
ON users(email)
|
|
286
|
+
WHERE is_active = true;
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Covering Index (Avoid Table Lookup)
|
|
290
|
+
|
|
291
|
+
```sql
|
|
292
|
+
-- Query only needs id and status, no need to read the table row
|
|
293
|
+
CREATE INDEX idx_orders_user_covering
|
|
294
|
+
ON orders(user_id) INCLUDE (status, total);
|
|
295
|
+
|
|
296
|
+
-- Now this query is index-only:
|
|
297
|
+
SELECT status, total FROM orders WHERE user_id = 123;
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### When NOT to Index
|
|
301
|
+
|
|
302
|
+
```
|
|
303
|
+
❌ Columns rarely used in WHERE/JOIN/ORDER BY
|
|
304
|
+
❌ Tables with < 1,000 rows (sequential scan is faster)
|
|
305
|
+
❌ Columns with very low cardinality alone (e.g., boolean is_active)
|
|
306
|
+
❌ Write-heavy tables where index maintenance cost > read benefit
|
|
307
|
+
❌ Duplicate indexes (check pg_stat_user_indexes for unused indexes)
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## 4. Zero-Downtime Migrations (HIGH)
|
|
313
|
+
|
|
314
|
+
### The Golden Rule
|
|
315
|
+
|
|
316
|
+
```
|
|
317
|
+
NEVER make destructive changes in one step.
|
|
318
|
+
Always: ADD → MIGRATE DATA → REMOVE OLD (in separate deploys).
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Safe Migration Patterns
|
|
322
|
+
|
|
323
|
+
**Rename a column (3 deploys):**
|
|
324
|
+
|
|
325
|
+
```
|
|
326
|
+
Deploy 1: Add new column
|
|
327
|
+
ALTER TABLE users ADD COLUMN full_name text;
|
|
328
|
+
UPDATE users SET full_name = name; -- backfill
|
|
329
|
+
-- App writes to BOTH name and full_name
|
|
330
|
+
|
|
331
|
+
Deploy 2: Switch reads to new column
|
|
332
|
+
-- App reads from full_name, still writes to both
|
|
333
|
+
|
|
334
|
+
Deploy 3: Drop old column
|
|
335
|
+
ALTER TABLE users DROP COLUMN name;
|
|
336
|
+
-- App only uses full_name
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Add a NOT NULL column (2 deploys):**
|
|
340
|
+
|
|
341
|
+
```sql
|
|
342
|
+
-- Deploy 1: Add nullable column, backfill
|
|
343
|
+
ALTER TABLE orders ADD COLUMN currency text; -- nullable first
|
|
344
|
+
UPDATE orders SET currency = 'USD' WHERE currency IS NULL; -- backfill
|
|
345
|
+
|
|
346
|
+
-- Deploy 2: Add constraint (after all rows backfilled)
|
|
347
|
+
ALTER TABLE orders ALTER COLUMN currency SET NOT NULL;
|
|
348
|
+
ALTER TABLE orders ALTER COLUMN currency SET DEFAULT 'USD';
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**Add an index without locking:**
|
|
352
|
+
|
|
353
|
+
```sql
|
|
354
|
+
-- ✅ CONCURRENTLY: no table lock, can run on live DB
|
|
355
|
+
CREATE INDEX CONCURRENTLY idx_orders_status ON orders(status);
|
|
356
|
+
|
|
357
|
+
-- ❌ Without CONCURRENTLY: locks table for writes during build
|
|
358
|
+
CREATE INDEX idx_orders_status ON orders(status);
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Migration Safety Checklist
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
✅ Migration runs in < 30 seconds on production data size
|
|
365
|
+
✅ No exclusive table locks (use CONCURRENTLY for indexes)
|
|
366
|
+
✅ Rollback plan documented and tested
|
|
367
|
+
✅ Backfill runs in batches (not one giant UPDATE)
|
|
368
|
+
✅ New column added as nullable first, constraint added later
|
|
369
|
+
✅ Old column kept until all code references removed
|
|
370
|
+
|
|
371
|
+
❌ Never rename/drop columns in one deploy
|
|
372
|
+
❌ Never ALTER TYPE on large tables without testing timing
|
|
373
|
+
❌ Never run data backfill in a transaction (OOM on large tables)
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Batch Backfill Template
|
|
377
|
+
|
|
378
|
+
```sql
|
|
379
|
+
-- Backfill in batches of 10,000 (avoids long-running transactions)
|
|
380
|
+
DO $$
|
|
381
|
+
DECLARE
|
|
382
|
+
batch_size int := 10000;
|
|
383
|
+
affected int;
|
|
384
|
+
BEGIN
|
|
385
|
+
LOOP
|
|
386
|
+
UPDATE orders
|
|
387
|
+
SET currency = 'USD'
|
|
388
|
+
WHERE id IN (
|
|
389
|
+
SELECT id FROM orders WHERE currency IS NULL LIMIT batch_size
|
|
390
|
+
);
|
|
391
|
+
GET DIAGNOSTICS affected = ROW_COUNT;
|
|
392
|
+
RAISE NOTICE 'Updated % rows', affected;
|
|
393
|
+
EXIT WHEN affected = 0;
|
|
394
|
+
PERFORM pg_sleep(0.1); -- brief pause to reduce load
|
|
395
|
+
END LOOP;
|
|
396
|
+
END $$;
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## 5. Multi-Tenant Design (HIGH)
|
|
402
|
+
|
|
403
|
+
### Three Approaches
|
|
404
|
+
|
|
405
|
+
| Approach | Isolation | Complexity | When |
|
|
406
|
+
|----------|-----------|------------|------|
|
|
407
|
+
| **Row-level** (shared tables + `tenant_id`) | Low | Low | SaaS MVP, < 1,000 tenants |
|
|
408
|
+
| **Schema-per-tenant** | Medium | Medium | Regulated industries, moderate scale |
|
|
409
|
+
| **Database-per-tenant** | High | High | Enterprise, strict data isolation |
|
|
410
|
+
|
|
411
|
+
### Row-Level Tenancy (Most Common)
|
|
412
|
+
|
|
413
|
+
```sql
|
|
414
|
+
-- Every table has tenant_id
|
|
415
|
+
CREATE TABLE orders (
|
|
416
|
+
id bigserial PRIMARY KEY,
|
|
417
|
+
tenant_id bigint NOT NULL REFERENCES tenants(id),
|
|
418
|
+
user_id bigint NOT NULL REFERENCES users(id),
|
|
419
|
+
total numeric(10,2) NOT NULL,
|
|
420
|
+
-- ...
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
-- Composite index: tenant first (most queries filter by tenant)
|
|
424
|
+
CREATE INDEX idx_orders_tenant_user ON orders(tenant_id, user_id);
|
|
425
|
+
CREATE INDEX idx_orders_tenant_status ON orders(tenant_id, status);
|
|
426
|
+
|
|
427
|
+
-- Row-Level Security (PostgreSQL)
|
|
428
|
+
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
|
|
429
|
+
CREATE POLICY tenant_isolation ON orders
|
|
430
|
+
USING (tenant_id = current_setting('app.tenant_id')::bigint);
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
**Application-level enforcement:**
|
|
434
|
+
|
|
435
|
+
```typescript
|
|
436
|
+
// Middleware: set tenant context on every request
|
|
437
|
+
app.use((req, res, next) => {
|
|
438
|
+
const tenantId = req.headers['x-tenant-id'];
|
|
439
|
+
if (!tenantId) return res.status(400).json({ error: 'Missing tenant' });
|
|
440
|
+
req.tenantId = tenantId;
|
|
441
|
+
next();
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// Repository: ALWAYS filter by tenant
|
|
445
|
+
async findOrders(tenantId: string, userId: string) {
|
|
446
|
+
return db.order.findMany({
|
|
447
|
+
where: { tenantId, userId }, // ← tenant_id in EVERY query
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### Rules
|
|
453
|
+
|
|
454
|
+
```
|
|
455
|
+
✅ tenant_id in EVERY table that holds tenant data
|
|
456
|
+
✅ tenant_id as FIRST column in every composite index
|
|
457
|
+
✅ Application middleware enforces tenant context
|
|
458
|
+
✅ Use RLS (PostgreSQL) as defense-in-depth, not sole protection
|
|
459
|
+
✅ Test with 2+ tenants to verify isolation
|
|
460
|
+
|
|
461
|
+
❌ Never allow cross-tenant queries in application code
|
|
462
|
+
❌ Never skip tenant_id in WHERE clauses (even in admin tools)
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
## 6. Common Schema Patterns (MEDIUM)
|
|
468
|
+
|
|
469
|
+
### Soft Delete
|
|
470
|
+
|
|
471
|
+
```sql
|
|
472
|
+
ALTER TABLE orders ADD COLUMN deleted_at timestamptz;
|
|
473
|
+
|
|
474
|
+
-- All queries filter deleted records
|
|
475
|
+
CREATE VIEW active_orders AS
|
|
476
|
+
SELECT * FROM orders WHERE deleted_at IS NULL;
|
|
477
|
+
|
|
478
|
+
-- Partial index: only index non-deleted rows
|
|
479
|
+
CREATE INDEX idx_orders_active_status
|
|
480
|
+
ON orders(status, created_at DESC)
|
|
481
|
+
WHERE deleted_at IS NULL;
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
**ORM integration:**
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
// Prisma middleware: auto-filter soft-deleted records
|
|
488
|
+
prisma.$use(async (params, next) => {
|
|
489
|
+
if (params.action === 'findMany' || params.action === 'findFirst') {
|
|
490
|
+
params.args.where = { ...params.args.where, deletedAt: null };
|
|
491
|
+
}
|
|
492
|
+
return next(params);
|
|
493
|
+
});
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### Audit Trail
|
|
497
|
+
|
|
498
|
+
```sql
|
|
499
|
+
-- Option A: Audit columns on every table
|
|
500
|
+
ALTER TABLE orders ADD COLUMN created_by bigint REFERENCES users(id);
|
|
501
|
+
ALTER TABLE orders ADD COLUMN updated_by bigint REFERENCES users(id);
|
|
502
|
+
|
|
503
|
+
-- Option B: Separate audit log table (more detail)
|
|
504
|
+
CREATE TABLE audit_log (
|
|
505
|
+
id bigserial PRIMARY KEY,
|
|
506
|
+
table_name text NOT NULL,
|
|
507
|
+
record_id bigint NOT NULL,
|
|
508
|
+
action text NOT NULL CHECK (action IN ('INSERT', 'UPDATE', 'DELETE')),
|
|
509
|
+
old_data jsonb,
|
|
510
|
+
new_data jsonb,
|
|
511
|
+
changed_by bigint REFERENCES users(id),
|
|
512
|
+
changed_at timestamptz NOT NULL DEFAULT now()
|
|
513
|
+
);
|
|
514
|
+
CREATE INDEX idx_audit_table_record ON audit_log(table_name, record_id);
|
|
515
|
+
CREATE INDEX idx_audit_changed_at ON audit_log(changed_at DESC);
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### Enum Columns
|
|
519
|
+
|
|
520
|
+
```sql
|
|
521
|
+
-- Option A: PostgreSQL enum type (strict, but ALTER TYPE is painful)
|
|
522
|
+
CREATE TYPE order_status AS ENUM ('pending', 'confirmed', 'shipped', 'delivered', 'cancelled');
|
|
523
|
+
ALTER TABLE orders ADD COLUMN status order_status NOT NULL DEFAULT 'pending';
|
|
524
|
+
|
|
525
|
+
-- Option B: Text + CHECK constraint (easier to migrate)
|
|
526
|
+
ALTER TABLE orders ADD COLUMN status text NOT NULL DEFAULT 'pending'
|
|
527
|
+
CHECK (status IN ('pending', 'confirmed', 'shipped', 'delivered', 'cancelled'));
|
|
528
|
+
|
|
529
|
+
-- Option C: Lookup table (most flexible, best for UI-driven lists)
|
|
530
|
+
CREATE TABLE order_statuses (
|
|
531
|
+
id serial PRIMARY KEY,
|
|
532
|
+
name text UNIQUE NOT NULL,
|
|
533
|
+
label text NOT NULL -- display name
|
|
534
|
+
);
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
**Recommendation:** Option B (text + CHECK) for most cases. Option C if statuses are managed by non-developers.
|
|
538
|
+
|
|
539
|
+
### Polymorphic Associations
|
|
540
|
+
|
|
541
|
+
```sql
|
|
542
|
+
-- ❌ Anti-pattern: polymorphic FK (no referential integrity)
|
|
543
|
+
CREATE TABLE comments (
|
|
544
|
+
id bigserial PRIMARY KEY,
|
|
545
|
+
commentable_type text, -- 'Post' or 'Photo'
|
|
546
|
+
commentable_id bigint, -- no FK constraint possible!
|
|
547
|
+
body text
|
|
548
|
+
);
|
|
549
|
+
|
|
550
|
+
-- ✅ Pattern A: Separate FK columns (nullable)
|
|
551
|
+
CREATE TABLE comments (
|
|
552
|
+
id bigserial PRIMARY KEY,
|
|
553
|
+
post_id bigint REFERENCES posts(id) ON DELETE CASCADE,
|
|
554
|
+
photo_id bigint REFERENCES photos(id) ON DELETE CASCADE,
|
|
555
|
+
body text NOT NULL,
|
|
556
|
+
CHECK (
|
|
557
|
+
(post_id IS NOT NULL AND photo_id IS NULL) OR
|
|
558
|
+
(post_id IS NULL AND photo_id IS NOT NULL)
|
|
559
|
+
)
|
|
560
|
+
);
|
|
561
|
+
|
|
562
|
+
-- ✅ Pattern B: Separate tables (cleanest, best for different schemas)
|
|
563
|
+
CREATE TABLE post_comments (..., post_id bigint REFERENCES posts(id));
|
|
564
|
+
CREATE TABLE photo_comments (..., photo_id bigint REFERENCES photos(id));
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
### JSONB Columns (Semi-Structured Data)
|
|
568
|
+
|
|
569
|
+
```sql
|
|
570
|
+
-- Good uses: metadata, settings, flexible attributes
|
|
571
|
+
CREATE TABLE products (
|
|
572
|
+
id bigserial PRIMARY KEY,
|
|
573
|
+
name text NOT NULL,
|
|
574
|
+
price numeric(10,2) NOT NULL,
|
|
575
|
+
attributes jsonb NOT NULL DEFAULT '{}' -- color, size, weight...
|
|
576
|
+
);
|
|
577
|
+
|
|
578
|
+
-- Index for JSONB queries
|
|
579
|
+
CREATE INDEX idx_products_attrs ON products USING GIN(attributes);
|
|
580
|
+
|
|
581
|
+
-- Query
|
|
582
|
+
SELECT * FROM products WHERE attributes->>'color' = 'red';
|
|
583
|
+
SELECT * FROM products WHERE attributes @> '{"size": "XL"}';
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
```
|
|
587
|
+
✅ Use JSONB for truly flexible/optional data (metadata, settings, preferences)
|
|
588
|
+
✅ Index JSONB columns with GIN when queried
|
|
589
|
+
|
|
590
|
+
❌ Never use JSONB for data that should be columns (email, status, price)
|
|
591
|
+
❌ Never use JSONB to avoid schema design (it's not MongoDB-in-Postgres)
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
596
|
+
## 7. Table Partitioning (MEDIUM)
|
|
597
|
+
|
|
598
|
+
### When to Partition
|
|
599
|
+
|
|
600
|
+
```
|
|
601
|
+
✅ Table > 100M rows AND growing
|
|
602
|
+
✅ Most queries filter on the partition key (date range, tenant)
|
|
603
|
+
✅ Old data can be dropped/archived by partition (efficient DELETE)
|
|
604
|
+
|
|
605
|
+
❌ Table < 10M rows (overhead not worth it)
|
|
606
|
+
❌ Queries don't filter on partition key (scans all partitions)
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### Range Partitioning (Time-Series)
|
|
610
|
+
|
|
611
|
+
```sql
|
|
612
|
+
CREATE TABLE events (
|
|
613
|
+
id bigserial,
|
|
614
|
+
tenant_id bigint NOT NULL,
|
|
615
|
+
event_type text NOT NULL,
|
|
616
|
+
payload jsonb,
|
|
617
|
+
created_at timestamptz NOT NULL DEFAULT now()
|
|
618
|
+
) PARTITION BY RANGE (created_at);
|
|
619
|
+
|
|
620
|
+
-- Monthly partitions
|
|
621
|
+
CREATE TABLE events_2025_01 PARTITION OF events
|
|
622
|
+
FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');
|
|
623
|
+
CREATE TABLE events_2025_02 PARTITION OF events
|
|
624
|
+
FOR VALUES FROM ('2025-02-01') TO ('2025-03-01');
|
|
625
|
+
|
|
626
|
+
-- Automate partition creation with pg_partman or cron
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
### List Partitioning (Multi-Tenant)
|
|
630
|
+
|
|
631
|
+
```sql
|
|
632
|
+
CREATE TABLE orders (
|
|
633
|
+
id bigserial,
|
|
634
|
+
tenant_id bigint NOT NULL,
|
|
635
|
+
total numeric(10,2)
|
|
636
|
+
) PARTITION BY LIST (tenant_id);
|
|
637
|
+
|
|
638
|
+
CREATE TABLE orders_tenant_1 PARTITION OF orders FOR VALUES IN (1);
|
|
639
|
+
CREATE TABLE orders_tenant_2 PARTITION OF orders FOR VALUES IN (2);
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
---
|
|
643
|
+
|
|
644
|
+
## Anti-Patterns
|
|
645
|
+
|
|
646
|
+
| # | ❌ Don't | ✅ Do Instead |
|
|
647
|
+
|---|---------|--------------|
|
|
648
|
+
| 1 | Premature denormalization | Start 3NF, denormalize when measured |
|
|
649
|
+
| 2 | Auto-increment IDs as public API identifiers | UUID for public, serial for internal |
|
|
650
|
+
| 3 | No foreign key constraints | FK enforced in database, always |
|
|
651
|
+
| 4 | Nullable by default | NOT NULL by default, nullable when required |
|
|
652
|
+
| 5 | No indexes on FK columns | Index every FK column |
|
|
653
|
+
| 6 | Single-step destructive migration | ADD → MIGRATE → REMOVE in separate deploys |
|
|
654
|
+
| 7 | `CREATE INDEX` without `CONCURRENTLY` | Always `CONCURRENTLY` on live tables |
|
|
655
|
+
| 8 | Polymorphic FK (`commentable_type + commentable_id`) | Separate FK columns or separate tables |
|
|
656
|
+
| 9 | JSONB for everything | JSONB for flexible data only, columns for structured |
|
|
657
|
+
| 10 | No `created_at` / `updated_at` | Timestamp pair on every table |
|
|
658
|
+
| 11 | Comma-separated values in one column | Separate table or PostgreSQL array |
|
|
659
|
+
| 12 | `text` without length validation | CHECK constraint or application validation |
|
|
660
|
+
|
|
661
|
+
---
|
|
662
|
+
|
|
663
|
+
## Common Issues
|
|
664
|
+
|
|
665
|
+
### Issue 1: "Query is slow but I already have an index"
|
|
666
|
+
|
|
667
|
+
**Symptom:** `EXPLAIN ANALYZE` shows Sequential Scan despite existing index.
|
|
668
|
+
|
|
669
|
+
**Causes:**
|
|
670
|
+
1. **Wrong index column order** — composite index `(A, B)` won't help `WHERE B = ?`
|
|
671
|
+
2. **Low selectivity** — index on boolean column (50% of rows match), planner prefers seq scan
|
|
672
|
+
3. **Stale statistics** — run `ANALYZE table_name;`
|
|
673
|
+
4. **Type mismatch** — comparing `varchar` column with `integer` parameter → no index use
|
|
674
|
+
|
|
675
|
+
**Fix:** Check `EXPLAIN (ANALYZE, BUFFERS)`, verify index matches query pattern, run `ANALYZE`.
|
|
676
|
+
|
|
677
|
+
### Issue 2: "Migration locks the table for minutes"
|
|
678
|
+
|
|
679
|
+
**Symptom:** `ALTER TABLE` blocks all writes during execution.
|
|
680
|
+
|
|
681
|
+
**Cause:** Adding NOT NULL constraint, changing column type, or creating index without `CONCURRENTLY`.
|
|
682
|
+
|
|
683
|
+
**Fix:**
|
|
684
|
+
```sql
|
|
685
|
+
-- Add index without lock
|
|
686
|
+
CREATE INDEX CONCURRENTLY idx_name ON table(col);
|
|
687
|
+
|
|
688
|
+
-- Add NOT NULL constraint without lock (Postgres 12+)
|
|
689
|
+
ALTER TABLE t ADD CONSTRAINT t_col_nn CHECK (col IS NOT NULL) NOT VALID;
|
|
690
|
+
ALTER TABLE t VALIDATE CONSTRAINT t_col_nn; -- non-blocking validation
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
### Issue 3: "How many indexes is too many?"
|
|
694
|
+
|
|
695
|
+
**Rule of thumb:**
|
|
696
|
+
- Read-heavy table (reports, product catalog): 5-10 indexes is fine
|
|
697
|
+
- Write-heavy table (events, logs): 2-3 indexes max
|
|
698
|
+
- Monitor with `pg_stat_user_indexes` — drop indexes with `idx_scan = 0`
|
|
699
|
+
|
|
700
|
+
```sql
|
|
701
|
+
-- Find unused indexes
|
|
702
|
+
SELECT schemaname, relname, indexrelname, idx_scan
|
|
703
|
+
FROM pg_stat_user_indexes
|
|
704
|
+
WHERE idx_scan = 0 AND indexrelname NOT LIKE '%pkey%'
|
|
705
|
+
ORDER BY pg_relation_size(indexrelid) DESC;
|
|
706
|
+
```
|