@ngockhoale/ukit 1.1.6
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/CHANGELOG.md +179 -0
- package/LICENSE +21 -0
- package/README.md +189 -0
- package/bin/ukit +30 -0
- package/manifests/platform.full.yaml +1194 -0
- package/package.json +71 -0
- package/scripts/bug/triage.mjs +37 -0
- package/scripts/index/build-index.mjs +35 -0
- package/scripts/index/query-index.mjs +92 -0
- package/scripts/index/refresh-index.mjs +85 -0
- package/scripts/release/verify-release.mjs +56 -0
- package/src/bug/triageBug.js +123 -0
- package/src/cli/adapters.js +148 -0
- package/src/cli/commands/diff.js +51 -0
- package/src/cli/commands/doctor.js +125 -0
- package/src/cli/commands/indexArgs.js +73 -0
- package/src/cli/commands/indexTools.js +509 -0
- package/src/cli/commands/install.js +293 -0
- package/src/cli/commands/memory.js +126 -0
- package/src/cli/commands/status.js +8 -0
- package/src/cli/commands/uninstall.js +51 -0
- package/src/cli/index.js +109 -0
- package/src/context/detectProjectContext.js +49 -0
- package/src/context/detectProviders.js +12 -0
- package/src/core/applyPlan.js +89 -0
- package/src/core/buildPlan.js +228 -0
- package/src/core/compact/index.js +294 -0
- package/src/core/compact/threshold.js +936 -0
- package/src/core/diffPlan.js +73 -0
- package/src/core/ensureGitignore.js +117 -0
- package/src/core/fileOps.js +188 -0
- package/src/core/memory/hygiene.js +160 -0
- package/src/core/memory/index.js +2 -0
- package/src/core/memory/retrieval.js +476 -0
- package/src/core/memory/store.js +202 -0
- package/src/core/metadata.js +132 -0
- package/src/core/migrateLegacy.js +139 -0
- package/src/core/output/index.js +1309 -0
- package/src/core/paths.js +13 -0
- package/src/core/report.js +17 -0
- package/src/core/router/advisor.js +42 -0
- package/src/core/router/index.js +2 -0
- package/src/core/router/router.js +164 -0
- package/src/core/runInstallPipeline.js +365 -0
- package/src/core/runtimeConfig.js +190 -0
- package/src/core/runtimePaths.js +24 -0
- package/src/core/status.js +186 -0
- package/src/core/token/index.js +328 -0
- package/src/core/uninstall.js +246 -0
- package/src/core/validation/confidence.js +89 -0
- package/src/core/validation/index.js +2 -0
- package/src/core/validation/validator.js +165 -0
- package/src/index/buildIndex.js +1392 -0
- package/src/index/gitHooks.js +109 -0
- package/src/index/importResolution.js +377 -0
- package/src/index/languageTools.js +127 -0
- package/src/index/paths.js +27 -0
- package/src/index/queryIndex.js +637 -0
- package/src/index/relatedTests.js +237 -0
- package/src/index/resolveContext.js +345 -0
- package/src/index/routeCatalog.js +258 -0
- package/src/index/taskRouting.js +677 -0
- package/src/index/verificationPlan.js +437 -0
- package/src/manifest/loadManifest.js +22 -0
- package/src/manifest/selectItems.js +78 -0
- package/src/manifest/validateManifest.js +115 -0
- package/src/render/buildVariables.js +39 -0
- package/src/render/renderTemplate.js +44 -0
- package/src/stack/detectStack.js +213 -0
- package/templates/.claude/agents/bug-debugger.md +57 -0
- package/templates/.claude/agents/feature-implementer.md +55 -0
- package/templates/.claude/config/providers.md +25 -0
- package/templates/.claude/hooks/auto-allow-bash.sh +155 -0
- package/templates/.claude/hooks/auto-prune-bash.sh +75 -0
- package/templates/.claude/hooks/block-dangerous.sh +54 -0
- package/templates/.claude/hooks/compress-output.sh +17 -0
- package/templates/.claude/hooks/protect-files.sh +37 -0
- package/templates/.claude/hooks/reinject-context.sh +28 -0
- package/templates/.claude/hooks/session-start.md +13 -0
- package/templates/.claude/hooks/skill-router.sh +1681 -0
- package/templates/.claude/hooks/verification-guard.sh +271 -0
- package/templates/.claude/settings.json +144 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/mce/mc.xsd +75 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/pack.py +159 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/unpack.py +29 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validate.py +69 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/__init__.py +15 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/base.py +951 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/docx.py +274 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/pptx.py +315 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/redlining.py +279 -0
- package/templates/.claude/skills/backend-api/SKILL.md +26 -0
- package/templates/.claude/skills/canvas-design/LICENSE.txt +202 -0
- package/templates/.claude/skills/canvas-design/SKILL.md +130 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- package/templates/.claude/skills/code-review/SKILL.md +97 -0
- package/templates/.claude/skills/debugging-toolkit/SKILL.md +156 -0
- package/templates/.claude/skills/delivery/SKILL.md +92 -0
- package/templates/.claude/skills/discover-security/SKILL.md +86 -0
- package/templates/.claude/skills/docker-packaging/SKILL.md +60 -0
- package/templates/.claude/skills/docs-manager/SKILL.md +465 -0
- package/templates/.claude/skills/docs-manager/init-project-docs.sh +70 -0
- package/templates/.claude/skills/docs-manager/templates/README.md.template +50 -0
- package/templates/.claude/skills/docs-manager/templates/agent-roles.md.template +24 -0
- package/templates/.claude/skills/docs-manager/templates/coding-conventions.md.template +28 -0
- package/templates/.claude/skills/docs-manager/templates/memory.md.template +30 -0
- package/templates/.claude/skills/docs-manager/templates/onboarding.md.template +20 -0
- package/templates/.claude/skills/docs-manager/templates/project.md.template +26 -0
- package/templates/.claude/skills/docs-quality/SKILL.md +148 -0
- package/templates/.claude/skills/docx/LICENSE.txt +30 -0
- package/templates/.claude/skills/docx/SKILL.md +197 -0
- package/templates/.claude/skills/docx/docx-js.md +350 -0
- package/templates/.claude/skills/docx/ooxml.md +610 -0
- package/templates/.claude/skills/docx/scripts/__init__.py +1 -0
- package/templates/.claude/skills/docx/scripts/document.py +1276 -0
- package/templates/.claude/skills/docx/scripts/templates/comments.xml +3 -0
- package/templates/.claude/skills/docx/scripts/templates/commentsExtended.xml +3 -0
- package/templates/.claude/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/templates/.claude/skills/docx/scripts/templates/commentsIds.xml +3 -0
- package/templates/.claude/skills/docx/scripts/templates/people.xml +3 -0
- package/templates/.claude/skills/docx/scripts/utilities.py +374 -0
- package/templates/.claude/skills/duraone/SKILL.md +204 -0
- package/templates/.claude/skills/duraone/references/backend.md +636 -0
- package/templates/.claude/skills/duraone/references/frontend.md +1506 -0
- package/templates/.claude/skills/duraone/references/sql.md +631 -0
- package/templates/.claude/skills/duraone/references/workflow.md +520 -0
- package/templates/.claude/skills/executing-plans/SKILL.md +76 -0
- package/templates/.claude/skills/file-organizer/SKILL.md +433 -0
- package/templates/.claude/skills/frontend/SKILL.md +26 -0
- package/templates/.claude/skills/frontend-design/LICENSE.txt +177 -0
- package/templates/.claude/skills/frontend-design/SKILL.md +42 -0
- package/templates/.claude/skills/frontend-vue/SKILL.md +127 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Box.vue +137 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Button.vue +93 -0
- package/templates/.claude/skills/frontend-vue/components/Control/ButtonBar.vue +29 -0
- package/templates/.claude/skills/frontend-vue/components/Control/ButtonFloat.vue +62 -0
- package/templates/.claude/skills/frontend-vue/components/Control/CheckButton.vue +75 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Checkbox.vue +58 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Datetime.vue +148 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Dropdownlist.vue +156 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Input.vue +106 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Label.vue +38 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Master/BoxColumn.vue +24 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Popup/Confirm.vue +33 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Popup/Info.vue +32 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Popup/ModalInfo.vue +39 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Popup/Reject.vue +64 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Tag.vue +82 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Upload.vue +61 -0
- package/templates/.claude/skills/frontend-vue/components/ControlMobile/Dropdownlist.vue +103 -0
- package/templates/.claude/skills/frontend-vue/components/ControlMobile/PagingBar.vue +108 -0
- package/templates/.claude/skills/frontend-vue/components/ControlMobile/UploadImage.vue +137 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/AG.vue +806 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/AntTable.vue +253 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/CustomDropdownEditor.vue +43 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/CustomDropdownEditorEnable.vue +55 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/HtmlTable.vue +40 -0
- package/templates/.claude/skills/frontend-vue/components/PDFViewer.vue +25 -0
- package/templates/.claude/skills/frontend-vue/components/Panel/FormView.vue +309 -0
- package/templates/.claude/skills/frontend-vue/components/Partial/Footer.vue +23 -0
- package/templates/.claude/skills/frontend-vue/components/Partial/Header.vue +265 -0
- package/templates/.claude/skills/frontend-vue/components/Partial/Sidebar.vue +122 -0
- package/templates/.claude/skills/frontend-vue/components/Template.vue +16 -0
- package/templates/.claude/skills/frontend-vue/components/View/Form.vue +89 -0
- package/templates/.claude/skills/frontend-vue/composables/indexDBStore.js +140 -0
- package/templates/.claude/skills/frontend-vue/composables/masterApi.js +362 -0
- package/templates/.claude/skills/frontend-vue/composables/state.js +578 -0
- package/templates/.claude/skills/frontend-vue/composables/useRequest.js +221 -0
- package/templates/.claude/skills/frontend-vue/composables/useSession.js +179 -0
- package/templates/.claude/skills/frontend-vue/composables/useTranslation.js +54 -0
- package/templates/.claude/skills/frontend-vue/composables/useWebSocket.js +257 -0
- package/templates/.claude/skills/frontend-vue/composables/userObj.js +111 -0
- package/templates/.claude/skills/frontend-vue/composables/utils.js +322 -0
- package/templates/.claude/skills/frontend-vue/reference/composables-example.vue +320 -0
- package/templates/.claude/skills/frontend-vue/reference/form-example.vue +183 -0
- package/templates/.claude/skills/frontend-vue/reference/grid-example.vue +147 -0
- package/templates/.claude/skills/frontend-vue/reference/masterdata-example/[id].vue +106 -0
- package/templates/.claude/skills/frontend-vue/reference/masterdata-example/index.vue +58 -0
- package/templates/.claude/skills/frontend-vue/reference/popup-example.vue +159 -0
- package/templates/.claude/skills/pdf/LICENSE.txt +30 -0
- package/templates/.claude/skills/pdf/SKILL.md +294 -0
- package/templates/.claude/skills/pdf/forms.md +205 -0
- package/templates/.claude/skills/pdf/reference.md +612 -0
- package/templates/.claude/skills/pdf/scripts/check_bounding_boxes.py +70 -0
- package/templates/.claude/skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
- package/templates/.claude/skills/pdf/scripts/check_fillable_fields.py +12 -0
- package/templates/.claude/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
- package/templates/.claude/skills/pdf/scripts/create_validation_image.py +41 -0
- package/templates/.claude/skills/pdf/scripts/extract_form_field_info.py +152 -0
- package/templates/.claude/skills/pdf/scripts/fill_fillable_fields.py +114 -0
- package/templates/.claude/skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
- package/templates/.claude/skills/pdf-processing/SKILL.md +107 -0
- package/templates/.claude/skills/pdf-processing-pro/FORMS.md +610 -0
- package/templates/.claude/skills/pdf-processing-pro/OCR.md +137 -0
- package/templates/.claude/skills/pdf-processing-pro/SKILL.md +296 -0
- package/templates/.claude/skills/pdf-processing-pro/TABLES.md +626 -0
- package/templates/.claude/skills/pdf-processing-pro/scripts/analyze_form.py +307 -0
- package/templates/.claude/skills/postgres/SKILL.md +69 -0
- package/templates/.claude/skills/postgres/reference/fn_get_examples.sql +208 -0
- package/templates/.claude/skills/postgres/reference/fn_rpt_examples.sql +239 -0
- package/templates/.claude/skills/postgres/reference/utility_functions.sql +94 -0
- package/templates/.claude/skills/pptx/LICENSE.txt +30 -0
- package/templates/.claude/skills/pptx/SKILL.md +484 -0
- package/templates/.claude/skills/pptx/html2pptx.md +625 -0
- package/templates/.claude/skills/pptx/ooxml.md +427 -0
- package/templates/.claude/skills/pptx/scripts/html2pptx.js +979 -0
- package/templates/.claude/skills/pptx/scripts/inventory.py +1020 -0
- package/templates/.claude/skills/pptx/scripts/rearrange.py +231 -0
- package/templates/.claude/skills/pptx/scripts/replace.py +385 -0
- package/templates/.claude/skills/pptx/scripts/thumbnail.py +450 -0
- package/templates/.claude/skills/repo-maintenance/SKILL.md +97 -0
- package/templates/.claude/skills/research/EXAMPLES.md +434 -0
- package/templates/.claude/skills/research/REFERENCE.md +399 -0
- package/templates/.claude/skills/research/SKILL.md +136 -0
- package/templates/.claude/skills/root-cause-tracing/SKILL.md +174 -0
- package/templates/.claude/skills/root-cause-tracing/find-polluter.sh +63 -0
- package/templates/.claude/skills/sharing-skills/SKILL.md +194 -0
- package/templates/.claude/skills/sql-optimization-patterns/SKILL.md +493 -0
- package/templates/.claude/skills/subagent-driven-development/SKILL.md +189 -0
- package/templates/.claude/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/templates/.claude/skills/systematic-debugging/SKILL.md +295 -0
- package/templates/.claude/skills/systematic-debugging/test-academic.md +14 -0
- package/templates/.claude/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/templates/.claude/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/templates/.claude/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/templates/.claude/skills/test-driven-development/SKILL.md +364 -0
- package/templates/.claude/skills/testing-anti-patterns/SKILL.md +302 -0
- package/templates/.claude/skills/testing-quality/SKILL.md +97 -0
- package/templates/.claude/skills/verification-before-completion/SKILL.md +139 -0
- package/templates/.claude/skills/webapp-testing/LICENSE.txt +202 -0
- package/templates/.claude/skills/webapp-testing/SKILL.md +96 -0
- package/templates/.claude/skills/webapp-testing/examples/console_logging.py +35 -0
- package/templates/.claude/skills/webapp-testing/examples/element_discovery.py +40 -0
- package/templates/.claude/skills/webapp-testing/examples/static_html_automation.py +33 -0
- package/templates/.claude/skills/webapp-testing/scripts/with_server.py +106 -0
- package/templates/.claude/ukit/index/build-index.mjs +28 -0
- package/templates/.claude/ukit/index/cache-utils.mjs +140 -0
- package/templates/.claude/ukit/index/lib/index-core.mjs +2800 -0
- package/templates/.claude/ukit/index/query-index.mjs +150 -0
- package/templates/.claude/ukit/index/refresh-index.mjs +57 -0
- package/templates/.claude/ukit/index/reset-auto-permissions.mjs +76 -0
- package/templates/.claude/ukit/index/resolve-context.mjs +279 -0
- package/templates/.claude/ukit/index/route-catalog.mjs +258 -0
- package/templates/.claude/ukit/index/route-task.mjs +1994 -0
- package/templates/.claude/ukit/index/triage.mjs +133 -0
- package/templates/.claude/ukit/index/verify-context.mjs +689 -0
- package/templates/.claude/ukit/runtime/compact-threshold.mjs +1013 -0
- package/templates/.claude/ukit/runtime/output-compression.mjs +1340 -0
- package/templates/.claude/ukit/runtime/reinject-context.mjs +874 -0
- package/templates/.claude/ukit/runtime/token-utils.mjs +500 -0
- package/templates/.codex/README.md +83 -0
- package/templates/.codex/settings.json +187 -0
- package/templates/.gitignore +75 -0
- package/templates/AGENTS.md +116 -0
- package/templates/CLAUDE.md +93 -0
- package/templates/adapter-presets/antigravity/README.md +22 -0
- package/templates/adapter-presets/antigravity/rules.md +49 -0
- package/templates/adapter-presets/claude/settings.local.json +42 -0
- package/templates/adapter-presets/codex/settings.local.json +6 -0
- package/templates/adapter-presets/opencode/opencode.template.json +1 -0
- package/templates/docs/BUGFIX.md +20 -0
- package/templates/docs/BUG_INDEX.md +12 -0
- package/templates/docs/BUG_METRICS.md +7 -0
- package/templates/docs/BUG_TEMPLATE.md +13 -0
- package/templates/docs/CODE_MAP.md +35 -0
- package/templates/docs/INSTALL.md +113 -0
- package/templates/docs/MEMORY.md +49 -0
- package/templates/docs/PROJECT.md +50 -0
- package/templates/docs/UKIT_USAGE_GUIDE.md +147 -0
- package/templates/docs/WORKLOG.md +10 -0
- package/templates/ukit/README.md +14 -0
- package/templates/ukit/storage/cache/compact-history.json +3 -0
- package/templates/ukit/storage/cache/compact-pressure.json +1 -0
- package/templates/ukit/storage/cache/output-history.json +3 -0
- package/templates/ukit/storage/cache/prompt-cache.json +3 -0
- package/templates/ukit/storage/config.json +37 -0
- package/templates/ukit/storage/memory/projects/.gitkeep +2 -0
- package/templates/ukit/storage/memory/sessions/.gitkeep +0 -0
- package/templates/ukit/storage/memory/user.json +5 -0
|
@@ -0,0 +1,631 @@
|
|
|
1
|
+
# DuraOne SQL Reference
|
|
2
|
+
## PostgreSQL — Views, Functions, Stored Procedures
|
|
3
|
+
|
|
4
|
+
> Nguồn sự thật cho phong cách viết SQL của LeNK.
|
|
5
|
+
> Database: PostgreSQL với 2 schema: `qas` (test) và `prd` (production)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## MỤC LỤC
|
|
10
|
+
1. [Schema Organization](#1-schema-organization)
|
|
11
|
+
2. [Data Types — Quy Tắc Bắt Buộc](#2-data-types)
|
|
12
|
+
3. [Naming Conventions](#3-naming-conventions)
|
|
13
|
+
4. [View Pattern (v_)](#4-view-pattern)
|
|
14
|
+
5. [Function Pattern (fn_)](#5-function-pattern)
|
|
15
|
+
6. [Stored Procedure Pattern (sp_)](#6-stored-procedure-pattern)
|
|
16
|
+
7. [Table Design Conventions](#7-table-design-conventions)
|
|
17
|
+
8. [Common SQL Patterns](#8-common-sql-patterns)
|
|
18
|
+
9. [File Organization](#9-file-organization)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 1. Schema Organization
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
PostgreSQL Database: duraone
|
|
26
|
+
├── qas (schema — QA/Testing)
|
|
27
|
+
│ ├── Tables
|
|
28
|
+
│ ├── Views: v_*
|
|
29
|
+
│ ├── Functions: fn_*
|
|
30
|
+
│ └── Procedures: sp_*
|
|
31
|
+
│
|
|
32
|
+
└── prd (schema — Production)
|
|
33
|
+
├── Tables (mirrors qas)
|
|
34
|
+
├── Views: v_*
|
|
35
|
+
├── Functions: fn_*
|
|
36
|
+
└── Procedures: sp_*
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Quy tắc:**
|
|
40
|
+
- Tất cả SQL objects LUÔN có schema prefix: `qas.` hoặc `prd.`
|
|
41
|
+
- Không viết SQL mà không có schema prefix
|
|
42
|
+
- Khi deploy, chạy SQL trên cả 2 schema (qas trước, prd sau)
|
|
43
|
+
- View/Function/Procedure trong qas và prd có cùng tên, chỉ khác schema prefix
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 2. Data Types — QUY TẮC BẮT BUỘC
|
|
48
|
+
|
|
49
|
+
**CHỈ dùng 3 data type này. KHÔNG dùng bất kỳ loại nào khác:**
|
|
50
|
+
|
|
51
|
+
| Type | Khi nào dùng | Default |
|
|
52
|
+
|------|-------------|---------|
|
|
53
|
+
| `varchar` | Text, ngày tháng, UUID, enum, mọi thứ dạng chuỗi | `default ''` |
|
|
54
|
+
| `numeric` | Số (integer, decimal, float, quantity) | `default 0` |
|
|
55
|
+
| `boolean` | True/false flags | `default false` |
|
|
56
|
+
|
|
57
|
+
**KHÔNG ĐƯỢC dùng:**
|
|
58
|
+
- ❌ `integer`, `int`, `bigint`, `serial` — dùng `numeric` thay thế
|
|
59
|
+
- ❌ `date`, `timestamp`, `timestamptz`, `datetime` — dùng `varchar` với format string
|
|
60
|
+
- ❌ `text` — dùng `varchar`
|
|
61
|
+
- ❌ `jsonb`, `json` — dùng `varchar` chứa JSON string
|
|
62
|
+
- ❌ `uuid` — dùng `varchar` với UUID generator default
|
|
63
|
+
- ❌ `NULL` — LUÔN có default value: `''` cho varchar, `0` cho numeric, `false` cho boolean
|
|
64
|
+
|
|
65
|
+
**Ngày tháng lưu dạng varchar:**
|
|
66
|
+
```sql
|
|
67
|
+
-- created_at: varchar với timezone Asia/Ho_Chi_Minh
|
|
68
|
+
created_at varchar default TO_CHAR(date_trunc('second', now() AT TIME ZONE 'Asia/Ho_Chi_Minh'),
|
|
69
|
+
'YYYY-MM-DD HH24:MI:SS')::character varying
|
|
70
|
+
-- → lưu thành string "2024-01-15 10:30:00"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 3. Naming Conventions
|
|
76
|
+
|
|
77
|
+
| Loại Object | Prefix | Ví dụ |
|
|
78
|
+
|------------|--------|-------|
|
|
79
|
+
| View | `v_` | `v_agreement`, `v_clearance_request` |
|
|
80
|
+
| Function | `fn_` | `fn_get_agreement`, `fn_get_review_list` |
|
|
81
|
+
| Stored Procedure | `sp_` | `sp_generate_running_no`, `sp_after_approve` |
|
|
82
|
+
| Table | snake_case | `agreement`, `clearance_request`, `user` |
|
|
83
|
+
| Global Function | `glb_fn_` | `glb_fn_convert_query_to_json` |
|
|
84
|
+
| Column | snake_case | `id_agreement`, `created_at`, `is_active` |
|
|
85
|
+
| ID Column | `id_` prefix | `id_agreement`, `id_user`, `id_type` |
|
|
86
|
+
| Boolean Column | `is_`/`can_`/`has_` | `is_active`, `can_approve`, `has_file` |
|
|
87
|
+
|
|
88
|
+
**File naming (SQL files):**
|
|
89
|
+
```
|
|
90
|
+
mainapp/SQL/duraone/qas/
|
|
91
|
+
├── view/
|
|
92
|
+
│ └── v_agreement.sql
|
|
93
|
+
├── function/
|
|
94
|
+
│ └── fn_get_agreement.sql
|
|
95
|
+
└── store/
|
|
96
|
+
└── sp_generate_running_no.sql
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 4. View Pattern (v_)
|
|
102
|
+
|
|
103
|
+
View là layer chính để FE đọc data — luôn dùng view thay vì query raw table.
|
|
104
|
+
|
|
105
|
+
```sql
|
|
106
|
+
-- ──────────────────────────────────────────────
|
|
107
|
+
-- TEMPLATE: View cơ bản
|
|
108
|
+
-- ──────────────────────────────────────────────
|
|
109
|
+
CREATE OR REPLACE VIEW qas.v_agreement AS
|
|
110
|
+
SELECT
|
|
111
|
+
-- Primary key
|
|
112
|
+
a.id_agreement,
|
|
113
|
+
|
|
114
|
+
-- Core fields
|
|
115
|
+
a.agreement_number,
|
|
116
|
+
a.status,
|
|
117
|
+
|
|
118
|
+
-- Date fields — substring để lấy date part
|
|
119
|
+
a.created_at,
|
|
120
|
+
SUBSTRING(a.created_at::text, 1, 10) AS created_date,
|
|
121
|
+
|
|
122
|
+
-- Computed numeric — LUÔN COALESCE để tránh null
|
|
123
|
+
COALESCE(a.amount, 0)::numeric(16, 2) AS amount,
|
|
124
|
+
COALESCE(a.discount, 0)::numeric(16, 2) AS discount,
|
|
125
|
+
COALESCE(a.amount, 0) - COALESCE(a.discount, 0) AS net_amount,
|
|
126
|
+
|
|
127
|
+
-- Boolean flags — computed từ business logic
|
|
128
|
+
CASE WHEN a.status IN ('draft', 'rejected') THEN TRUE ELSE FALSE END AS can_edit,
|
|
129
|
+
CASE WHEN a.status = 'approved' THEN TRUE ELSE FALSE END AS is_locked,
|
|
130
|
+
FALSE AS can_delete,
|
|
131
|
+
|
|
132
|
+
-- Joined fields
|
|
133
|
+
b.branch_name,
|
|
134
|
+
u.fullname AS created_by_name,
|
|
135
|
+
|
|
136
|
+
-- JSON aggregation cho nested data
|
|
137
|
+
COALESCE(
|
|
138
|
+
(SELECT json_agg(json_build_object(
|
|
139
|
+
'id_media', m.id_media,
|
|
140
|
+
'media_name', m.media_name,
|
|
141
|
+
'amount', COALESCE(m.amount, 0)
|
|
142
|
+
))
|
|
143
|
+
FROM qas.agreement_media m
|
|
144
|
+
WHERE m.id_agreement = a.id_agreement),
|
|
145
|
+
'[]'::json
|
|
146
|
+
) AS media_list,
|
|
147
|
+
|
|
148
|
+
-- Count
|
|
149
|
+
(SELECT COUNT(*) FROM qas.agreement_media m
|
|
150
|
+
WHERE m.id_agreement = a.id_agreement) AS media_count
|
|
151
|
+
|
|
152
|
+
FROM qas.agreement a
|
|
153
|
+
LEFT JOIN qas.branch b ON b.id_branch = a.id_branch
|
|
154
|
+
LEFT JOIN qas.user u ON u.username = a.created_by
|
|
155
|
+
WHERE a.is_deleted = FALSE -- soft delete pattern
|
|
156
|
+
ORDER BY a.created_at DESC;
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Conventions trong View:**
|
|
160
|
+
```sql
|
|
161
|
+
-- ✅ LUÔN COALESCE numeric
|
|
162
|
+
COALESCE(field, 0)::numeric(16, 2)
|
|
163
|
+
|
|
164
|
+
-- ✅ LUÔN có boolean flags
|
|
165
|
+
TRUE AS can_edit,
|
|
166
|
+
FALSE AS can_delete,
|
|
167
|
+
CASE WHEN status = 'approved' THEN TRUE ELSE FALSE END AS is_approved,
|
|
168
|
+
|
|
169
|
+
-- ✅ Date format
|
|
170
|
+
SUBSTRING(created_at::text, 1, 10) AS created_date -- YYYY-MM-DD
|
|
171
|
+
|
|
172
|
+
-- ✅ NULL-safe string concat
|
|
173
|
+
COALESCE(first_name, '') || ' ' || COALESCE(last_name, '') AS full_name
|
|
174
|
+
|
|
175
|
+
-- ✅ Soft delete filter trong view
|
|
176
|
+
WHERE is_deleted = FALSE
|
|
177
|
+
|
|
178
|
+
-- ✅ JSON array cho 1-to-many
|
|
179
|
+
COALESCE(json_agg(...) FILTER (WHERE id IS NOT NULL), '[]'::json) AS items
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 5. Function Pattern (fn_)
|
|
185
|
+
|
|
186
|
+
Function dùng khi cần filter phức tạp hoặc business logic:
|
|
187
|
+
|
|
188
|
+
```sql
|
|
189
|
+
-- ──────────────────────────────────────────────
|
|
190
|
+
-- TEMPLATE: Function trả về SETOF view
|
|
191
|
+
-- ──────────────────────────────────────────────
|
|
192
|
+
CREATE OR REPLACE FUNCTION qas.fn_get_agreement(
|
|
193
|
+
_username VARCHAR DEFAULT NULL,
|
|
194
|
+
_from_date DATE DEFAULT NULL,
|
|
195
|
+
_to_date DATE DEFAULT NULL,
|
|
196
|
+
_status VARCHAR DEFAULT NULL
|
|
197
|
+
)
|
|
198
|
+
RETURNS SETOF qas.v_agreement AS
|
|
199
|
+
$$
|
|
200
|
+
DECLARE
|
|
201
|
+
v_query TEXT;
|
|
202
|
+
v_conditions TEXT := 'WHERE TRUE';
|
|
203
|
+
BEGIN
|
|
204
|
+
-- Build dynamic conditions
|
|
205
|
+
IF _username IS NOT NULL AND _username <> '' THEN
|
|
206
|
+
v_conditions := v_conditions || format(' AND created_by = %L', _username);
|
|
207
|
+
END IF;
|
|
208
|
+
|
|
209
|
+
IF _from_date IS NOT NULL THEN
|
|
210
|
+
v_conditions := v_conditions || format(' AND created_date >= %L', _from_date);
|
|
211
|
+
END IF;
|
|
212
|
+
|
|
213
|
+
IF _to_date IS NOT NULL THEN
|
|
214
|
+
v_conditions := v_conditions || format(' AND created_date <= %L', _to_date);
|
|
215
|
+
END IF;
|
|
216
|
+
|
|
217
|
+
IF _status IS NOT NULL AND _status <> '' THEN
|
|
218
|
+
v_conditions := v_conditions || format(' AND status = %L', _status);
|
|
219
|
+
END IF;
|
|
220
|
+
|
|
221
|
+
v_query := 'SELECT * FROM qas.v_agreement ' || v_conditions || ' ORDER BY created_at DESC';
|
|
222
|
+
|
|
223
|
+
RETURN QUERY EXECUTE v_query;
|
|
224
|
+
END;
|
|
225
|
+
$$ LANGUAGE plpgsql;
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
-- ──────────────────────────────────────────────
|
|
229
|
+
-- TEMPLATE: Function trả về SETOF TABLE (custom shape)
|
|
230
|
+
-- ──────────────────────────────────────────────
|
|
231
|
+
CREATE OR REPLACE FUNCTION qas.fn_get_summary_by_branch(
|
|
232
|
+
_from_date VARCHAR,
|
|
233
|
+
_to_date VARCHAR
|
|
234
|
+
)
|
|
235
|
+
RETURNS TABLE(
|
|
236
|
+
id_branch VARCHAR,
|
|
237
|
+
branch_name VARCHAR,
|
|
238
|
+
total_amount NUMERIC(16, 2),
|
|
239
|
+
total_count NUMERIC
|
|
240
|
+
) AS
|
|
241
|
+
$$
|
|
242
|
+
BEGIN
|
|
243
|
+
RETURN QUERY
|
|
244
|
+
SELECT
|
|
245
|
+
b.id_branch,
|
|
246
|
+
b.branch_name,
|
|
247
|
+
COALESCE(SUM(a.amount), 0)::numeric(16, 2) AS total_amount,
|
|
248
|
+
COUNT(a.id_agreement)::numeric AS total_count
|
|
249
|
+
FROM qas.branch b
|
|
250
|
+
LEFT JOIN qas.agreement a
|
|
251
|
+
ON a.id_branch = b.id_branch
|
|
252
|
+
AND a.created_date BETWEEN _from_date AND _to_date
|
|
253
|
+
AND a.is_deleted = FALSE
|
|
254
|
+
GROUP BY b.id_branch, b.branch_name
|
|
255
|
+
ORDER BY b.branch_name;
|
|
256
|
+
END;
|
|
257
|
+
$$ LANGUAGE plpgsql;
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Conventions trong Function:**
|
|
261
|
+
```sql
|
|
262
|
+
-- ✅ Parameter prefix _
|
|
263
|
+
_username VARCHAR
|
|
264
|
+
|
|
265
|
+
-- ✅ Variable prefix v_
|
|
266
|
+
v_query TEXT;
|
|
267
|
+
v_count NUMERIC;
|
|
268
|
+
|
|
269
|
+
-- ✅ Default NULL cho optional params
|
|
270
|
+
_status VARCHAR DEFAULT NULL
|
|
271
|
+
|
|
272
|
+
-- ✅ Guard với IS NOT NULL AND <> ''
|
|
273
|
+
IF _param IS NOT NULL AND _param <> '' THEN
|
|
274
|
+
|
|
275
|
+
-- ✅ format() cho dynamic SQL (SQL injection safe)
|
|
276
|
+
format(' AND field = %L', _value)
|
|
277
|
+
format(' AND id = %s', _id::text)
|
|
278
|
+
|
|
279
|
+
-- ✅ RETURN QUERY EXECUTE cho dynamic
|
|
280
|
+
RETURN QUERY EXECUTE v_query;
|
|
281
|
+
|
|
282
|
+
-- ✅ RETURN QUERY cho static
|
|
283
|
+
RETURN QUERY SELECT ... FROM ...;
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## 6. Stored Procedure Pattern (sp_)
|
|
289
|
+
|
|
290
|
+
Dùng cho business operations (running numbers, audit logs, cascade updates):
|
|
291
|
+
|
|
292
|
+
```sql
|
|
293
|
+
-- ──────────────────────────────────────────────
|
|
294
|
+
-- TEMPLATE: Generate running number
|
|
295
|
+
-- ──────────────────────────────────────────────
|
|
296
|
+
CREATE OR REPLACE FUNCTION qas.sp_generate_running_no(
|
|
297
|
+
_prefix VARCHAR,
|
|
298
|
+
_year NUMERIC DEFAULT EXTRACT(YEAR FROM NOW())::NUMERIC
|
|
299
|
+
)
|
|
300
|
+
RETURNS VARCHAR AS
|
|
301
|
+
$$
|
|
302
|
+
DECLARE
|
|
303
|
+
v_running_no NUMERIC;
|
|
304
|
+
v_result VARCHAR;
|
|
305
|
+
BEGIN
|
|
306
|
+
-- Lock table row để tránh concurrent issues
|
|
307
|
+
SELECT COALESCE(MAX(seq_no), 0) + 1
|
|
308
|
+
INTO v_running_no
|
|
309
|
+
FROM qas.running_number
|
|
310
|
+
WHERE prefix = _prefix
|
|
311
|
+
AND year = _year
|
|
312
|
+
FOR UPDATE;
|
|
313
|
+
|
|
314
|
+
-- Insert hoặc update sequence
|
|
315
|
+
INSERT INTO qas.running_number (prefix, year, seq_no)
|
|
316
|
+
VALUES (_prefix, _year, v_running_no)
|
|
317
|
+
ON CONFLICT (prefix, year)
|
|
318
|
+
DO UPDATE SET seq_no = v_running_no;
|
|
319
|
+
|
|
320
|
+
-- Format: PREFIX-YYYY-XXXXX
|
|
321
|
+
v_result := _prefix || '-' || _year::TEXT || '-' || LPAD(v_running_no::TEXT, 5, '0');
|
|
322
|
+
|
|
323
|
+
RETURN v_result;
|
|
324
|
+
END;
|
|
325
|
+
$$ LANGUAGE plpgsql;
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
-- ──────────────────────────────────────────────
|
|
329
|
+
-- TEMPLATE: After-approve procedure
|
|
330
|
+
-- ──────────────────────────────────────────────
|
|
331
|
+
CREATE OR REPLACE FUNCTION qas.sp_after_approve(
|
|
332
|
+
_id_agreement VARCHAR
|
|
333
|
+
)
|
|
334
|
+
RETURNS JSON AS
|
|
335
|
+
$$
|
|
336
|
+
DECLARE
|
|
337
|
+
v_agreement RECORD;
|
|
338
|
+
v_result JSON;
|
|
339
|
+
BEGIN
|
|
340
|
+
-- Get agreement data
|
|
341
|
+
SELECT * INTO v_agreement
|
|
342
|
+
FROM qas.agreement
|
|
343
|
+
WHERE id_agreement = _id_agreement;
|
|
344
|
+
|
|
345
|
+
IF NOT FOUND THEN
|
|
346
|
+
RETURN json_build_object('success', false, 'message', 'Agreement not found');
|
|
347
|
+
END IF;
|
|
348
|
+
|
|
349
|
+
-- Update related records
|
|
350
|
+
UPDATE qas.agreement_media
|
|
351
|
+
SET status = 'confirmed',
|
|
352
|
+
confirmed_at = NOW()
|
|
353
|
+
WHERE id_agreement = _id_agreement;
|
|
354
|
+
|
|
355
|
+
-- Create audit log
|
|
356
|
+
INSERT INTO qas.audit_log (
|
|
357
|
+
table_name, record_id, action, changed_at
|
|
358
|
+
) VALUES (
|
|
359
|
+
'agreement', _id_agreement, 'approved', NOW()
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
RETURN json_build_object('success', true, 'id_agreement', _id_agreement);
|
|
363
|
+
|
|
364
|
+
EXCEPTION WHEN OTHERS THEN
|
|
365
|
+
RETURN json_build_object('success', false, 'message', SQLERRM);
|
|
366
|
+
END;
|
|
367
|
+
$$ LANGUAGE plpgsql;
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## 7. Table Design Conventions
|
|
373
|
+
|
|
374
|
+
```sql
|
|
375
|
+
-- ──────────────────────────────────────────────
|
|
376
|
+
-- TEMPLATE: Standard table
|
|
377
|
+
-- Rules: chỉ varchar/numeric/boolean, không NULL
|
|
378
|
+
-- ──────────────────────────────────────────────
|
|
379
|
+
create table qas.agreement
|
|
380
|
+
(
|
|
381
|
+
-- Primary Key: uuid varchar
|
|
382
|
+
id_agreement varchar default uuid_in(overlay(
|
|
383
|
+
overlay(md5(random()::text || ':' || random()::text) placing '4' from 13)
|
|
384
|
+
placing to_hex(floor(random() * (11 - 8 + 1) + 8)::int)::text from 17)::cstring)
|
|
385
|
+
constraint agreement_pkey primary key,
|
|
386
|
+
|
|
387
|
+
-- Business fields — LUÔN có default
|
|
388
|
+
agreement_number varchar default '',
|
|
389
|
+
status varchar default 'draft',
|
|
390
|
+
amount numeric default 0,
|
|
391
|
+
note varchar default '',
|
|
392
|
+
|
|
393
|
+
-- Foreign keys: id_ prefix (varchar)
|
|
394
|
+
id_branch varchar default '' references qas.branch (id_branch),
|
|
395
|
+
id_type varchar default '' references qas.agreement_type (id_type),
|
|
396
|
+
|
|
397
|
+
-- Data phụ (JSON string dạng varchar)
|
|
398
|
+
extra_data varchar default '',
|
|
399
|
+
|
|
400
|
+
-- Boolean flags: is_ prefix
|
|
401
|
+
is_active boolean default true,
|
|
402
|
+
is_deleted boolean default false,
|
|
403
|
+
|
|
404
|
+
-- Audit fields — varchar timezone VN
|
|
405
|
+
created_by varchar default '',
|
|
406
|
+
created_at varchar default TO_CHAR(date_trunc('second', now() AT TIME ZONE 'Asia/Ho_Chi_Minh'),
|
|
407
|
+
'YYYY-MM-DD HH24:MI:SS')::character varying,
|
|
408
|
+
updated_by varchar default '',
|
|
409
|
+
updated_at varchar default TO_CHAR(date_trunc('second', now() AT TIME ZONE 'Asia/Ho_Chi_Minh'),
|
|
410
|
+
'YYYY-MM-DD HH24:MI:SS')::character varying
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
create index if not exists idx_agreement_status on qas.agreement (status);
|
|
414
|
+
create index if not exists idx_agreement_branch on qas.agreement (id_branch);
|
|
415
|
+
create index if not exists idx_agreement_created on qas.agreement (created_at);
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
**UUID Generator Pattern — dùng cho mọi table:**
|
|
419
|
+
```sql
|
|
420
|
+
-- Macro UUID (copy nguyên cụm này cho mỗi PK mới)
|
|
421
|
+
id_<table_name> varchar default uuid_in(overlay(
|
|
422
|
+
overlay(md5(random()::text || ':' || random()::text) placing '4' from 13) placing
|
|
423
|
+
to_hex(floor(random() * (11 - 8 + 1) + 8)::int)::text from 17)::cstring)
|
|
424
|
+
constraint <table_name>_pkey primary key
|
|
425
|
+
|
|
426
|
+
-- Ví dụ:
|
|
427
|
+
id_user varchar default uuid_in(overlay(
|
|
428
|
+
overlay(md5(random()::text || ':' || random()::text) placing '4' from 13) placing
|
|
429
|
+
to_hex(floor(random() * (11 - 8 + 1) + 8)::int)::text from 17)::cstring)
|
|
430
|
+
constraint user_pkey primary key,
|
|
431
|
+
|
|
432
|
+
id_branch varchar default uuid_in(overlay(
|
|
433
|
+
overlay(md5(random()::text || ':' || random()::text) placing '4' from 13) placing
|
|
434
|
+
to_hex(floor(random() * (11 - 8 + 1) + 8)::int)::text from 17)::cstring)
|
|
435
|
+
constraint branch_pkey primary key,
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
**Audit fields LUÔN có trong mọi table — varchar, timezone VN:**
|
|
439
|
+
```sql
|
|
440
|
+
created_by varchar default '',
|
|
441
|
+
created_at varchar default TO_CHAR(date_trunc('second', now() AT TIME ZONE 'Asia/Ho_Chi_Minh'),
|
|
442
|
+
'YYYY-MM-DD HH24:MI:SS')::character varying,
|
|
443
|
+
updated_by varchar default '',
|
|
444
|
+
updated_at varchar default TO_CHAR(date_trunc('second', now() AT TIME ZONE 'Asia/Ho_Chi_Minh'),
|
|
445
|
+
'YYYY-MM-DD HH24:MI:SS')::character varying
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
**Full Table Template với tất cả conventions:**
|
|
449
|
+
```sql
|
|
450
|
+
create table prd.table_name
|
|
451
|
+
(
|
|
452
|
+
id_table_name varchar default uuid_in(overlay(
|
|
453
|
+
overlay(md5(random()::text || ':' || random()::text) placing '4' from 13) placing
|
|
454
|
+
to_hex(floor(random() * (11 - 8 + 1) + 8)::int)::text from 17)::cstring)
|
|
455
|
+
constraint table_name_pkey primary key,
|
|
456
|
+
|
|
457
|
+
-- business fields — LUÔN plain varchar/numeric/boolean, LUÔN có default
|
|
458
|
+
field_name varchar default '',
|
|
459
|
+
amount numeric default 0,
|
|
460
|
+
status varchar default 'draft',
|
|
461
|
+
is_active boolean default true,
|
|
462
|
+
is_deleted boolean default false,
|
|
463
|
+
|
|
464
|
+
-- foreign keys (varchar UUID, default '')
|
|
465
|
+
id_parent varchar default '' references prd.parent_table (id_parent),
|
|
466
|
+
|
|
467
|
+
-- audit fields
|
|
468
|
+
created_by varchar default '',
|
|
469
|
+
created_at varchar default TO_CHAR(date_trunc('second', now() AT TIME ZONE 'Asia/Ho_Chi_Minh'),
|
|
470
|
+
'YYYY-MM-DD HH24:MI:SS')::character varying,
|
|
471
|
+
updated_by varchar default '',
|
|
472
|
+
updated_at varchar default TO_CHAR(date_trunc('second', now() AT TIME ZONE 'Asia/Ho_Chi_Minh'),
|
|
473
|
+
'YYYY-MM-DD HH24:MI:SS')::character varying
|
|
474
|
+
);
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
> ⚠️ **Lưu ý `updated_at`:** `DEFAULT` chỉ chạy khi `INSERT`. Khi `UPDATE`, backend phải tự set tường minh:
|
|
478
|
+
> ```sql
|
|
479
|
+
> updated_at = TO_CHAR(NOW() AT TIME ZONE 'Asia/Ho_Chi_Minh', 'YYYY-MM-DD HH24:MI:SS'),
|
|
480
|
+
> updated_by = _username
|
|
481
|
+
> ```
|
|
482
|
+
> Hoặc dùng `/api/save` generic endpoint — endpoint này tự inject `updated_at` / `updated_by` vào mọi UPDATE.
|
|
483
|
+
|
|
484
|
+
---
|
|
485
|
+
|
|
486
|
+
## 8. Common SQL Patterns
|
|
487
|
+
|
|
488
|
+
### JSON Aggregation
|
|
489
|
+
```sql
|
|
490
|
+
-- Array of objects
|
|
491
|
+
json_agg(json_build_object(
|
|
492
|
+
'id', m.id_media,
|
|
493
|
+
'name', m.media_name,
|
|
494
|
+
'amount', COALESCE(m.amount, 0)
|
|
495
|
+
)) AS media_list
|
|
496
|
+
|
|
497
|
+
-- Null-safe array
|
|
498
|
+
COALESCE(
|
|
499
|
+
json_agg(obj) FILTER (WHERE obj IS NOT NULL),
|
|
500
|
+
'[]'::json
|
|
501
|
+
) AS items
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
### Date Calculations
|
|
505
|
+
|
|
506
|
+
> ⚠️ DuraOne lưu ngày tháng dạng **varchar** (`'2024-01-15'` hoặc `'2024-01-15 10:30:00'`).
|
|
507
|
+
> Khi dùng date functions của PostgreSQL, cần cast sang `DATE` hoặc `TIMESTAMP` trước.
|
|
508
|
+
|
|
509
|
+
```sql
|
|
510
|
+
-- Lưu ý: cast varchar → DATE trước khi dùng date functions
|
|
511
|
+
-- age()
|
|
512
|
+
EXTRACT(YEAR FROM age(end_date::DATE, start_date::DATE)) AS years
|
|
513
|
+
EXTRACT(MONTH FROM age(end_date::DATE, start_date::DATE)) AS months
|
|
514
|
+
|
|
515
|
+
-- Date truncation
|
|
516
|
+
DATE_TRUNC('month', created_at::TIMESTAMP) AS month_start
|
|
517
|
+
|
|
518
|
+
-- Date comparison — cast cả 2 vế
|
|
519
|
+
created_at::DATE BETWEEN _from_date::DATE AND _to_date::DATE
|
|
520
|
+
|
|
521
|
+
-- Hoặc dùng SUBSTRING (không cần cast — đơn giản hơn khi chỉ so sánh YYYY-MM-DD)
|
|
522
|
+
SUBSTRING(created_at, 1, 10) BETWEEN _from_date AND _to_date
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
### Conditional Aggregation
|
|
526
|
+
```sql
|
|
527
|
+
-- Sum with filter
|
|
528
|
+
SUM(amount) FILTER (WHERE status = 'approved') AS approved_amount
|
|
529
|
+
COUNT(*) FILTER (WHERE is_active = TRUE) AS active_count
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### CTEs (Common Table Expressions)
|
|
533
|
+
```sql
|
|
534
|
+
WITH monthly_data AS (
|
|
535
|
+
SELECT
|
|
536
|
+
DATE_TRUNC('month', created_at) AS month,
|
|
537
|
+
SUM(amount) AS total
|
|
538
|
+
FROM qas.agreement
|
|
539
|
+
WHERE is_deleted = FALSE
|
|
540
|
+
GROUP BY 1
|
|
541
|
+
),
|
|
542
|
+
cumulative AS (
|
|
543
|
+
SELECT
|
|
544
|
+
month,
|
|
545
|
+
total,
|
|
546
|
+
SUM(total) OVER (ORDER BY month) AS running_total
|
|
547
|
+
FROM monthly_data
|
|
548
|
+
)
|
|
549
|
+
SELECT * FROM cumulative ORDER BY month;
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### Window Functions
|
|
553
|
+
```sql
|
|
554
|
+
-- Rank/Row Number
|
|
555
|
+
ROW_NUMBER() OVER (PARTITION BY id_branch ORDER BY created_at DESC) AS row_num
|
|
556
|
+
RANK() OVER (ORDER BY amount DESC) AS rank
|
|
557
|
+
|
|
558
|
+
-- Running totals
|
|
559
|
+
SUM(amount) OVER (ORDER BY created_at) AS running_total
|
|
560
|
+
LAG(amount, 1) OVER (ORDER BY created_at) AS prev_amount
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### String Operations
|
|
564
|
+
```sql
|
|
565
|
+
-- Concat with null safety
|
|
566
|
+
COALESCE(first_name, '') || ' ' || COALESCE(last_name, '') AS full_name
|
|
567
|
+
|
|
568
|
+
-- Format number
|
|
569
|
+
TO_CHAR(amount, 'FM999,999,999.00') AS amount_formatted
|
|
570
|
+
|
|
571
|
+
-- String array
|
|
572
|
+
string_agg(tag_name, ', ' ORDER BY tag_name) AS tags
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Type Casting
|
|
576
|
+
```sql
|
|
577
|
+
-- Numeric với precision
|
|
578
|
+
COALESCE(field, 0)::numeric(16, 2)
|
|
579
|
+
|
|
580
|
+
-- Date extraction
|
|
581
|
+
SUBSTRING(created_at::text, 1, 10) -- → 'YYYY-MM-DD'
|
|
582
|
+
|
|
583
|
+
-- Int
|
|
584
|
+
-- Numeric (KHÔNG dùng ::INT)
|
|
585
|
+
field::NUMERIC
|
|
586
|
+
|
|
587
|
+
-- Boolean
|
|
588
|
+
(status = 'active')::BOOLEAN AS is_active
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
## 9. File Organization
|
|
594
|
+
|
|
595
|
+
```
|
|
596
|
+
mainapp/SQL/duraone/
|
|
597
|
+
├── qas/
|
|
598
|
+
│ ├── view/
|
|
599
|
+
│ │ ├── v_agreement.sql
|
|
600
|
+
│ │ ├── v_clearance_request.sql
|
|
601
|
+
│ │ └── v_[entity].sql
|
|
602
|
+
│ │
|
|
603
|
+
│ ├── function/
|
|
604
|
+
│ │ ├── fn_get_agreement.sql
|
|
605
|
+
│ │ ├── fn_get_review_list.sql
|
|
606
|
+
│ │ └── fn_[operation]_[entity].sql
|
|
607
|
+
│ │
|
|
608
|
+
│ ├── store/
|
|
609
|
+
│ │ ├── sp_generate_running_no.sql
|
|
610
|
+
│ │ ├── sp_after_approve.sql
|
|
611
|
+
│ │ └── sp_[action]_[entity].sql
|
|
612
|
+
│ │
|
|
613
|
+
│ └── [feature]/ # Feature-specific (linechat, clearance, etc.)
|
|
614
|
+
│ ├── view/
|
|
615
|
+
│ ├── function/
|
|
616
|
+
│ └── store/
|
|
617
|
+
│
|
|
618
|
+
└── prd/ # Mirrors qas — same files, schema = prd
|
|
619
|
+
├── view/
|
|
620
|
+
├── function/
|
|
621
|
+
└── store/
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
**Cách chạy SQL khi deploy:**
|
|
625
|
+
```bash
|
|
626
|
+
# QAS
|
|
627
|
+
psql $QAS_CONN -f mainapp/SQL/duraone/qas/view/v_agreement.sql
|
|
628
|
+
|
|
629
|
+
# PRD (thay qas. → prd. trong file hoặc chạy riêng)
|
|
630
|
+
psql $PRD_CONN -f mainapp/SQL/duraone/prd/view/v_agreement.sql
|
|
631
|
+
```
|