From e63c19d158cb2f13fd81ed32a9b5fe119fa90f52 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Sat, 31 Jan 2026 22:53:47 -0600 Subject: [PATCH] chore: Cleanup QA reports and improve setup scripts Scripts: - common.sh: Fix select_option to use /dev/tty for interactive prompts - common.sh: Improve check_docker with detailed error messages - setup.sh: Add Traefik configuration options - setup.sh: Add argument validation for --mode, --external-authentik, etc. - setup.sh: Add fun taglines QA Reports: - Remove stale remediation reports - Keep current pending reports Co-Authored-By: Claude Opus 4.5 --- ...t.ts_20260131-1535_1_remediation_needed.md | 20 - ...t.ts_20260131-1535_2_remediation_needed.md | 20 - ...t.ts_20260131-1535_3_remediation_needed.md | 20 - ...t.ts_20260131-1535_4_remediation_needed.md | 20 - ...r.ts_20260131-1534_1_remediation_needed.md | 20 - ...r.ts_20260131-1534_2_remediation_needed.md | 20 - ...r.ts_20260131-1534_3_remediation_needed.md | 20 - ...e.ts_20260131-1535_1_remediation_needed.md | 20 - ...x.ts_20260131-1534_1_remediation_needed.md | 20 - ....ts_20260131-1648_1_remediation_needed.md} | 6 +- ...c.ts_20260131-1532_1_remediation_needed.md | 20 - ...c.ts_20260131-1533_1_remediation_needed.md | 20 - ...c.ts_20260131-1533_2_remediation_needed.md | 20 - ...c.ts_20260131-1534_1_remediation_needed.md | 20 - ...e.ts_20260131-1533_1_remediation_needed.md | 20 - ...e.ts_20260131-1533_2_remediation_needed.md | 20 - ...e.ts_20260131-1533_3_remediation_needed.md | 20 - ...e.ts_20260131-1534_1_remediation_needed.md | 20 - ...e.ts_20260131-1537_1_remediation_needed.md | 20 - ...e.ts_20260131-1537_2_remediation_needed.md | 20 - ...e.ts_20260131-1538_1_remediation_needed.md | 20 - ...e.ts_20260131-1538_2_remediation_needed.md | 20 - ...e.ts_20260131-1538_4_remediation_needed.md | 20 - ...e.ts_20260131-1538_5_remediation_needed.md | 20 - ...e.ts_20260131-1539_1_remediation_needed.md | 20 - ...e.ts_20260131-1539_2_remediation_needed.md | 20 - ...e.ts_20260131-1539_3_remediation_needed.md | 20 - ...e.ts_20260131-1539_4_remediation_needed.md | 20 - ...e.ts_20260131-1539_5_remediation_needed.md | 20 - ...e.ts_20260131-1540_1_remediation_needed.md | 20 - ....ts_20260131-1649_1_remediation_needed.md} | 4 +- ....ts_20260131-1649_2_remediation_needed.md} | 4 +- ....ts_20260131-1649_3_remediation_needed.md} | 4 +- ...x.ts_20260131-1531_1_remediation_needed.md | 20 - ...e.ts_20260131-1531_1_remediation_needed.md | 20 - ...r.ts_20260131-1459_1_remediation_needed.md | 20 - ...r.ts_20260131-1459_2_remediation_needed.md | 20 - ...r.ts_20260131-1459_3_remediation_needed.md | 20 - ...c.ts_20260131-1500_1_remediation_needed.md | 20 - ...e.ts_20260131-1500_1_remediation_needed.md | 20 - scripts/lib/common.sh | 77 +- scripts/setup.sh | 1708 ++++++++++++++++- 42 files changed, 1764 insertions(+), 759 deletions(-) delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_2_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_3_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_4_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_2_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_3_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.module.ts_20260131-1535_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-index.ts_20260131-1534_1_remediation_needed.md rename docs/reports/qa-automation/pending/{home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-intent-classification.dto.ts_20260131-1534_1_remediation_needed.md => home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-intent-classification.dto.ts_20260131-1648_1_remediation_needed.md} (80%) delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1532_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1533_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1533_2_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1534_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_2_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_3_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1534_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1537_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1537_2_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_2_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_4_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_5_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_2_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_3_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_4_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_5_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1540_1_remediation_needed.md rename docs/reports/qa-automation/pending/{home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1536_1_remediation_needed.md => home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_1_remediation_needed.md} (84%) rename docs/reports/qa-automation/pending/{home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1536_2_remediation_needed.md => home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_2_remediation_needed.md} (84%) rename docs/reports/qa-automation/pending/{home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_3_remediation_needed.md => home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_3_remediation_needed.md} (84%) delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-interfaces-index.ts_20260131-1531_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-interfaces-intent.interface.ts_20260131-1531_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_2_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_3_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-token-budget-token-budget.service.spec.ts_20260131-1500_1_remediation_needed.md delete mode 100644 docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-token-budget-token-budget.service.ts_20260131-1500_1_remediation_needed.md diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_1_remediation_needed.md deleted file mode 100644 index 3b14ea2..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/brain.controller.test.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:35:17 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_2_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_2_remediation_needed.md deleted file mode 100644 index 98252cd..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_2_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/brain.controller.test.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 2 -**Generated:** 2026-01-31 15:35:20 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_2_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_3_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_3_remediation_needed.md deleted file mode 100644 index ec40a53..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_3_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/brain.controller.test.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 3 -**Generated:** 2026-01-31 15:35:23 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_3_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_4_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_4_remediation_needed.md deleted file mode 100644 index 8e7880f..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_4_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/brain.controller.test.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 4 -**Generated:** 2026-01-31 15:35:34 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.test.ts_20260131-1535_4_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_1_remediation_needed.md deleted file mode 100644 index cfe7267..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/brain.controller.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:34:44 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_2_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_2_remediation_needed.md deleted file mode 100644 index 61ff483..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_2_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/brain.controller.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 2 -**Generated:** 2026-01-31 15:34:46 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_2_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_3_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_3_remediation_needed.md deleted file mode 100644 index 22281f1..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_3_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/brain.controller.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 3 -**Generated:** 2026-01-31 15:34:53 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.controller.ts_20260131-1534_3_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.module.ts_20260131-1535_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.module.ts_20260131-1535_1_remediation_needed.md deleted file mode 100644 index 8e52c92..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.module.ts_20260131-1535_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/brain.module.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:35:02 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-brain.module.ts_20260131-1535_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-index.ts_20260131-1534_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-index.ts_20260131-1534_1_remediation_needed.md deleted file mode 100644 index a24a13f..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-index.ts_20260131-1534_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/dto/index.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:34:38 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-index.ts_20260131-1534_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-intent-classification.dto.ts_20260131-1534_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-intent-classification.dto.ts_20260131-1648_1_remediation_needed.md similarity index 80% rename from docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-intent-classification.dto.ts_20260131-1534_1_remediation_needed.md rename to docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-intent-classification.dto.ts_20260131-1648_1_remediation_needed.md index 4aef31e..e9bd122 100644 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-intent-classification.dto.ts_20260131-1534_1_remediation_needed.md +++ b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-intent-classification.dto.ts_20260131-1648_1_remediation_needed.md @@ -1,10 +1,10 @@ # QA Remediation Report **File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/dto/intent-classification.dto.ts -**Tool Used:** Write +**Tool Used:** Edit **Epic:** general **Iteration:** 1 -**Generated:** 2026-01-31 15:34:33 +**Generated:** 2026-01-31 16:48:58 ## Status @@ -16,5 +16,5 @@ This report was created by the QA automation hook. To process this report, run: ```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-intent-classification.dto.ts_20260131-1534_1_remediation_needed.md" +claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-dto-intent-classification.dto.ts_20260131-1648_1_remediation_needed.md" ``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1532_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1532_1_remediation_needed.md deleted file mode 100644 index 1681b9d..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1532_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.spec.ts -**Tool Used:** Write -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:32:02 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1532_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1533_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1533_1_remediation_needed.md deleted file mode 100644 index 345f50c..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1533_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.spec.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:33:26 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1533_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1533_2_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1533_2_remediation_needed.md deleted file mode 100644 index 8e6e1e9..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1533_2_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.spec.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 2 -**Generated:** 2026-01-31 15:33:30 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1533_2_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1534_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1534_1_remediation_needed.md deleted file mode 100644 index 163962f..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1534_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.spec.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:34:04 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.spec.ts_20260131-1534_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_1_remediation_needed.md deleted file mode 100644 index 49e375e..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Write -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:33:06 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_2_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_2_remediation_needed.md deleted file mode 100644 index 8ab0d38..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_2_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 2 -**Generated:** 2026-01-31 15:33:50 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_2_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_3_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_3_remediation_needed.md deleted file mode 100644 index 37878e3..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_3_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 3 -**Generated:** 2026-01-31 15:33:55 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1533_3_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1534_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1534_1_remediation_needed.md deleted file mode 100644 index 89b045b..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1534_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:34:21 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1534_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1537_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1537_1_remediation_needed.md deleted file mode 100644 index d0ec974..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1537_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:37:35 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1537_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1537_2_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1537_2_remediation_needed.md deleted file mode 100644 index c303745..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1537_2_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 2 -**Generated:** 2026-01-31 15:37:45 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1537_2_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_1_remediation_needed.md deleted file mode 100644 index 39f1310..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:38:00 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_2_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_2_remediation_needed.md deleted file mode 100644 index b0cf961..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_2_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 2 -**Generated:** 2026-01-31 15:38:05 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_2_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_4_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_4_remediation_needed.md deleted file mode 100644 index f91af2d..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_4_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 4 -**Generated:** 2026-01-31 15:38:18 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_4_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_5_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_5_remediation_needed.md deleted file mode 100644 index 01b760d..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_5_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 5 -**Generated:** 2026-01-31 15:38:58 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_5_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_1_remediation_needed.md deleted file mode 100644 index 56dc2fc..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:39:05 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_2_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_2_remediation_needed.md deleted file mode 100644 index 67793d5..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_2_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 2 -**Generated:** 2026-01-31 15:39:10 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_2_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_3_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_3_remediation_needed.md deleted file mode 100644 index f860e9b..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_3_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 3 -**Generated:** 2026-01-31 15:39:37 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_3_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_4_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_4_remediation_needed.md deleted file mode 100644 index 41b0cf1..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_4_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 4 -**Generated:** 2026-01-31 15:39:41 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_4_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_5_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_5_remediation_needed.md deleted file mode 100644 index a23669e..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_5_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 5 -**Generated:** 2026-01-31 15:39:43 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1539_5_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1540_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1540_1_remediation_needed.md deleted file mode 100644 index f54934d..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1540_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/intent-classification.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:40:31 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1540_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1536_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_1_remediation_needed.md similarity index 84% rename from docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1536_1_remediation_needed.md rename to docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_1_remediation_needed.md index a73e5f4..3a682d8 100644 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1536_1_remediation_needed.md +++ b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_1_remediation_needed.md @@ -4,7 +4,7 @@ **Tool Used:** Edit **Epic:** general **Iteration:** 1 -**Generated:** 2026-01-31 15:36:27 +**Generated:** 2026-01-31 16:49:04 ## Status @@ -16,5 +16,5 @@ This report was created by the QA automation hook. To process this report, run: ```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1536_1_remediation_needed.md" +claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_1_remediation_needed.md" ``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1536_2_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_2_remediation_needed.md similarity index 84% rename from docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1536_2_remediation_needed.md rename to docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_2_remediation_needed.md index f249d2d..3bc7072 100644 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1536_2_remediation_needed.md +++ b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_2_remediation_needed.md @@ -4,7 +4,7 @@ **Tool Used:** Edit **Epic:** general **Iteration:** 2 -**Generated:** 2026-01-31 15:36:34 +**Generated:** 2026-01-31 16:49:18 ## Status @@ -16,5 +16,5 @@ This report was created by the QA automation hook. To process this report, run: ```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1536_2_remediation_needed.md" +claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_2_remediation_needed.md" ``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_3_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_3_remediation_needed.md similarity index 84% rename from docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_3_remediation_needed.md rename to docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_3_remediation_needed.md index f127b75..5db8210 100644 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_3_remediation_needed.md +++ b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_3_remediation_needed.md @@ -4,7 +4,7 @@ **Tool Used:** Edit **Epic:** general **Iteration:** 3 -**Generated:** 2026-01-31 15:38:11 +**Generated:** 2026-01-31 16:49:50 ## Status @@ -16,5 +16,5 @@ This report was created by the QA automation hook. To process this report, run: ```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1538_3_remediation_needed.md" +claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-intent-classification.service.ts_20260131-1649_3_remediation_needed.md" ``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-interfaces-index.ts_20260131-1531_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-interfaces-index.ts_20260131-1531_1_remediation_needed.md deleted file mode 100644 index 3f04769..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-interfaces-index.ts_20260131-1531_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/interfaces/index.ts -**Tool Used:** Write -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:31:08 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-interfaces-index.ts_20260131-1531_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-interfaces-intent.interface.ts_20260131-1531_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-interfaces-intent.interface.ts_20260131-1531_1_remediation_needed.md deleted file mode 100644 index 29d2a3d..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-interfaces-intent.interface.ts_20260131-1531_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/brain/interfaces/intent.interface.ts -**Tool Used:** Write -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:31:07 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-brain-interfaces-intent.interface.ts_20260131-1531_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_1_remediation_needed.md deleted file mode 100644 index 7d66674..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/llm/llm-provider-admin.controller.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 14:59:32 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_2_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_2_remediation_needed.md deleted file mode 100644 index 28e0fb2..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_2_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/llm/llm-provider-admin.controller.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 2 -**Generated:** 2026-01-31 14:59:42 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_2_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_3_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_3_remediation_needed.md deleted file mode 100644 index fbfa764..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_3_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/llm/llm-provider-admin.controller.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 3 -**Generated:** 2026-01-31 14:59:48 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-llm-llm-provider-admin.controller.ts_20260131-1459_3_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-token-budget-token-budget.service.spec.ts_20260131-1500_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-token-budget-token-budget.service.spec.ts_20260131-1500_1_remediation_needed.md deleted file mode 100644 index 40a6e8a..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-token-budget-token-budget.service.spec.ts_20260131-1500_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/token-budget/token-budget.service.spec.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:00:38 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-token-budget-token-budget.service.spec.ts_20260131-1500_1_remediation_needed.md" -``` diff --git a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-token-budget-token-budget.service.ts_20260131-1500_1_remediation_needed.md b/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-token-budget-token-budget.service.ts_20260131-1500_1_remediation_needed.md deleted file mode 100644 index e65ac58..0000000 --- a/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-token-budget-token-budget.service.ts_20260131-1500_1_remediation_needed.md +++ /dev/null @@ -1,20 +0,0 @@ -# QA Remediation Report - -**File:** /home/jwoltje/src/mosaic-stack/apps/api/src/token-budget/token-budget.service.ts -**Tool Used:** Edit -**Epic:** general -**Iteration:** 1 -**Generated:** 2026-01-31 15:00:02 - -## Status - -Pending QA validation - -## Next Steps - -This report was created by the QA automation hook. -To process this report, run: - -```bash -claude -p "Use Task tool to launch universal-qa-agent for report: /home/jwoltje/src/mosaic-stack/docs/reports/qa-automation/pending/home-jwoltje-src-mosaic-stack-apps-api-src-token-budget-token-budget.service.ts_20260131-1500_1_remediation_needed.md" -``` diff --git a/scripts/lib/common.sh b/scripts/lib/common.sh index 2877933..a9b2e87 100644 --- a/scripts/lib/common.sh +++ b/scripts/lib/common.sh @@ -20,7 +20,7 @@ else GREEN='' YELLOW='' BLUE='' - CYAN='\033[0;36m' + CYAN='' BOLD='' NC='' fi @@ -91,22 +91,24 @@ select_option() { local options=("$@") local num_options=${#options[@]} - echo "$prompt" + # Output UI to /dev/tty so it's visible even when function output is captured + echo "$prompt" >/dev/tty for i in "${!options[@]}"; do - printf " %d) %s\n" "$((i + 1))" "${options[$i]}" + printf " %d) %s\n" "$((i + 1))" "${options[$i]}" >/dev/tty done - echo "" + echo "" >/dev/tty local selection while true; do - read -r -p "Enter selection [1-$num_options]: " selection + read -r -p "Enter selection [1-$num_options]: " selection /dev/tty if [[ "$selection" =~ ^[0-9]+$ ]] && \ [ "$selection" -ge 1 ] && \ [ "$selection" -le "$num_options" ]; then + # Only output the selected value to stdout (for capture) echo "${options[$((selection - 1))]}" return 0 else - print_error "Invalid selection. Please enter a number between 1 and $num_options." + print_error "Invalid selection. Please enter a number between 1 and $num_options." >/dev/tty fi done } @@ -204,7 +206,34 @@ check_command() { } check_docker() { - check_command docker && docker info >/dev/null 2>&1 + if ! check_command docker; then + return 1 + fi + + # Check if daemon is accessible + if docker info >/dev/null 2>&1; then + return 0 + fi + + # Docker exists but daemon not accessible + # This could be permission issue or daemon not running + local error_msg + error_msg=$(docker info 2>&1) + + if [[ "$error_msg" =~ "permission denied" ]]; then + print_warning "Docker installed but permission denied" + print_info "You may need to add your user to the docker group:" + print_info " sudo usermod -aG docker \$USER" + print_info " Then log out and back in" + return 2 # Special code for permission issue + elif [[ "$error_msg" =~ "Cannot connect to the Docker daemon" ]]; then + print_warning "Docker installed but daemon not running" + print_info "Start it with: sudo systemctl start docker" + return 3 # Special code for daemon not running + else + print_warning "Docker installed but not accessible" + return 4 # Unknown issue + fi } check_docker_compose() { @@ -316,16 +345,17 @@ install_package() { case "$pkg_manager" in apt) - sudo apt update && sudo apt install -y "$package" + # Don't quote $package to allow multi-word package names + sudo apt update && sudo apt install -y $package ;; pacman) - sudo pacman -Sy --noconfirm "$package" + sudo pacman -Sy --noconfirm $package ;; dnf) - sudo dnf install -y "$package" + sudo dnf install -y $package ;; brew) - brew install "$package" + brew install $package ;; *) print_error "Unknown package manager: $pkg_manager" @@ -367,13 +397,34 @@ validate_port() { validate_domain() { local domain="$1" - if [[ "$domain" =~ ^[a-zA-Z0-9][a-zA-Z0-9.-]{0,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$ ]]; then + # Allow single-character subdomains and properly validate domain structure + if [[ "$domain" =~ ^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$ ]]; then return 0 else return 1 fi } +validate_ipv4() { + local ip="$1" + local IFS='.' + local -a octets + read -ra octets <<< "$ip" + + # Must have exactly 4 octets + [[ ${#octets[@]} -eq 4 ]] || return 1 + + # Each octet must be 0-255 + for octet in "${octets[@]}"; do + # Must be numeric + [[ "$octet" =~ ^[0-9]+$ ]] || return 1 + # Must be in range 0-255 + (( octet >= 0 && octet <= 255 )) || return 1 + done + + return 0 +} + # ============================================================================ # Secret and Password Generation # ============================================================================ @@ -407,7 +458,7 @@ is_placeholder() { # Check for common placeholder patterns if [[ "$value" =~ ^\$\{.*\}$ ]] || \ [[ "$value" =~ ^(change-me|changeme|your-.*|example|placeholder|TODO|FIXME|xxx+)$ ]] || \ - [[ "$value" =~ ^<.*>$ ]] || \ + [[ "$value" =~ ^\<.*\>$ ]] || \ [[ -z "$value" ]]; then return 0 else diff --git a/scripts/setup.sh b/scripts/setup.sh index a64f7e9..ec100ab 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -52,13 +52,61 @@ OLLAMA_MODE="disabled" OLLAMA_URL="" ENABLE_MOLTBOT=false MOSAIC_BASE_URL="" -MOSAIC_ALLOWED_HOSTS="" -AUTHENTIK_BASE_URL="" +API_BASE_URL="" +AUTHENTIK_PUBLIC_URL="" + +BASE_URL_MODE="" +BASE_URL_SCHEME="http" +BASE_URL_HOST="" +BASE_URL_PORT="" + +TRAEFIK_MODE="none" +TRAEFIK_ENABLE=false +TRAEFIK_TLS_ENABLED=true +TRAEFIK_ENTRYPOINT="websecure" +TRAEFIK_NETWORK="" +TRAEFIK_DOCKER_NETWORK="mosaic-public" +TRAEFIK_ACME_EMAIL="" +TRAEFIK_CERTRESOLVER="" +TRAEFIK_DASHBOARD_ENABLED=true +TRAEFIK_DASHBOARD_PORT="" + +MOSAIC_WEB_DOMAIN="" +MOSAIC_API_DOMAIN="" +MOSAIC_AUTH_DOMAIN="" + +WEB_PORT="" +API_PORT="" +POSTGRES_PORT="" +VALKEY_PORT="" +AUTHENTIK_PORT_HTTP="" +AUTHENTIK_PORT_HTTPS="" +OLLAMA_PORT="" +TRAEFIK_HTTP_PORT="" +TRAEFIK_HTTPS_PORT="" DETECTED_OS="" DETECTED_PKG_MANAGER="" PORT_OVERRIDES=() +# ============================================================================ +# Taglines (OpenClaw-inspired flavor) +# ============================================================================ + +TAGLINES=( + "Claws out, configs in — let's ship a calm, clean stack." + "Less yak-shaving, more uptime." + "Turnkey today, productive tonight." + "Ports resolved. Secrets sealed. Stack ready." + "All signal, no ceremony." + "Your .env is safe with me." +) + +pick_tagline() { + local idx=$((RANDOM % ${#TAGLINES[@]})) + echo "${TAGLINES[$idx]}" +} + # ============================================================================ # Help and Usage # ============================================================================ @@ -117,6 +165,10 @@ parse_arguments() { DRY_RUN=true ;; --mode) + if [[ -z "${2:-}" || "$2" == --* ]]; then + print_error "--mode requires a value (docker or native)" + exit 1 + fi MODE="$2" shift ;; @@ -127,14 +179,26 @@ parse_arguments() { USE_BUNDLED_AUTHENTIK=true ;; --external-authentik) + if [[ -z "${2:-}" || "$2" == --* ]]; then + print_error "--external-authentik requires a URL" + exit 1 + fi EXTERNAL_AUTHENTIK_URL="$2" shift ;; --ollama-mode) + if [[ -z "${2:-}" || "$2" == --* ]]; then + print_error "--ollama-mode requires a value (local, remote, or disabled)" + exit 1 + fi OLLAMA_MODE="$2" shift ;; --ollama-url) + if [[ -z "${2:-}" || "$2" == --* ]]; then + print_error "--ollama-url requires a URL" + exit 1 + fi OLLAMA_URL="$2" shift ;; @@ -142,6 +206,10 @@ parse_arguments() { ENABLE_MOLTBOT=true ;; --base-url) + if [[ -z "${2:-}" || "$2" == --* ]]; then + print_error "--base-url requires a URL" + exit 1 + fi MOSAIC_BASE_URL="$2" shift ;; @@ -170,6 +238,11 @@ parse_arguments() { print_error "Remote Ollama mode requires --ollama-url" exit 1 fi + + if [[ "$ENABLE_SSO" == true && "$USE_BUNDLED_AUTHENTIK" != true && -z "$EXTERNAL_AUTHENTIK_URL" ]]; then + print_error "SSO enabled in non-interactive mode requires --bundled-authentik or --external-authentik URL" + exit 1 + fi fi } @@ -184,15 +257,19 @@ show_banner() { cat << "EOF" - __ __ _ ____ _ _ - | \/ | ___ ___ __ _(_) ___| _ \| |_ __ _ ___| | __ - | |\/| |/ _ \/ __|/ _` | |/ __| |_) | __/ _` |/ __| |/ / - | | | | (_) \__ \ (_| | | (__| __/| || (_| | (__| < - |_| |_|\___/|___/\__,_|_|\___|_| \__\__,_|\___|_|\_\ + __ __ _ ____ _ _ + | \/ | ___ ___ __ _(_) ___ / ___| |_ __ _ ___| | __ + | |\/| |/ _ \/ __|/ _` | |/ __|\___ | __/ _` |/ __| |/ / + | | | | (_) \__ \ (_| | | (__ ___/ | || (_| | (__| < + |_| |_|\___/|___/\__,_|_|\___|____/ \__\__,_|\___|_|\_\ Multi-Tenant Personal Assistant Platform EOF + local tagline + tagline=$(pick_tagline) + echo " $tagline" + echo "" echo "Welcome to the Mosaic Stack Setup Wizard!" echo "" @@ -282,27 +359,50 @@ check_and_install_dependencies() { print_header "Checking Dependencies" local missing_deps=() + local docker_status=0 if [[ "$MODE" == "docker" ]]; then - if ! check_docker; then + check_docker + docker_status=$? + + if [[ $docker_status -eq 1 ]]; then + # Docker not installed missing_deps+=("Docker") + elif [[ $docker_status -ne 0 ]]; then + # Docker installed but not accessible (permission/daemon issue) + echo "" + print_error "Docker is installed but not accessible" + print_info "Please fix the issue above and run the setup script again" + exit 1 + else + print_success "Docker: OK" fi + if ! check_docker_compose; then missing_deps+=("Docker Compose") + else + print_success "Docker Compose: OK" fi else if ! check_node 18; then missing_deps+=("Node.js 18+") + else + print_success "Node.js: OK" fi if ! check_pnpm; then missing_deps+=("pnpm") + else + print_success "pnpm: OK" fi if ! check_postgres; then missing_deps+=("PostgreSQL") + else + print_success "PostgreSQL: OK" fi fi if [[ ${#missing_deps[@]} -eq 0 ]]; then + echo "" print_success "All dependencies satisfied" return 0 fi @@ -426,6 +526,321 @@ load_existing_env() { return 1 } +# ============================================================================ +# URL and Port Helpers +# ============================================================================ + +strip_trailing_slash() { + local value="$1" + echo "${value%/}" +} + +format_url() { + local scheme="$1" + local host="$2" + local port="$3" + local always_port="${4:-false}" + + if [[ -z "$host" ]]; then + echo "" + return + fi + + if [[ -z "$port" ]]; then + echo "${scheme}://${host}" + return + fi + + if [[ "$always_port" == true ]]; then + echo "${scheme}://${host}:${port}" + return + fi + + if [[ "$scheme" == "http" && "$port" == "80" ]] || [[ "$scheme" == "https" && "$port" == "443" ]]; then + echo "${scheme}://${host}" + else + echo "${scheme}://${host}:${port}" + fi +} + +bool_str() { + if [[ "$1" == true ]]; then + echo "true" + else + echo "false" + fi +} + +resolve_env_value() { + local key="$1" + local fallback="$2" + local value + value=$(get_env_value "$key") + if [[ -n "$value" ]] && ! is_placeholder "$value"; then + echo "$value" + else + echo "$fallback" + fi +} + +resolve_secret_value() { + local key="$1" + local generator="$2" + local length="$3" + local value + value=$(get_env_value "$key") + if [[ -n "$value" ]] && ! is_placeholder "$value"; then + echo "$value" + else + "$generator" "$length" + fi +} + +derive_cookie_domain() { + local domain="$1" + if [[ "$domain" == *.* ]]; then + echo ".${domain#*.}" + else + echo ".${domain}" + fi +} + +resolve_port_value() { + local key="$1" + local fallback="$2" + local value + value=$(get_env_value "$key") + if validate_port "$value"; then + echo "$value" + else + echo "$fallback" + fi +} + +initialize_ports() { + WEB_PORT=$(resolve_port_value "WEB_PORT" "3000") + API_PORT=$(resolve_port_value "API_PORT" "3001") + POSTGRES_PORT=$(resolve_port_value "POSTGRES_PORT" "5432") + VALKEY_PORT=$(resolve_port_value "VALKEY_PORT" "6379") + AUTHENTIK_PORT_HTTP=$(resolve_port_value "AUTHENTIK_PORT_HTTP" "9000") + AUTHENTIK_PORT_HTTPS=$(resolve_port_value "AUTHENTIK_PORT_HTTPS" "9443") + OLLAMA_PORT=$(resolve_port_value "OLLAMA_PORT" "11434") + TRAEFIK_HTTP_PORT=$(resolve_port_value "TRAEFIK_HTTP_PORT" "80") + TRAEFIK_HTTPS_PORT=$(resolve_port_value "TRAEFIK_HTTPS_PORT" "443") + TRAEFIK_DASHBOARD_PORT=$(resolve_port_value "TRAEFIK_DASHBOARD_PORT" "8080") +} + +parse_base_url() { + local url="$1" + + if [[ "$url" =~ ^(https?)://([^/:]+)(:([0-9]+))?(/.*)?$ ]]; then + BASE_URL_SCHEME="${BASH_REMATCH[1]}" + BASE_URL_HOST="${BASH_REMATCH[2]}" + BASE_URL_PORT="${BASH_REMATCH[4]}" + return 0 + fi + + return 1 +} + +recalculate_urls() { + if [[ "$BASE_URL_MODE" == "traefik" ]]; then + local traefik_port="" + if [[ "$TRAEFIK_MODE" == "bundled" ]]; then + if [[ "$BASE_URL_SCHEME" == "https" ]]; then + traefik_port="$TRAEFIK_HTTPS_PORT" + else + traefik_port="$TRAEFIK_HTTP_PORT" + fi + fi + + MOSAIC_BASE_URL=$(format_url "$BASE_URL_SCHEME" "$MOSAIC_WEB_DOMAIN" "$traefik_port") + API_BASE_URL=$(format_url "$BASE_URL_SCHEME" "$MOSAIC_API_DOMAIN" "$traefik_port") + else + local always_port=false + if [[ "$BASE_URL_MODE" == "localhost" || "$BASE_URL_MODE" == "ip" ]]; then + always_port=true + fi + MOSAIC_BASE_URL=$(format_url "$BASE_URL_SCHEME" "$BASE_URL_HOST" "$WEB_PORT" "$always_port") + API_BASE_URL=$(format_url "$BASE_URL_SCHEME" "$BASE_URL_HOST" "$API_PORT" true) + fi + + if [[ "$ENABLE_SSO" == true ]]; then + if [[ "$USE_BUNDLED_AUTHENTIK" == true ]]; then + if [[ "$BASE_URL_MODE" == "traefik" && -n "$MOSAIC_AUTH_DOMAIN" ]]; then + local auth_port="" + if [[ "$TRAEFIK_MODE" == "bundled" ]]; then + if [[ "$BASE_URL_SCHEME" == "https" ]]; then + auth_port="$TRAEFIK_HTTPS_PORT" + else + auth_port="$TRAEFIK_HTTP_PORT" + fi + fi + AUTHENTIK_PUBLIC_URL=$(format_url "$BASE_URL_SCHEME" "$MOSAIC_AUTH_DOMAIN" "$auth_port") + else + AUTHENTIK_PUBLIC_URL="http://localhost:${AUTHENTIK_PORT_HTTP}" + fi + else + AUTHENTIK_PUBLIC_URL="$EXTERNAL_AUTHENTIK_URL" + fi + fi +} + +port_label() { + local key="$1" + case "$key" in + WEB_PORT) echo "Web UI" ;; + API_PORT) echo "API" ;; + POSTGRES_PORT) echo "PostgreSQL" ;; + VALKEY_PORT) echo "Valkey" ;; + AUTHENTIK_PORT_HTTP) echo "Authentik HTTP" ;; + AUTHENTIK_PORT_HTTPS) echo "Authentik HTTPS" ;; + OLLAMA_PORT) echo "Ollama" ;; + TRAEFIK_HTTP_PORT) echo "Traefik HTTP" ;; + TRAEFIK_HTTPS_PORT) echo "Traefik HTTPS" ;; + TRAEFIK_DASHBOARD_PORT) echo "Traefik Dashboard" ;; + *) echo "$key" ;; + esac +} + +suggest_port_for_key() { + local key="$1" + local port="$2" + + case "$key" in + TRAEFIK_HTTP_PORT) + if ! check_port_in_use 8080; then + echo "8080" + return 0 + fi + ;; + TRAEFIK_HTTPS_PORT) + if ! check_port_in_use 8443; then + echo "8443" + return 0 + fi + ;; + esac + + suggest_alternative_port "$port" +} + +apply_port_override() { + local key="$1" + local value="$2" + + case "$key" in + WEB_PORT) WEB_PORT="$value" ;; + API_PORT) API_PORT="$value" ;; + POSTGRES_PORT) POSTGRES_PORT="$value" ;; + VALKEY_PORT) VALKEY_PORT="$value" ;; + AUTHENTIK_PORT_HTTP) AUTHENTIK_PORT_HTTP="$value" ;; + AUTHENTIK_PORT_HTTPS) AUTHENTIK_PORT_HTTPS="$value" ;; + OLLAMA_PORT) OLLAMA_PORT="$value" ;; + TRAEFIK_HTTP_PORT) TRAEFIK_HTTP_PORT="$value" ;; + TRAEFIK_HTTPS_PORT) TRAEFIK_HTTPS_PORT="$value" ;; + TRAEFIK_DASHBOARD_PORT) TRAEFIK_DASHBOARD_PORT="$value" ;; + esac + + set_env_value "$key" "$value" +} + +apply_port_overrides() { + if [[ ${#PORT_OVERRIDES[@]} -eq 0 ]]; then + return + fi + + for override in "${PORT_OVERRIDES[@]}"; do + local key="${override%%=*}" + local value="${override#*=}" + apply_port_override "$key" "$value" + done + + recalculate_urls +} + +resolve_port_conflicts() { + if [[ "$MODE" != "docker" ]]; then + return + fi + + print_header "Port Check" + + local port_entries=() + port_entries+=("WEB_PORT=$WEB_PORT") + port_entries+=("API_PORT=$API_PORT") + port_entries+=("POSTGRES_PORT=$POSTGRES_PORT") + port_entries+=("VALKEY_PORT=$VALKEY_PORT") + + if [[ "$ENABLE_SSO" == true && "$USE_BUNDLED_AUTHENTIK" == true ]]; then + port_entries+=("AUTHENTIK_PORT_HTTP=$AUTHENTIK_PORT_HTTP") + port_entries+=("AUTHENTIK_PORT_HTTPS=$AUTHENTIK_PORT_HTTPS") + fi + + if [[ "$OLLAMA_MODE" == "local" ]]; then + port_entries+=("OLLAMA_PORT=$OLLAMA_PORT") + fi + + if [[ "$TRAEFIK_MODE" == "bundled" ]]; then + port_entries+=("TRAEFIK_HTTP_PORT=$TRAEFIK_HTTP_PORT") + port_entries+=("TRAEFIK_HTTPS_PORT=$TRAEFIK_HTTPS_PORT") + if [[ "$TRAEFIK_DASHBOARD_ENABLED" == true ]]; then + port_entries+=("TRAEFIK_DASHBOARD_PORT=$TRAEFIK_DASHBOARD_PORT") + fi + fi + + local conflicts=() + local suggestions=() + + for entry in "${port_entries[@]}"; do + local key="${entry%%=*}" + local port="${entry#*=}" + if check_port_in_use "$port"; then + local suggested + suggested=$(suggest_port_for_key "$key" "$port") + conflicts+=("${key}=${port}") + suggestions+=("${key}=${suggested}") + fi + done + + if [[ ${#conflicts[@]} -eq 0 ]]; then + print_success "No port conflicts detected" + return + fi + + echo "" + print_warning "Port conflicts detected:" + for conflict in "${conflicts[@]}"; do + local key="${conflict%%=*}" + local port="${conflict#*=}" + echo " - $(port_label "$key"): $port" + done + echo "" + print_info "Suggested alternatives:" + for suggestion in "${suggestions[@]}"; do + local key="${suggestion%%=*}" + local port="${suggestion#*=}" + echo " - $(port_label "$key"): $port" + done + echo "" + + if [[ "$NON_INTERACTIVE" == true ]]; then + PORT_OVERRIDES=("${suggestions[@]}") + print_success "Applying alternative ports automatically (non-interactive)" + apply_port_overrides + return + fi + + if confirm "Apply suggested ports automatically?" "y"; then + PORT_OVERRIDES=("${suggestions[@]}") + apply_port_overrides + print_success "Alternative ports applied" + else + print_error "Port conflicts must be resolved to continue" + exit 1 + fi +} + collect_configuration() { print_header "Configuration" @@ -438,9 +853,1258 @@ collect_configuration() { echo "" fi - # Continue with remaining configuration... - # (This would continue with URL config, SSO, Ollama, MoltBot, etc.) - # Keeping this section shorter for now - can be expanded following Calibr pattern + initialize_ports + + # Base URL Configuration + configure_base_url + + # SSO Configuration (Docker mode only) + if [[ "$MODE" == "docker" ]]; then + configure_sso + fi + + # Ollama Configuration + configure_ollama + + # MoltBot Configuration + configure_moltbot + + # Generate secrets if needed + configure_secrets +} + +configure_base_url() { + echo "" + print_step "Base URL Configuration" + echo "" + + local current_url + current_url=$(get_env_value "MOSAIC_BASE_URL") + + if [[ -n "$current_url" ]] && ! is_placeholder "$current_url"; then + echo "Current base URL: $current_url" + if [[ "$NON_INTERACTIVE" == true ]] || ! confirm "Change base URL?" "n"; then + if parse_base_url "$current_url"; then + BASE_URL_MODE="custom" + if [[ -n "$BASE_URL_PORT" ]]; then + WEB_PORT="$BASE_URL_PORT" + else + if [[ "$BASE_URL_SCHEME" == "https" ]]; then + WEB_PORT="443" + else + WEB_PORT="80" + fi + fi + recalculate_urls + return + fi + fi + fi + + if [[ -n "$MOSAIC_BASE_URL" ]]; then + # Already set via CLI argument + print_info "Using base URL from command line: $MOSAIC_BASE_URL" + if ! parse_base_url "$MOSAIC_BASE_URL"; then + print_error "Invalid base URL format. Expected: http(s)://host[:port]" + exit 1 + fi + BASE_URL_MODE="custom" + if [[ -n "$BASE_URL_PORT" ]]; then + WEB_PORT="$BASE_URL_PORT" + else + if [[ "$BASE_URL_SCHEME" == "https" ]]; then + WEB_PORT="443" + else + WEB_PORT="80" + fi + fi + recalculate_urls + return + fi + + if [[ "$NON_INTERACTIVE" == true ]]; then + BASE_URL_MODE="localhost" + BASE_URL_SCHEME="http" + BASE_URL_HOST="localhost" + BASE_URL_PORT="$WEB_PORT" + recalculate_urls + print_info "Non-interactive mode: using $MOSAIC_BASE_URL" + return + fi + + echo "How will Mosaic Stack be accessed?" + echo "" + + local options=( + "Localhost (recommended for local install)" + "Local network IP" + "Custom domain (direct ports)" + ) + + if [[ "$MODE" == "docker" ]]; then + options+=("Traefik reverse proxy (bundled or existing)") + fi + + local selection + selection=$(select_option "Select access method:" "${options[@]}") + + case "$selection" in + *"Localhost"*) + configure_localhost_url + ;; + *"Local network IP"*) + configure_ip_url + ;; + *"Custom domain"*) + configure_dns_url + ;; + *"Traefik"*) + configure_traefik_url + ;; + esac +} + +configure_dns_url() { + echo "" + BASE_URL_MODE="domain" + + local domain + while true; do + read -r -p "Enter your domain (e.g., mosaic.example.com): " domain + if validate_domain "$domain"; then + break + else + print_error "Invalid domain format" + fi + done + + # Ask about SSL + local use_https=true + if ! confirm "Use HTTPS?" "y"; then + use_https=false + fi + + if [[ "$use_https" == true ]]; then + BASE_URL_SCHEME="https" + print_warning "Consider using a reverse proxy for TLS certificates" + else + BASE_URL_SCHEME="http" + fi + + BASE_URL_HOST="$domain" + + local default_port="$WEB_PORT" + local port + while true; do + read -r -p "Enter web port [$default_port]: " port + port=${port:-$default_port} + if validate_port "$port"; then + break + else + print_error "Invalid port number" + fi + done + + WEB_PORT="$port" + BASE_URL_PORT="$WEB_PORT" + recalculate_urls + print_success "Base URL set to: $MOSAIC_BASE_URL" +} + +configure_localhost_url() { + echo "" + BASE_URL_MODE="localhost" + BASE_URL_SCHEME="http" + BASE_URL_HOST="localhost" + + local default_port="$WEB_PORT" + + local port + while true; do + read -r -p "Enter web port [$default_port]: " port + port=${port:-$default_port} + if validate_port "$port"; then + break + else + print_error "Invalid port number" + fi + done + + WEB_PORT="$port" + BASE_URL_PORT="$WEB_PORT" + recalculate_urls + print_success "Base URL set to: $MOSAIC_BASE_URL" +} + +configure_ip_url() { + echo "" + BASE_URL_MODE="ip" + BASE_URL_SCHEME="http" + + # Try to detect local IP + local detected_ip + if command -v ip >/dev/null 2>&1; then + detected_ip=$(ip route get 1 2>/dev/null | awk '{print $7; exit}') + elif command -v ifconfig >/dev/null 2>&1; then + detected_ip=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | head -n1) + fi + + if [[ -n "$detected_ip" ]]; then + print_info "Detected IP: $detected_ip" + fi + + local ip_addr + while true; do + read -r -p "Enter IP address${detected_ip:+ [$detected_ip]}: " ip_addr + ip_addr=${ip_addr:-$detected_ip} + if validate_ipv4 "$ip_addr"; then + break + else + print_error "Invalid IP address (must be 0.0.0.0 - 255.255.255.255)" + fi + done + + BASE_URL_HOST="$ip_addr" + + local default_port="$WEB_PORT" + local port + while true; do + read -r -p "Enter web port [$default_port]: " port + port=${port:-$default_port} + if validate_port "$port"; then + break + else + print_error "Invalid port number" + fi + done + + WEB_PORT="$port" + BASE_URL_PORT="$WEB_PORT" + recalculate_urls + print_success "Base URL set to: $MOSAIC_BASE_URL" +} + +configure_traefik_url() { + echo "" + print_info "Configuring Traefik integration" + echo "" + + local mode_selection + mode_selection=$(select_option "Traefik mode:" \ + "Bundled Traefik (run inside this stack)" \ + "Upstream Traefik (existing instance)") + + if [[ "$mode_selection" == *"Bundled"* ]]; then + TRAEFIK_MODE="bundled" + TRAEFIK_ENABLE=true + else + TRAEFIK_MODE="upstream" + TRAEFIK_ENABLE=true + fi + + if confirm "Enable TLS/HTTPS for Traefik?" "y"; then + TRAEFIK_TLS_ENABLED=true + TRAEFIK_ENTRYPOINT="websecure" + BASE_URL_SCHEME="https" + else + TRAEFIK_TLS_ENABLED=false + TRAEFIK_ENTRYPOINT="web" + BASE_URL_SCHEME="http" + fi + + BASE_URL_MODE="traefik" + + local default_web_domain="mosaic.local" + while true; do + read -r -p "Web domain [$default_web_domain]: " MOSAIC_WEB_DOMAIN + MOSAIC_WEB_DOMAIN=${MOSAIC_WEB_DOMAIN:-$default_web_domain} + if validate_domain "$MOSAIC_WEB_DOMAIN"; then + break + fi + print_error "Invalid domain format" + done + + local default_api_domain="api.${MOSAIC_WEB_DOMAIN}" + while true; do + read -r -p "API domain [$default_api_domain]: " MOSAIC_API_DOMAIN + MOSAIC_API_DOMAIN=${MOSAIC_API_DOMAIN:-$default_api_domain} + if validate_domain "$MOSAIC_API_DOMAIN"; then + break + fi + print_error "Invalid domain format" + done + + if [[ "$ENABLE_SSO" == true ]]; then + local default_auth_domain="auth.${MOSAIC_WEB_DOMAIN}" + while true; do + read -r -p "Auth domain [$default_auth_domain]: " MOSAIC_AUTH_DOMAIN + MOSAIC_AUTH_DOMAIN=${MOSAIC_AUTH_DOMAIN:-$default_auth_domain} + if validate_domain "$MOSAIC_AUTH_DOMAIN"; then + break + fi + print_error "Invalid domain format" + done + fi + + if [[ "$TRAEFIK_MODE" == "upstream" ]]; then + local default_network="traefik-public" + read -r -p "External Traefik network name [$default_network]: " TRAEFIK_NETWORK + TRAEFIK_NETWORK=${TRAEFIK_NETWORK:-$default_network} + TRAEFIK_DOCKER_NETWORK="$TRAEFIK_NETWORK" + fi + + if [[ "$TRAEFIK_MODE" == "bundled" ]]; then + if confirm "Enable Traefik dashboard?" "y"; then + TRAEFIK_DASHBOARD_ENABLED=true + local default_dash_port="$TRAEFIK_DASHBOARD_PORT" + local dash_port + while true; do + read -r -p "Traefik dashboard port [$default_dash_port]: " dash_port + dash_port=${dash_port:-$default_dash_port} + if validate_port "$dash_port"; then + break + else + print_error "Invalid port number" + fi + done + TRAEFIK_DASHBOARD_PORT="$dash_port" + else + TRAEFIK_DASHBOARD_ENABLED=false + fi + fi + + recalculate_urls + print_success "Base URL set to: $MOSAIC_BASE_URL" + print_info "Traefik domains configured for web and API" +} + +configure_sso() { + echo "" + print_step "SSO Configuration (Authentik)" + echo "" + + # Check if SSO already configured + local current_sso_enabled + current_sso_enabled=$(get_env_value "ENABLE_SSO") + + if [[ -n "$ENABLE_SSO" ]]; then + # Already set via CLI + print_info "SSO enabled: $ENABLE_SSO" + elif [[ "$current_sso_enabled" == "true" ]]; then + echo "SSO is currently enabled" + if [[ "$NON_INTERACTIVE" == false ]] && ! confirm "Keep SSO enabled?" "y"; then + ENABLE_SSO=false + return + fi + ENABLE_SSO=true + else + if [[ "$NON_INTERACTIVE" == true ]]; then + ENABLE_SSO=false + return + fi + if ! confirm "Enable Authentik SSO?"; then + ENABLE_SSO=false + return + fi + ENABLE_SSO=true + fi + + if [[ "$ENABLE_SSO" != true ]]; then + return + fi + + # Bundled vs External Authentik + local current_bundled + current_bundled=$(get_env_value "USE_BUNDLED_AUTHENTIK") + + if [[ -n "$USE_BUNDLED_AUTHENTIK" ]]; then + # Already set via CLI + print_info "Using bundled Authentik: $USE_BUNDLED_AUTHENTIK" + elif [[ "$current_bundled" == "true" ]]; then + echo "Currently using bundled Authentik" + if [[ "$NON_INTERACTIVE" == false ]] && ! confirm "Keep using bundled Authentik?" "y"; then + USE_BUNDLED_AUTHENTIK=false + else + USE_BUNDLED_AUTHENTIK=true + fi + else + if [[ "$NON_INTERACTIVE" == true ]]; then + USE_BUNDLED_AUTHENTIK=false + elif confirm "Use bundled Authentik server?" "y"; then + USE_BUNDLED_AUTHENTIK=true + else + USE_BUNDLED_AUTHENTIK=false + fi + fi + + # If external, get URL + if [[ "$USE_BUNDLED_AUTHENTIK" != true ]]; then + local current_auth_url + current_auth_url=$(get_env_value "AUTHENTIK_BASE_URL") + + if [[ -n "$EXTERNAL_AUTHENTIK_URL" ]]; then + EXTERNAL_AUTHENTIK_URL=$(strip_trailing_slash "$EXTERNAL_AUTHENTIK_URL") + elif [[ -n "$current_auth_url" ]] && ! is_placeholder "$current_auth_url"; then + echo "Current Authentik URL: $current_auth_url" + if [[ "$NON_INTERACTIVE" == true ]] || ! confirm "Change Authentik URL?" "n"; then + EXTERNAL_AUTHENTIK_URL=$(strip_trailing_slash "$current_auth_url") + else + read_authentik_url + fi + else + read_authentik_url + fi + + if [[ -z "$EXTERNAL_AUTHENTIK_URL" ]]; then + print_error "External Authentik URL is required when not using bundled Authentik" + exit 1 + fi + fi + + if [[ "$USE_BUNDLED_AUTHENTIK" == true ]]; then + if [[ "$BASE_URL_MODE" == "traefik" && -z "$MOSAIC_AUTH_DOMAIN" ]]; then + if [[ "$NON_INTERACTIVE" == true ]]; then + MOSAIC_AUTH_DOMAIN="auth.${MOSAIC_WEB_DOMAIN:-mosaic.local}" + else + local default_auth_domain="auth.${MOSAIC_WEB_DOMAIN:-mosaic.local}" + read -r -p "Auth domain [$default_auth_domain]: " MOSAIC_AUTH_DOMAIN + MOSAIC_AUTH_DOMAIN=${MOSAIC_AUTH_DOMAIN:-$default_auth_domain} + fi + fi + fi + + recalculate_urls +} + +read_authentik_url() { + while true; do + read -r -p "Enter external Authentik URL: " EXTERNAL_AUTHENTIK_URL + if validate_url "$EXTERNAL_AUTHENTIK_URL"; then + EXTERNAL_AUTHENTIK_URL=$(strip_trailing_slash "$EXTERNAL_AUTHENTIK_URL") + break + else + print_error "Invalid URL format" + fi + done +} + +configure_ollama() { + echo "" + print_step "Ollama Configuration" + echo "" + + local current_mode + current_mode=$(get_env_value "OLLAMA_MODE") + + if [[ -n "$OLLAMA_MODE" ]] && [[ "$OLLAMA_MODE" != "disabled" ]]; then + # Already set via CLI + print_info "Ollama mode: $OLLAMA_MODE" + elif [[ -n "$current_mode" ]] && [[ "$current_mode" != "disabled" ]]; then + echo "Current Ollama mode: $current_mode" + if [[ "$NON_INTERACTIVE" == false ]] && confirm "Change Ollama configuration?" "n"; then + select_ollama_mode + else + OLLAMA_MODE="$current_mode" + fi + else + select_ollama_mode + fi + + # Get Ollama URL if remote mode + if [[ "$OLLAMA_MODE" == "remote" ]]; then + local current_url + current_url=$(get_env_value "OLLAMA_ENDPOINT") + + if [[ -n "$OLLAMA_URL" ]]; then + # Already set via CLI + print_info "Ollama URL: $OLLAMA_URL" + elif [[ -n "$current_url" ]] && ! is_placeholder "$current_url"; then + echo "Current Ollama URL: $current_url" + if [[ "$NON_INTERACTIVE" == false ]] && confirm "Change Ollama URL?" "n"; then + read_ollama_url + else + OLLAMA_URL="$current_url" + fi + else + read_ollama_url + fi + fi +} + +select_ollama_mode() { + if [[ "$NON_INTERACTIVE" == true ]]; then + OLLAMA_MODE="disabled" + return + fi + + local selection + selection=$(select_option "Select Ollama mode:" \ + "Disabled (no local LLM)" \ + "Local (run Ollama in Docker)" \ + "Remote (connect to existing Ollama server)") + + case "$selection" in + *"Disabled"*) + OLLAMA_MODE="disabled" + ;; + *"Local"*) + OLLAMA_MODE="local" + ;; + *"Remote"*) + OLLAMA_MODE="remote" + ;; + esac +} + +read_ollama_url() { + while true; do + read -r -p "Enter Ollama server URL: " OLLAMA_URL + if validate_url "$OLLAMA_URL"; then + break + else + print_error "Invalid URL format" + fi + done +} + +configure_moltbot() { + echo "" + print_step "MoltBot Configuration" + echo "" + + local current_enabled + current_enabled=$(get_env_value "ENABLE_MOLTBOT") + + if [[ -n "$ENABLE_MOLTBOT" ]]; then + # Already set via CLI + print_info "MoltBot enabled: $ENABLE_MOLTBOT" + elif [[ "$current_enabled" == "true" ]]; then + echo "MoltBot is currently enabled" + if [[ "$NON_INTERACTIVE" == false ]] && ! confirm "Keep MoltBot enabled?" "y"; then + ENABLE_MOLTBOT=false + else + ENABLE_MOLTBOT=true + fi + else + if [[ "$NON_INTERACTIVE" == true ]]; then + ENABLE_MOLTBOT=false + elif confirm "Enable MoltBot integration?"; then + ENABLE_MOLTBOT=true + else + ENABLE_MOLTBOT=false + fi + fi +} + +configure_secrets() { + echo "" + print_step "Secret Generation" + echo "" + + # Check if secrets exist and are not placeholders + local db_password + local jwt_secret + local auth_db_password + local auth_secret_key + local auth_bootstrap_password + + db_password=$(get_env_value "POSTGRES_PASSWORD") + jwt_secret=$(get_env_value "JWT_SECRET") + auth_db_password=$(get_env_value "AUTHENTIK_POSTGRES_PASSWORD") + auth_secret_key=$(get_env_value "AUTHENTIK_SECRET_KEY") + auth_bootstrap_password=$(get_env_value "AUTHENTIK_BOOTSTRAP_PASSWORD") + + local needs_generation=false + + if is_placeholder "$db_password"; then + print_info "Will generate database password" + needs_generation=true + fi + + if is_placeholder "$jwt_secret"; then + print_info "Will generate JWT secret" + needs_generation=true + fi + + if [[ "$ENABLE_SSO" == true && "$USE_BUNDLED_AUTHENTIK" == true ]]; then + if is_placeholder "$auth_db_password"; then + print_info "Will generate Authentik database password" + needs_generation=true + fi + + if is_placeholder "$auth_secret_key"; then + print_info "Will generate Authentik secret key" + needs_generation=true + fi + + if is_placeholder "$auth_bootstrap_password"; then + print_info "Will generate Authentik bootstrap password" + needs_generation=true + fi + fi + + if [[ "$needs_generation" == true ]]; then + print_success "Secrets will be generated during .env creation" + else + print_success "Existing secrets will be preserved" + fi +} + +# ============================================================================ +# .env File Generation +# ============================================================================ + +declare -gA ENV_OVERRIDES + +env_override_set() { + local key="$1" + local value="$2" + ENV_OVERRIDES["$key"]="$value" +} + +write_env_with_overrides() { + local template="$1" + local output="$2" + + local overrides_file + overrides_file=$(mktemp) + + for key in "${!ENV_OVERRIDES[@]}"; do + printf '%s=%s\n' "$key" "${ENV_OVERRIDES[$key]}" >> "$overrides_file" + done + + awk -v overrides_file="$overrides_file" ' + BEGIN { + while ((getline < overrides_file) > 0) { + line = $0 + if (line ~ /^[A-Za-z0-9_]+=*/) { + key = substr(line, 1, index(line, "=") - 1) + value = substr(line, index(line, "=") + 1) + map[key] = value + } + } + close(overrides_file) + } + { + if (match($0, /^([A-Za-z0-9_]+)=/, m)) { + key = m[1] + if (key in map) { + print key "=" map[key] + used[key] = 1 + next + } + } + print + } + END { + for (key in map) { + if (!(key in used)) { + print key "=" map[key] + } + } + } + ' "$template" > "$output" + + rm -f "$overrides_file" +} + +generate_env_file() { + print_header ".env File Generation" + + # Backup existing .env if it exists + if [[ -f "$PROJECT_ROOT/.env" ]]; then + backup_file "$PROJECT_ROOT/.env" + fi + + echo "" + print_step "Generating .env file with your configuration..." + echo "" + + # Start with .env.example template + local template="$PROJECT_ROOT/.env.example" + local output="$PROJECT_ROOT/.env" + + if [[ ! -f "$template" ]]; then + print_error ".env.example template not found" + exit 1 + fi + + ENV_OVERRIDES=() + + for key in "${!ENV_VALUES[@]}"; do + local value="${ENV_VALUES[$key]}" + if [[ -n "$value" ]] && ! is_placeholder "$value"; then + env_override_set "$key" "$value" + fi + done + + local xtrace_was_on=false + if [[ "$-" == *x* ]]; then + xtrace_was_on=true + set +x + fi + + local postgres_user + local postgres_db + local db_password + local jwt_secret + local jwt_expiration + local api_host + local valkey_url + local database_url + + postgres_user=$(resolve_env_value "POSTGRES_USER" "mosaic") + postgres_db=$(resolve_env_value "POSTGRES_DB" "mosaic") + api_host=$(resolve_env_value "API_HOST" "0.0.0.0") + jwt_expiration=$(resolve_env_value "JWT_EXPIRATION" "24h") + + local existing_db_password + existing_db_password=$(get_env_value "POSTGRES_PASSWORD") + db_password=$(resolve_secret_value "POSTGRES_PASSWORD" generate_password 32) + if [[ -n "$existing_db_password" ]] && ! is_placeholder "$existing_db_password"; then + print_info "Preserving existing database password" + else + print_info "Generated database password" + fi + + local existing_jwt_secret + existing_jwt_secret=$(get_env_value "JWT_SECRET") + jwt_secret=$(resolve_secret_value "JWT_SECRET" generate_secret 50) + if [[ -n "$existing_jwt_secret" ]] && ! is_placeholder "$existing_jwt_secret"; then + print_info "Preserving existing JWT secret" + else + print_info "Generated JWT secret" + fi + + if [[ "$MODE" == "docker" ]]; then + database_url="postgresql://${postgres_user}:${db_password}@postgres:5432/${postgres_db}" + valkey_url="redis://valkey:6379" + else + database_url="postgresql://${postgres_user}:${db_password}@localhost:${POSTGRES_PORT}/${postgres_db}" + valkey_url="redis://localhost:${VALKEY_PORT}" + fi + + local authentik_db_password="" + local authentik_secret_key="" + local authentik_bootstrap_password="" + local authentik_postgres_user="" + local authentik_postgres_db="" + local authentik_bootstrap_email="" + local authentik_cookie_domain="" + + if [[ "$ENABLE_SSO" == true && "$USE_BUNDLED_AUTHENTIK" == true ]]; then + authentik_postgres_user=$(resolve_env_value "AUTHENTIK_POSTGRES_USER" "authentik") + authentik_postgres_db=$(resolve_env_value "AUTHENTIK_POSTGRES_DB" "authentik") + authentik_bootstrap_email=$(resolve_env_value "AUTHENTIK_BOOTSTRAP_EMAIL" "admin@localhost") + + local existing_auth_db_password + existing_auth_db_password=$(get_env_value "AUTHENTIK_POSTGRES_PASSWORD") + authentik_db_password=$(resolve_secret_value "AUTHENTIK_POSTGRES_PASSWORD" generate_password 32) + if [[ -n "$existing_auth_db_password" ]] && ! is_placeholder "$existing_auth_db_password"; then + print_info "Preserving existing Authentik database password" + else + print_info "Generated Authentik database password" + fi + + local existing_auth_secret + existing_auth_secret=$(get_env_value "AUTHENTIK_SECRET_KEY") + authentik_secret_key=$(resolve_secret_value "AUTHENTIK_SECRET_KEY" generate_secret 64) + if [[ -n "$existing_auth_secret" ]] && ! is_placeholder "$existing_auth_secret"; then + print_info "Preserving existing Authentik secret key" + else + print_info "Generated Authentik secret key" + fi + + local existing_auth_bootstrap + existing_auth_bootstrap=$(get_env_value "AUTHENTIK_BOOTSTRAP_PASSWORD") + authentik_bootstrap_password=$(resolve_secret_value "AUTHENTIK_BOOTSTRAP_PASSWORD" generate_password 24) + if [[ -n "$existing_auth_bootstrap" ]] && ! is_placeholder "$existing_auth_bootstrap"; then + print_info "Preserving existing Authentik bootstrap password" + else + print_info "Generated Authentik bootstrap password" + fi + + authentik_cookie_domain=$(resolve_env_value "AUTHENTIK_COOKIE_DOMAIN" "") + if [[ -z "$authentik_cookie_domain" ]]; then + if [[ "$BASE_URL_MODE" == "traefik" && -n "$MOSAIC_AUTH_DOMAIN" ]]; then + authentik_cookie_domain=$(derive_cookie_domain "$MOSAIC_AUTH_DOMAIN") + else + authentik_cookie_domain=".localhost" + fi + fi + fi + + local oidc_issuer="" + local oidc_client_id="" + local oidc_client_secret="" + local oidc_redirect_uri="" + + if [[ "$ENABLE_SSO" == true ]]; then + local auth_url + if [[ "$USE_BUNDLED_AUTHENTIK" == true ]]; then + auth_url=$(strip_trailing_slash "$AUTHENTIK_PUBLIC_URL") + else + auth_url=$(strip_trailing_slash "$EXTERNAL_AUTHENTIK_URL") + fi + + oidc_issuer="${auth_url}/application/o/mosaic-stack/" + oidc_client_id=$(resolve_env_value "OIDC_CLIENT_ID" "mosaic-stack") + oidc_client_secret=$(resolve_env_value "OIDC_CLIENT_SECRET" "change-after-authentik-setup") + oidc_redirect_uri="${API_BASE_URL}/auth/callback" + fi + + local ollama_mode_env="" + local ollama_endpoint="" + if [[ "$OLLAMA_MODE" == "local" ]]; then + ollama_mode_env="local" + ollama_endpoint="http://ollama:11434" + elif [[ "$OLLAMA_MODE" == "remote" ]]; then + ollama_mode_env="remote" + ollama_endpoint="$OLLAMA_URL" + else + ollama_mode_env="remote" + ollama_endpoint=$(resolve_env_value "OLLAMA_ENDPOINT" "http://localhost:11434") + fi + + local compose_profiles=() + if [[ "$ENABLE_SSO" == true && "$USE_BUNDLED_AUTHENTIK" == true ]]; then + compose_profiles+=("authentik") + fi + if [[ "$OLLAMA_MODE" == "local" ]]; then + compose_profiles+=("ollama") + fi + if [[ "$TRAEFIK_MODE" == "bundled" ]]; then + compose_profiles+=("traefik-bundled") + fi + + local profiles_string="" + if [[ ${#compose_profiles[@]} -gt 0 ]]; then + profiles_string=$(IFS=,; echo "${compose_profiles[*]}") + fi + + env_override_set "API_PORT" "$API_PORT" + env_override_set "API_HOST" "$api_host" + env_override_set "WEB_PORT" "$WEB_PORT" + env_override_set "POSTGRES_USER" "$postgres_user" + env_override_set "POSTGRES_PASSWORD" "$db_password" + env_override_set "POSTGRES_DB" "$postgres_db" + env_override_set "POSTGRES_PORT" "$POSTGRES_PORT" + env_override_set "DATABASE_URL" "$database_url" + env_override_set "VALKEY_URL" "$valkey_url" + env_override_set "VALKEY_PORT" "$VALKEY_PORT" + env_override_set "NEXT_PUBLIC_API_URL" "$API_BASE_URL" + if [[ -n "$MOSAIC_BASE_URL" ]]; then + env_override_set "MOSAIC_BASE_URL" "$MOSAIC_BASE_URL" + fi + env_override_set "JWT_SECRET" "$jwt_secret" + env_override_set "JWT_EXPIRATION" "$jwt_expiration" + env_override_set "OLLAMA_MODE" "$ollama_mode_env" + env_override_set "OLLAMA_ENDPOINT" "$ollama_endpoint" + + if [[ -n "$profiles_string" ]]; then + env_override_set "COMPOSE_PROFILES" "$profiles_string" + else + env_override_set "COMPOSE_PROFILES" "" + fi + + env_override_set "TRAEFIK_MODE" "$TRAEFIK_MODE" + env_override_set "TRAEFIK_ENABLE" "$(bool_str "$TRAEFIK_ENABLE")" + env_override_set "TRAEFIK_TLS_ENABLED" "$(bool_str "$TRAEFIK_TLS_ENABLED")" + env_override_set "TRAEFIK_ENTRYPOINT" "$TRAEFIK_ENTRYPOINT" + + if [[ -n "$TRAEFIK_NETWORK" ]]; then + env_override_set "TRAEFIK_NETWORK" "$TRAEFIK_NETWORK" + fi + if [[ -n "$TRAEFIK_DOCKER_NETWORK" ]]; then + env_override_set "TRAEFIK_DOCKER_NETWORK" "$TRAEFIK_DOCKER_NETWORK" + fi + if [[ -n "$MOSAIC_WEB_DOMAIN" ]]; then + env_override_set "MOSAIC_WEB_DOMAIN" "$MOSAIC_WEB_DOMAIN" + fi + if [[ -n "$MOSAIC_API_DOMAIN" ]]; then + env_override_set "MOSAIC_API_DOMAIN" "$MOSAIC_API_DOMAIN" + fi + if [[ -n "$MOSAIC_AUTH_DOMAIN" ]]; then + env_override_set "MOSAIC_AUTH_DOMAIN" "$MOSAIC_AUTH_DOMAIN" + fi + + if [[ "$TRAEFIK_MODE" == "bundled" ]]; then + env_override_set "TRAEFIK_HTTP_PORT" "$TRAEFIK_HTTP_PORT" + env_override_set "TRAEFIK_HTTPS_PORT" "$TRAEFIK_HTTPS_PORT" + env_override_set "TRAEFIK_DASHBOARD_ENABLED" "$(bool_str "$TRAEFIK_DASHBOARD_ENABLED")" + env_override_set "TRAEFIK_DASHBOARD_PORT" "$TRAEFIK_DASHBOARD_PORT" + if [[ -n "$TRAEFIK_ACME_EMAIL" ]]; then + env_override_set "TRAEFIK_ACME_EMAIL" "$TRAEFIK_ACME_EMAIL" + fi + if [[ -n "$TRAEFIK_CERTRESOLVER" ]]; then + env_override_set "TRAEFIK_CERTRESOLVER" "$TRAEFIK_CERTRESOLVER" + fi + fi + + if [[ "$ENABLE_SSO" == true ]]; then + env_override_set "OIDC_ISSUER" "$oidc_issuer" + env_override_set "OIDC_CLIENT_ID" "$oidc_client_id" + env_override_set "OIDC_CLIENT_SECRET" "$oidc_client_secret" + env_override_set "OIDC_REDIRECT_URI" "$oidc_redirect_uri" + fi + + if [[ "$ENABLE_SSO" == true && "$USE_BUNDLED_AUTHENTIK" == true ]]; then + env_override_set "AUTHENTIK_POSTGRES_USER" "$authentik_postgres_user" + env_override_set "AUTHENTIK_POSTGRES_PASSWORD" "$authentik_db_password" + env_override_set "AUTHENTIK_POSTGRES_DB" "$authentik_postgres_db" + env_override_set "AUTHENTIK_SECRET_KEY" "$authentik_secret_key" + env_override_set "AUTHENTIK_BOOTSTRAP_PASSWORD" "$authentik_bootstrap_password" + env_override_set "AUTHENTIK_BOOTSTRAP_EMAIL" "$authentik_bootstrap_email" + env_override_set "AUTHENTIK_COOKIE_DOMAIN" "$authentik_cookie_domain" + env_override_set "AUTHENTIK_PORT_HTTP" "$AUTHENTIK_PORT_HTTP" + env_override_set "AUTHENTIK_PORT_HTTPS" "$AUTHENTIK_PORT_HTTPS" + fi + + if [[ "$OLLAMA_MODE" == "local" ]]; then + env_override_set "OLLAMA_PORT" "$OLLAMA_PORT" + fi + + write_env_with_overrides "$template" "$output" + + chmod 600 "$output" + print_success "Generated .env file" + + # Write credentials file + write_credentials_file "$db_password" "$authentik_bootstrap_password" + + if [[ "$xtrace_was_on" == true ]]; then + set -x + fi +} + +write_credentials_file() { + local db_password="$1" + local authentik_password="$2" + + local creds_file="$PROJECT_ROOT/.admin-credentials" + local db_user + db_user=$(resolve_env_value "POSTGRES_USER" "mosaic") + + cat > "$creds_file" << EOF +# Mosaic Stack Admin Credentials +# Generated: $(date) +# KEEP THIS FILE SECURE AND DO NOT COMMIT TO VERSION CONTROL + +Database (PostgreSQL): + Username: ${db_user} + Password: $(mask_value "$db_password") + Full password available in .env as POSTGRES_PASSWORD + +JWT Secret: + Available in .env as JWT_SECRET + +EOF + + if [[ "$ENABLE_SSO" == true && -n "$authentik_password" ]]; then + cat >> "$creds_file" << EOF +Authentik Admin: + Email: admin@localhost + Password: $(mask_value "$authentik_password") + Full password available in .env as AUTHENTIK_BOOTSTRAP_PASSWORD + URL: ${AUTHENTIK_PUBLIC_URL:-http://localhost:9000} + + IMPORTANT: Change the bootstrap password after first login! + +EOF + fi + + chmod 600 "$creds_file" + print_success "Saved credentials to .admin-credentials" +} + +# ============================================================================ +# Deployment +# ============================================================================ + +run_deployment() { + print_header "Deployment" + + if [[ "$MODE" == "docker" ]]; then + deploy_docker + else + deploy_native + fi +} + +prepare_traefik_upstream() { + if [[ "$TRAEFIK_MODE" != "upstream" ]]; then + return + fi + + print_header "Traefik Upstream Setup" + + local network="${TRAEFIK_NETWORK:-traefik-public}" + + if ! docker network ls --format '{{.Name}}' | grep -q "^${network}$"; then + print_warning "Traefik network '${network}' not found" + if [[ "$NON_INTERACTIVE" == true ]] || confirm "Create network '${network}' now?" "y"; then + docker network create "$network" + print_success "Created network: ${network}" + else + print_warning "Continuing without creating network" + fi + fi + + local override_file="$PROJECT_ROOT/docker-compose.override.yml" + if [[ -f "$override_file" ]]; then + print_info "docker-compose.override.yml already exists. Leaving it unchanged." + return + fi + + cat > "$override_file" << 'EOF' +version: '3.9' + +services: + api: + networks: + - traefik-public + + web: + networks: + - traefik-public + + authentik-server: + networks: + - traefik-public + +networks: + traefik-public: + external: true + name: ${TRAEFIK_NETWORK:-traefik-public} +EOF + + print_success "Created docker-compose.override.yml for upstream Traefik" +} + +deploy_docker() { + echo "" + print_step "Starting Docker deployment..." + echo "" + + prepare_traefik_upstream + + # Check if docker-compose.yml exists + if [[ ! -f "$PROJECT_ROOT/docker-compose.yml" ]]; then + print_error "docker-compose.yml not found" + exit 1 + fi + + cd "$PROJECT_ROOT" || exit 1 + + local compose_files=("-f" "docker-compose.yml") + if [[ -f "docker-compose.override.yml" ]]; then + compose_files+=("-f" "docker-compose.override.yml") + fi + + # Set up error trap for rollback + local deployment_started=false + rollback_deployment() { + if [[ "$deployment_started" == true ]]; then + print_warning "Deployment failed, rolling back..." + docker compose "${compose_files[@]}" down --remove-orphans 2>/dev/null || true + print_info "Rollback complete" + fi + } + trap rollback_deployment ERR + + # Pull images + print_step "Pulling Docker images..." + if ! docker compose "${compose_files[@]}" pull; then + print_warning "Failed to pull some images (will build locally)" + fi + + # Build services + print_step "Building services..." + if ! docker compose "${compose_files[@]}" build; then + print_error "Build failed" + trap - ERR + return 1 + fi + + # Start services + print_step "Starting services..." + deployment_started=true + if ! docker compose "${compose_files[@]}" up -d; then + print_error "Failed to start services" + trap - ERR + rollback_deployment + return 1 + fi + + # Clear trap on success + trap - ERR + + # Wait for services to be healthy + echo "" + print_step "Waiting for services to start..." + sleep 5 + + # Check service health + local all_healthy=true + local services=("postgres" "valkey" "api" "web") + + for service in "${services[@]}"; do + if docker compose "${compose_files[@]}" ps "$service" 2>/dev/null | grep -q "Up"; then + print_success "$service: Running" + else + print_warning "$service: Not running" + all_healthy=false + fi + done + + if [[ "$all_healthy" == true ]]; then + echo "" + print_success "All services started successfully" + else + echo "" + print_warning "Some services may not be running correctly" + print_info "Check logs with: docker compose logs" + fi +} + +deploy_native() { + echo "" + print_step "Native deployment setup..." + echo "" + + cd "$PROJECT_ROOT" || exit 1 + + # Install dependencies + print_step "Installing Node.js dependencies..." + if ! pnpm install; then + print_error "Failed to install dependencies" + exit 1 + fi + + # Database setup + print_step "Setting up database..." + print_info "Make sure PostgreSQL is running and accessible" + + # Run migrations + print_step "Running database migrations..." + if ! pnpm -F api run prisma:migrate; then + print_warning "Database migration failed - you may need to set this up manually" + fi + + # Build + print_step "Building application..." + pnpm run build + + print_success "Native setup complete" + echo "" + print_info "To start the application:" + print_info " pnpm dev # Development mode" + print_info " pnpm start # Production mode" +} + +# ============================================================================ +# Post-Install Information +# ============================================================================ + +show_post_install_info() { + if [[ "$DRY_RUN" == true ]]; then + print_header "Dry Run Summary" + echo "" + print_info "No files were written and no containers were started." + echo "" + print_step "Planned URLs:" + echo "" + if [[ "$MODE" == "docker" ]]; then + echo " Web Interface: $MOSAIC_BASE_URL" + echo " API: $API_BASE_URL" + if [[ "$ENABLE_SSO" == true ]]; then + echo " Authentik SSO: ${AUTHENTIK_PUBLIC_URL:-http://localhost:9000}" + fi + fi + echo "" + return + fi + + print_header "Installation Complete" + + echo "" + echo "🎉 Mosaic Stack has been set up successfully!" + echo "" + + # Show URLs + print_step "Access URLs:" + echo "" + + if [[ "$MODE" == "docker" ]]; then + local web_url="$MOSAIC_BASE_URL" + local api_url="$API_BASE_URL" + + echo " Web Interface: $web_url" + echo " API: $api_url" + + if [[ "$ENABLE_SSO" == true ]]; then + local auth_url="${AUTHENTIK_PUBLIC_URL:-http://localhost:9000}" + echo " Authentik SSO: $auth_url" + fi + + if [[ "$OLLAMA_MODE" == "local" ]]; then + echo " Ollama: http://localhost:${OLLAMA_PORT}" + fi + else + echo " Run 'pnpm dev' to start the development server" + fi + + echo "" + print_step "Credentials:" + echo "" + echo " Saved to: .admin-credentials" + print_warning "Keep this file secure!" + + echo "" + print_step "Next Steps:" + echo "" + + if [[ "$ENABLE_SSO" == true ]]; then + echo " 1. Access Authentik at ${AUTHENTIK_PUBLIC_URL:-http://localhost:9000}" + echo " 2. Log in with credentials from .admin-credentials" + echo " 3. Complete SSO setup (create application, get client secret)" + echo " 4. Update OIDC_CLIENT_SECRET in .env" + echo " 5. Access Mosaic Stack at $MOSAIC_BASE_URL" + else + echo " 1. Access Mosaic Stack at $MOSAIC_BASE_URL" + echo " 2. Create your first user account" + fi + + if [[ "$TRAEFIK_MODE" == "upstream" ]]; then + echo "" + print_info "Upstream Traefik: ensure your Traefik is attached to '${TRAEFIK_NETWORK:-traefik-public}'" + elif [[ "$TRAEFIK_MODE" == "bundled" && "$TRAEFIK_DASHBOARD_ENABLED" == true ]]; then + echo "" + print_info "Traefik dashboard: http://localhost:${TRAEFIK_DASHBOARD_PORT}/dashboard/" + fi + + echo "" + print_step "Useful Commands:" + echo "" + + if [[ "$MODE" == "docker" ]]; then + echo " View logs: docker compose logs -f" + echo " Stop services: docker compose down" + echo " Restart: docker compose restart" + echo " View status: docker compose ps" + else + echo " Development: pnpm dev" + echo " Production: pnpm start" + echo " Database: pnpm -F api run prisma:migrate" + fi + + echo "" + print_step "Documentation:" + echo "" + echo " Setup docs: /home/jwoltje/src/mosaic-stack/scripts/README.md" + echo " Architecture: /home/jwoltje/src/mosaic-stack/docs/" + + echo "" } # ============================================================================ @@ -459,21 +2123,31 @@ main() { check_and_install_dependencies collect_configuration + resolve_port_conflicts - # TODO: generate_env_file - # TODO: run_deployment - # TODO: show_post_install_info + if [[ "$DRY_RUN" != true ]]; then + generate_env_file + run_deployment + else + echo "" + print_warning "Dry run mode - skipping .env generation and deployment" + echo "" + print_info "Configuration collected but not applied" + fi + + show_post_install_info echo "" - print_success "Setup complete (partial implementation)!" + print_success "Setup complete!" echo "" echo "===================================================================" echo "Setup completed: $(date)" echo "Full log saved to: $LOG_FILE" echo "===================================================================" echo "" - print_info "This is a foundation setup script." - print_info "Additional features (env generation, deployment) to be implemented." + + # Reset terminal colors before exiting + printf "${NC}" } # Run main function